feat(l2): integrate Phylax Credible Layer into L2 sequencer#6488
Draft
avilagaston9 wants to merge 46 commits intofeat/l1/prestate-tracerfrom
Draft
feat(l2): integrate Phylax Credible Layer into L2 sequencer#6488avilagaston9 wants to merge 46 commits intofeat/l1/prestate-tracerfrom
avilagaston9 wants to merge 46 commits intofeat/l1/prestate-tracerfrom
Conversation
Add optional transaction validation against the Credible Layer Assertion
Enforcer sidecar during L2 block building. When enabled via --circuit-breaker-url,
each candidate transaction is sent to the sidecar via gRPC. If the sidecar
returns ASSERTION_FAILED, the transaction is dropped from the block. On any
error or timeout, the transaction is included (permissive / liveness over safety).
Changes:
- gRPC client (tonic/prost) implementing sidecar.proto StreamEvents + GetTransaction
and aeges.proto VerifyTransaction for optional mempool pre-filtering
- Block producer sends NewIteration, Transaction, and CommitHead events via
a persistent bidirectional gRPC stream with automatic reconnection
- L2 WebSocket server with eth_subscribe("newHeads") support, required by
the sidecar for live chain state tracking
- prestateTracer (diff mode) for debug_traceBlockByNumber, required by the
sidecar to build its local state database
- Fix eth_getLogs to accept requests without topics parameter (spec compliance)
- CLI flags: --circuit-breaker-url, --circuit-breaker-aeges-url,
--circuit-breaker-state-oracle, --l2.ws-enabled/addr/port
- Test contracts (OwnableTarget.sol, TestOwnershipAssertion.sol),
mock sidecar binary, and e2e validation script
- Documentation with verified 10-step end-to-end guide covering L1 setup,
L2 with circuit breaker, State Oracle deployment via Phylax Forge scripts,
assertion registration via DA + State Oracle, real sidecar with indexer,
and transaction rejection/inclusion verification
Tested end-to-end with the real Phylax sidecar Docker image, assertion-da,
sidecar-indexer, and credible-layer-contracts Forge deployment scripts.
…naming Circuit Breaker was an informal name. Phylax's official product name is Credible Layer — used consistently across all their documentation, code, and repos. Rename all references: module directories, struct names, CLI flags, env vars, docs, and Makefile targets.
Build with COMPILE_CONTRACTS=true once in prerequisites, then use the binary directly in Step 2 instead of cargo run which triggers a rebuild.
block production. Adds a stream_connected flag that the background task sets/clears. When false, evaluate_transaction returns true immediately instead of polling GetTransaction (which would timeout and block the block producer for ~2s per tx).
Docker logs contain ANSI escape sequences that break plain grep matching. Add sed pipe to strip them in all docker logs grep commands.
… doc improvements Add a --credible-layer boolean gate flag to CredibleLayerOptions (modeled after --aligned), so operators explicitly opt in before providing any --credible-layer-* sub-flags. The three sub-flags (--credible-layer-url, --credible-layer-aeges-url, --credible-layer-state-oracle) now carry requires = "credible_layer". The TryFrom mapping returns CredibleLayerConfig::default() when the gate flag is absent. Promote three log messages in client.rs from debug to info/warn: forwarding events is useful for operators to trace the event flow (info), while StreamEvents connect failures and channel closure are anomalies that deserve visibility (warn). The GetTransaction poll-attempt message stays at debug since it fires on every poll attempt. Update credible_layer.md: clarify the privileged-tx bypass is specific to this first version of the integration, expand Key Files descriptions to distinguish the sidecar client from the Aeges client by listing their RPCs, reflect the new --credible-layer gate flag in the Configuration table and the Step 3 startup command, simplify RUST_LOG to plain "info" since the important Credible Layer messages are now at INFO/WARN level, replace cast commands with rex equivalents (block-number, send -k, call, address -k), and remove cast from the Prerequisites list (only forge is now required).
rex deploy can compile and deploy Solidity directly, no need for manual solc compilation + cast send --create.
…mentation exists) Deletes the Aeges gRPC client module (aeges.rs), its proto definition (aeges.proto), the --credible-layer-aeges-url CLI flag, the aeges_url field from CredibleLayerConfig, the MempoolFilter type and mempool_filter field from RpcApiContext, the build_aeges_filter function from initializers, and all related wiring in start_api. Updates docs/CLI.md, docs/l2/credible_layer.md, and the Makefile init-l2-credible-layer target accordingly.
…m L2 to L1 RPC crate. The subscription functionality (newHeads) is standard Ethereum behavior that belongs in the base execution client, not L2-specific code. The L1 RpcApiContext now carries a new_heads_sender field, and the subscription functions (handle_eth_subscribe, handle_eth_unsubscribe, generate_subscription_id, drain_subscriptions, build_subscription_notification) and the NEW_HEADS_CHANNEL_CAPACITY constant are defined in the L1 crate and exported from its lib.rs. The L1 handle_websocket is upgraded from a simple request-response loop to a select!-based loop that multiplexes incoming WS messages with subscription notification draining. The L2 WS handler is simplified to delegate eth_subscribe and eth_unsubscribe to L1's implementations (via context.l1_ctx), eliminating the duplicate code. The L2 lib.rs re-exports NEW_HEADS_CHANNEL_CAPACITY from ethrex_rpc for backward compatibility with existing callers (cmd/ethrex/l2/initializers.rs). The L2 tests that covered the subscription utilities are updated to reference the L1 implementations directly.
e311925 to
9d8569b
Compare
Lines of code reportTotal lines added: Detailed view |
Integrates the SubscriptionManager actor refactoring (replacing broadcast channels) with the Credible Layer integration. Updates WS CLI flags in the credible layer guide from the removed --l2.ws-enabled/--l2.ws-port to --ws.enabled/--ws.port, fixes rex address and rex deploy command syntax, and removes unused TxExecutionId import.
…_build. The mock sidecar was a standalone dev tool for testing the gRPC protocol without the real Phylax sidecar, but it was never referenced by any Makefile target, script, test, or documentation.
…ectly preserved during the merge and is unrelated to the Credible Layer integration.
…tor, split transaction evaluation into pre/post execution phases, and simplify the block producer interface. The CredibleLayerClient is now a spawned actor using #[protocol]/#[actor] macros, replacing the previous Arc-wrapped struct. All protobuf conversion logic (BlockEnv, CommitHead, NewIteration, TransactionEnv) is encapsulated inside the actor — the block producer makes one-line calls instead of building protobuf messages inline. Transaction evaluation now follows the Besu plugin pattern: the tx event is sent to the sidecar before execution (fire-and-forget), and the verdict is polled after execution. If the sidecar rejects, the execution is undone using the existing undo_last_tx mechanism. Also removes unused state_oracle_address config/CLI flag, the e2e script, sidecar-config template, unused Makefile targets, and broken doc links. TestOwnershipAssertion.sol rewritten as a real credible-std assertion.
…ssing it enables the integration, removing the separate --credible-layer boolean gate) and replace #[allow(clippy::as_conversions)] with proper try_into conversions that return errors instead of panicking.
…oncurrency primitives: connection is established in #[started], the ack stream is bridged into actor messages via spawn_listener, and reconnection on failure is scheduled with send_after. This ties the background stream lifecycle to the actor — when the actor stops, the stream listener is automatically cancelled. The Arc<AtomicBool> for tracking connection state is replaced by a plain bool in the actor's owned state.
not actor events) and rename handle_stream_ack protocol method to stream_ack to avoid the auto-generated handle_handle_stream_ack double prefix. Clarify the channel field comment.
…ient already wraps the channel internally and tonic clients are Clone, so try_connect just clones grpc_client for new stream connections.
… handle to sidecar), grpc_client -> sidecar_client, connected -> stream_connected, try_connect -> open_event_stream. Remove unnecessary clone of sidecar_client when opening the stream — use self.sidecar_client directly since the stream lives independently once established.
…n mod.rs, next to the proto type definitions. Removes build_transaction_env from client.rs — the handler now just calls (tx, sender).into().
BlockProducer::new sync (no async needed since CL actor is spawned externally), and get last_tx_hash from the block before store_block consumes it instead of re-fetching from the store.
and update sp1/risc0 guest program Cargo.lock files to fix CI check-cargo-lock.
the 3-step pre/post execution flow (send tx, execute, poll verdict with undo on rejection), remove the non-existent Aeges check, and fix the gRPC label positioning.
as dependencies it reads from ethrex (not separate components), separate Assertion DA and Indexer into an off-chain services section (they are not on-chain), and keep only State Oracle in the on-chain box.
this integration) and update all Cargo.lock files to fix CI check-cargo-lock.
Benchmark Results ComparisonNo significant difference was registered for any benchmark run. Detailed ResultsBenchmark Results: BubbleSort
Benchmark Results: ERC20Approval
Benchmark Results: ERC20Mint
Benchmark Results: ERC20Transfer
Benchmark Results: Factorial
Benchmark Results: FactorialRecursive
Benchmark Results: Fibonacci
Benchmark Results: FibonacciRecursive
Benchmark Results: ManyHashes
Benchmark Results: MstoreBench
Benchmark Results: Push
Benchmark Results: SstoreBench_no_opt
|
…ssertion.sol) from crates/l2/contracts/src/credible_layer/ to tooling/l2/credible_layer/ since the sequencer never compiles or references them — they exist only for the e2e setup guide. Update contract path in docs and relative doc link in README.
…explicit by adding example output for the owner() call before the violation test and clarifying that the value after must match exactly.
…_transaction restores SSTORE changes. Without this fix, the Credible Layer demo corrupts state when a transaction is dropped because the L2Hook cleared the call_frame_backup before BackupHook could capture storage slot rollback data.
…_build step in crates/l2/build.rs which compiles sidecar.proto for the Credible Layer gRPC client.
…e_err on actor constructor, replace disallowed as_u32 with u32::try_from
…olchain as the rest of CI
…uilds are not burdened with an L2-only dependency. Protoc is now installed only in L2 CI jobs (via arduino/setup-protoc) and conditionally in the Docker builder stage when BUILD_FLAGS contains l2. Also revert unnecessary diff in rpc.rs (derive order, expect→allow), and fix result_large_err properly by boxing CredibleLayerError instead of suppressing the lint with #[allow].
…protoc action following the same pattern as install-solc (curl download from official protobuf releases). In the Dockerfile, install protoc alongside solc in the same RUN block instead of the hacky BUILD_FLAGS conditional. Revert the unnecessary setup-rust addition to the L1 check-cargo-locks job — cargo metadata doesn't need a specific toolchain.
…protoc. The build.rs now calls protox::compile() to produce a FileDescriptorSet and feeds it into tonic-build via compile_fds(), so no external protoc binary is needed at build time. This removes the need to install protoc in CI workflows and the Dockerfile entirely — both are reverted to main.
toolchain from rust-toolchain.toml (1.91.0). Without it, the job uses whatever Rust version is pre-installed on the runner and cargo metadata --locked can fail with 'lock file needs to be updated' because a different cargo version resolves some transitive dependencies differently (e.g. ruint 1.17.2 -> 1.18.0). Also remove a now-redundant comment in build.rs.
c66cc58 to
ef9a11a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Integrate the Phylax Credible Layer into ethrex's L2 sequencer. This allows protocol teams to write Solidity-based security assertions that are validated against every transaction before block inclusion — violating transactions are silently dropped.
Description
When enabled via
--credible-layer, the L2 block producer communicates with the Credible Layer Assertion Enforcer sidecar via gRPC during block building. For each candidate transaction, aTransactionevent is sent to the sidecar, which evaluates it against registered assertions. IfASSERTION_FAILED, the transaction is dropped. On any error or timeout, transactions are included (permissive behavior — liveness over safety).Implementation:
tonic/prost) implementingsidecar.proto(StreamEventsbidirectional stream,GetTransactionpolling)fill_transactions: per-tx Credible Layer check for non-privileged txs,NewIteration/CommitHeadlifecycle eventseth_subscribe("newHeads")— required by the sidecar for live chain state tracking (implemented in feat(l1): add eth_subscribe/eth_unsubscribe WebSocket subscription support #6496)prestateTracer(diff mode) fordebug_traceBlockByNumber— required by the sidecar to build its local state DBeth_getLogsfix: accept requests withouttopicsparameter (Ethereum spec compliance, needed by the sidecar's assertion indexer)OwnableTarget.sol,TestOwnershipAssertion.sol) intooling/l2/credible_layer/for e2e validationHow to Test
Full end-to-end guide in
docs/l2/credible_layer.md— 10 verified steps from L1 startup to assertion rejection. Summary:--credible-layercredible-layer-contractsForge scriptsOwnableTarget(fromtooling/l2/credible_layer/), compileOwnableAssertionfromcredible-layer-starter, upload to assertion DA, register on State Oraclesidecar-indexer(Docker) + real Phylax sidecar (Docker)transferOwnership→ dropped (assertion violation detected by real sidecar)doSomething()→ included (no assertion triggered)Tested end-to-end with the real Phylax sidecar Docker image (
ghcr.io/phylaxsystems/credible-sdk/sidecar:main), assertion-da, sidecar-indexer, and credible-layer-contracts deployment scripts.Checklist
cargo check -p ethrex --features l2)docs/l2/credible_layer.mdwith verified step-by-step guide--credible-layeris not set)