ref-fvm icon indicating copy to clipboard operation
ref-fvm copied to clipboard

EIP‑7702: VM Intercept for Delegated CALLs, EXTCODE* Pointer Projection, Authority Storage Overlay, and Event Emission

Open snissn opened this issue 1 month ago • 4 comments

EIP‑7702: VM Intercept for Delegated CALLs, EXTCODE* Pointer Projection, Authority Storage Overlay, and Event Emission

Summary

  • Implements EIP‑7702 execution semantics in ref‑fvm:
    • Intercept EVM CALL/STATICCALL to EthAccount (EOA) with active delegation and execute the delegate code under an authority context with depth=1.
    • Project a virtual 23‑byte pointer code for delegated EOAs on EXTCODESIZE/HASH/COPY.
    • Mount and persist an authority storage overlay (evm_storage_root) on success.
    • Emit best‑effort Delegated(address) event with the authority encoded as a 32‑byte ABI word.
    • Propagate revert codes and bytes to the EVM return buffer.
  • Adds runtime/SDK syscall get_eth_delegate_to(ActorID) -> Option<[u8;20]> for EXTCODE* pointer projection and tests.
  • Provides a Dockerized test runner to build the builtin‑actors Wasm bundle and run end‑to‑end ref‑fvm tests.

Motivation

  • Complete the migration of EIP‑7702 semantics from the EVM actor into the VM:
    • Delegation state moves into EthAccount so it is globally visible.
    • VM handles delegated dispatch and pointer projection so the interpreter remains minimal and does not re‑follow delegation internally.
  • Keeps Lotus’ client behavior aligned (receipts attribution via tuples or the synthetic event; behavioral gas model remains unchanged).

Key Changes

  • VM intercept (DefaultCallManager):
    • Gate on EVM InvokeEVM calls to an EthAccount target with a non‑empty delegate_to.
    • Resolve the delegate from the 20‑byte ETH address via EAM into f4, confirm code via EVM.GetBytecode.
    • Perform value transfer to the authority first; on failure, short‑circuit with a revert‑like mapping (no execution).
    • Invoke the caller EVM actor’s trampoline InvokeAsEoaWithRoot (FRC‑42 hash) with (code_cid, input, caller, receiver, value, initial_storage_root).
    • Decode (output_data, new_storage_root), persist new_storage_root to the EthAccount, and emit Delegated(address) (topic keccak("Delegated(address)"), data = 32‑byte ABI word with right‑aligned authority).
    • Return ExitCode::OK + raw IPLD return bytes on success; propagate non‑success code and revert data as received.
    • Depth limit enforced: delegation is not re‑followed in authority context; SELFDESTRUCT is a no‑op.
  • EXTCODE* pointer projection:
    • EVM interpreter consults the runtime helper; when delegate_to is set, expose a 23‑byte virtual code image 0xEF 0x01 0x00 || <delegate(20)>.
    • EXTCODESIZE=23, EXTCODEHASH=keccak(pointer_code), EXTCODECOPY honors windowing with zero‑fill semantics.
  • SDK/syscalls:
    • New syscall actor::get_eth_delegate_to plumbed through kernel + SDK (sdk/src/actor.rs, sdk/src/sys/actor.rs, fvm/src/syscalls/actor.rs).
    • Adds a pure helper and unit tests for the 20‑byte extraction.
  • Utilities:
    • Local frc42_method_hash and keccak32 helpers used in intercept code.

Files

  • VM intercept and helpers:
    • fvm/src/call_manager/default.rs
  • Syscalls/SDK:
    • fvm/src/syscalls/actor.rs
    • fvm/src/syscalls/mod.rs
    • sdk/src/actor.rs
    • sdk/src/sys/actor.rs
  • Tests:
    • fvm/tests/evm_extcode_projection.rs (EXTCODESIZE/HASH/COPY pointer image)
    • fvm/tests/delegated_call_mapping.rs (mapping + storage overlay persist)
    • fvm/tests/delegated_value_transfer_short_circuit.rs (failed transfer → revert mapping)
    • fvm/tests/depth_limit.rs (no re‑follow A→B→C)
    • fvm/tests/selfdestruct_noop_authority.rs (SELFDESTRUCT no‑op under authority context)
    • fvm/tests/overlay_persist_success.rs (overlay mount/persist success path)
    • fvm/tests/eth_delegate_to.rs (helper syscall)
    • fvm/tests/ethaccount_state_roundtrip.rs (state view round‑trip)
    • fvm/tests/common.rs (EthAccount install + helper utilities)
  • Tooling:
    • scripts/run_eip7702_tests.sh (Docker bundle build + ref‑fvm test runner with host fallback)

Behavioral Details

  • Intercept trigger:
    • Only when entrypoint is EVM’s InvokeEVM and the receiver is an EthAccount with delegate_to set.
  • Value transfer:
    • Charged and executed before invoking the trampoline; failure maps to non‑success without executing the delegate.
  • Authority context:
    • Depth limit = 1; no nested delegation follow.
    • SELFDESTRUCT is a no‑op (no balance move or tombstone).
  • Storage overlay:
    • Mount evm_storage_root prior to execution; persist updated root to EthAccount state on success only.
  • Events:
    • Emit Delegated(address) with ABI‑encoded 32‑byte word; best‑effort (may be dropped under extreme gas tightness).
  • Revert mapping:
    • Revert exit codes and data are propagated as‑is; EVM surface exposes bytes via RETURNDATASIZE/RETURNDATACOPY.
  • EXTCODE*:
    • Virtual 23‑byte pointer image is exposed with correct windowing and zero‑fill.

Testing

  • Unit tests cover:
    • EXTCODE* projection: size/hash/copy and partial/out‑of‑bounds reads.
    • Delegated CALL success and revert, revert data correctness.
    • Value transfer short‑circuit behavior.
    • Depth limit (A→B→C).
    • SELFDESTRUCT no‑op under authority context.
    • EthAccount state view round‑trips and helper syscall behavior.
  • Runner:
    • scripts/run_eip7702_tests.sh builds the builtin‑actors bundle in Docker, then runs ref‑fvm tests; falls back to in‑Docker tests if host toolchain fails.

How To Test

  • Host (if toolchain permits):
    • cargo test -p fvm --tests -- --nocapture
  • Dockerized (recommended, especially on macOS):
    • ./scripts/run_eip7702_tests.sh
  • Pair with builtin‑actors (eip7702 branch) to build a fresh bundle for end‑to‑end EXTCODE*/delegation tests.

Compatibility / Notes

  • No runtime NV gate; activation is via the Wasm bundle.
  • Adds a new syscall; SDK consumers can use sdk::actor::get_eth_delegate_to to detect delegation and expose pointer images.
  • EVM interpreter no longer re‑follows delegation internally; the VM intercept is authoritative.

Follow‑Ups

  • Extend negative‑path/edge tests if coverage flags regressions in call_manager/default.rs.
  • Telemetry: decide whether to reserve a small fixed gas budget for event emission if Delegated(address) drops frequently under gas tightness.
  • Keep coverage profiles consistent between base and patch to ensure delegated paths are exercised.

Related Changes

  • builtin‑actors (paired eip7702): EthAccount state expanded (delegate_to, auth_nonce, evm_storage_root), ApplyAndCall added; EVM.ApplyAndCall and InvokeAsEoa removed; InvokeAsEoaWithRoot remains for the trampoline.
  • Lotus (paired eip7702): route type‑0x04 to EthAccount.ApplyAndCall; receipt adjuster recognizes Delegated(address) topic with 32‑byte ABI word; behavioral gas estimation based on tuple count.

Thanks for reviewing. Happy to split or annotate commits further if helpful.


EIP‑7702 Reviewers Guide (Lotus + builtin‑actors + ref‑fvm)

Audience: Filecoin core devs and reviewers looking at the coordinated 7702 changes in ../builtin-actors, ../ref-fvm, and ../lotus.
Scope: Explains the current EthAccount + VM‑intercept design, how the three repos fit together, and where to focus review and testing.


1. Conceptual Model

  • What 7702 does (in this branch)

    • Ethereum 0x04 txs carry an authorizationList of signed tuples that let an EOA delegate execution to a contract.
    • In this Filecoin integration:
      • Delegation state lives in EthAccount (per‑EOA): delegate_to, auth_nonce, evm_storage_root.
      • The EVM actor is kept minimal; it no longer stores delegation or follows it internally.
      • The VM (ref-fvm) intercepts CALLs to delegated EOAs and implements the execution semantics and EXTCODE* pointer projection.
      • Lotus parses 0x04 RLP, builds an EthAccount.ApplyAndCall message, and reconstructs receipts (status + authorizationList + delegatedTo).
  • Key invariants (cross‑repo)

    • Delegation + nonce bumps persist even if the outer call reverts (spec‑compliant atomicity).
    • Authorities must not be EVM contracts (pre‑existence policy).
    • Delegation depth is capped at 1; SELFDESTRUCT in authority context is a no‑op.
    • EXTCODE* on delegated EOAs exposes a 23‑byte pointer code 0xEF 0x01 0x00 || delegate(20).
    • Event topic for delegated execution is keccak256("Delegated(address)"), data is a 32‑byte ABI word with the authority address.

2. End‑to‑End Data Flow

  1. eth_sendRawTransaction (0x04)

    • Lotus decodes the RLP 0x04 payload into Eth7702TxArgs with authorizationList and outer call fields (to, value, input).
    • ToUnsignedFilecoinMessageAtomic builds a Filecoin message targeting EthAccount.ApplyAndCall with canonical CBOR params
      ([ [tuple...], [to(20), value, input] ])
      – see chain/types/ethtypes/eth_7702_transactions.go:121.
  2. EthAccount.ApplyAndCall (builtin‑actors)

    • EthAccount validates the tuples, recovers the authority from the 0x05 || rlp(...) domain, enforces per‑authority nonce equality, updates delegate_to/auth_nonce/evm_storage_root, and then executes the outer call (possibly to an EVM contract).
    • EthAccount itself always exits OK and embeds the callee’s success bit + returndata in ApplyAndCallReturn
      – see ../builtin-actors/actors/ethaccount/src/lib.rs:187.
  3. VM Execution (ref-fvm)

    • When an EVM contract later does CALL to an EOA that has delegate_to set, the VM’s DefaultCallManager intercepts the call instead of the EVM interpreter following delegation.
    • The intercept:
      • Resolves the delegate EVM actor and its bytecode.
      • Mounts the authority storage overlay (evm_storage_root from EthAccount state).
      • Executes the delegate under an “authority context” trampoline (InvokeAsEoaWithRoot).
      • Persists the new storage root on success, emits Delegated(address) best‑effort, and returns revert codes/data back to the caller.
        – see ../ref-fvm/fvm/src/call_manager/default.rs:560.
  4. EXTCODE Pointer Projection (ref-fvm + EVM)*

    • The EVM interpreter calls a runtime helper to check if a target ID has delegate_to set (via a new syscall).
    • For delegated EOAs, EXTCODESIZE/HASH/COPY operate over the virtual pointer image 0xEF 0x01 0x00 || delegate(20); windowing and zero‑fill semantics are enforced in tests.
    • The interpreter itself no longer performs dynamic delegation or storage mounting.
  5. Receipts & RPC (Lotus)

    • newEthTxReceipt computes the 7702 receipt status from the ApplyAndCallReturn CBOR (status field), not from the Filecoin exit code; the actor always exits OK – see node/impl/eth/utils.go:450.
    • adjustReceiptForDelegation populates:
      • authorizationList from the tx view, and
      • delegatedTo either from tuples or from the synthetic Delegated(address) event emitted by the VM intercept – see node/impl/eth/receipt_7702_scaffold.go:19 and node/impl/eth/transaction.go:345.

3. On‑Chain Logic (builtin‑actors)

3.1 EthAccount Actor

  • State

    • State { delegate_to: Option<EthAddress>, auth_nonce: u64, evm_storage_root: Cid }
      – see ../builtin-actors/actors/ethaccount/src/state.rs:5.
    • delegate_to and auth_nonce persist across transactions; evm_storage_root is used by the VM intercept to mount authority storage.
  • Validation & Authority Recovery

    • validate_tuple enforces:
      • chain_id ∈ {0, local}
      • len(r), len(s) ≤ 32, rejects > 32
      • r and s non‑zero
      • y_parity ∈ {0,1}
      • s is low‑s after left‑padding to 32 bytes – see validate_tuple and is_high_s in ethaccount/src/lib.rs.
    • recover_authority computes:
      • msg = keccak256(0x05 || rlp([chain_id, address(20), nonce])) (domain separator)
      • recovers the secp256k1 pubkey and then the 20‑byte EthAddress – see ethaccount/src/lib.rs above the constructor.
  • ApplyAndCall semantics
    (EthAccountActor::apply_and_call, ethaccount/src/lib.rs:189)

    • Enforces:
      • authorizationList non‑empty and ≤ 64 tuples (tuple cap).
      • All tuples in a message target the receiver authority only (no multi‑authority apply in one call).
      • No duplicate authorities within the list.
      • Pre‑existence: rejects if the authority resolves to an EVM contract actor.
      • Nonce equality for the receiver (auth_nonce vs tuple nonce, absent treated as 0).
    • Persistence:
      • Within a rt.transaction, for each tuple:
        • If delegate address is zero → clears delegate_to.
        • Otherwise sets delegate_to = Some(address).
        • Increments auth_nonce (saturating).
        • Initializes evm_storage_root if empty.
      • This transaction commits before the outer call, so mapping + nonce persist even if the outer call fails or reverts.
    • Outer call:
      • Decodes call.to (EthAddress → Filecoin Address) and call.value (bytes → U256TokenAmount).
      • Detects whether the target is an EVM builtin actor by resolving the ID and get_actor_code_cid.
      • If EVM target:
        • CBOR‑encodes InvokeContractParams { input_data } and calls EVM’s InvokeEVM entrypoint with that payload and value.
      • If non‑EVM or unresolved:
        • Sends a plain METHOD_SEND with the value and no params.
      • In all cases:
        • EthAccount returns ApplyAndCallReturn { status, output_data } to the caller, where status = 1 iff the callee exit code was ExitCode::OK.
        • If the rt.send fails at the syscall level, status=0 and output_data=[].
    • Tests to check:
      • Invalid cases: chainId, yParity, r/s size and zero, tuple arity, CBOR fuzzing
        ../builtin-actors/actors/ethaccount/tests/apply_and_call_invalids.rs
        ../builtin-actors/actors/ethaccount/tests/apply_and_call_cbor_fuzz.rs.
      • Nonces and duplicates – apply_and_call_nonces.rs, apply_and_call_tuple_cap_boundary.rs.
      • R/S padding (accept 1..31, 32; reject >32) – apply_and_call_rs_padding.rs.
      • Value transfer behavior – apply_and_call_value_transfer.rs.
      • Outer call routing and status mapping – apply_and_call_outer_call.rs.

3.2 EVM Actor

  • Minimalization (../builtin-actors/actors/evm/src/lib.rs)
    • Delegation state and execution have been removed from the EVM actor:
      • Legacy ApplyAndCall and InvokeAsEoa are no longer used; InvokeAsEoa is a stub returning illegal_state.
      • InvokeAsEoaWithRoot remains as a private trampoline used by the VM intercept to execute delegate bytecode under the authority context, with an explicit storage root.
    • The interpreter:
      • Executes EVM bytecode normally for direct calls.
      • No longer re‑follows delegation internally – delegation is entirely handled at the VM layer.
      • EXTCODE* behavior consults the runtime helper for delegated EOAs, but the pointer image itself is defined in ref-fvm (see section 4.2).

4. VM Layer (ref-fvm)

4.1 Delegated CALL Intercept

  • Entry point

    • Implemented in DefaultCallManager::intercept_evm_call_to_ethaccount (inlined into call_actor_unchecked) – see ../ref-fvm/fvm/src/call_manager/default.rs:560.
    • Gated by:
      • Receiver code being an EthAccount builtin actor.
      • Entrypoint method matching FRC‑42 hash of "InvokeEVM" (EVM Invoke entrypoint).
      • A non‑empty EthAccount state with delegate_to set.
  • Flow (high level)

    1. Fetch caller and receiver actor state.
    2. Decode EthAccount state (delegate_to, auth_nonce, evm_storage_root). If delegate_to is None, do not intercept.
    3. Resolve delegate_to as a delegated f4 under EAM, ensure actor exists.
    4. Call the delegate’s GetBytecode method (method 3) to obtain the bytecode CID; abort interception if missing or non‑success.
    5. Extract the EVM input bytes from the original params block.
    6. Compute:
      • caller_eth20 from the caller’s f4 delegated address, and
      • authority_eth20 from the EthAccount’s f4 delegated address.
    7. Build InvokeAsEoaWithRoot params:
      • code: delegate bytecode CID.
      • input: original CALL input.
      • caller: caller EthAddress (20 bytes).
      • receiver: authority EthAddress (20 bytes).
      • value: original CALL value.
      • initial_storage_root: ea.evm_storage_root.
    8. Perform a value transfer to the authority before executing delegate code:
      • If value != 0, charge gas and transfer(from, to, value).
      • On failure, short‑circuit: return a non‑success exit code and empty return bytes; do not execute the delegate and do not alter evm_storage_root – see delegated_value_transfer_short_circuit.rs.
    9. Mark delegation_active = true for this call so nested CALLs by the delegate do not re‑enter the interception path (depth limit = 1).
    10. Invoke the caller EVM actor’s InvokeAsEoaWithRoot method (self‑call) with full available gas.
    11. On non‑success, propagate the exit code + return block as‑is to the original CALL (revert mapping), and do not persist storage – see delegated_call_mapping.rs.
    12. On success:
      • Decode (output_data, new_storage_root) from the return block.
      • Write updated EthAccount state with the new evm_storage_root while preserving balance and code.
      • Emit a Delegated(address) event:
        • topic0 = keccak256("Delegated(address)").
        • Data: one 32‑byte ABI word whose last 20 bytes are authority_eth20.
      • Return OK + raw output_data as IPLD IPLD_RAW block to the EVM interpreter.
  • Depth limit & SELFDESTRUCT

    • delegation_active flag ensures nested CALLs are not re‑intercepted; depth is strictly 1 – see ../ref-fvm/fvm/tests/depth_limit.rs.
    • In authority context, SELFDESTRUCT does not move balance or tombstone the authority; behavior is tested in selfdestruct_noop_authority.rs.
  • Storage overlay semantics

    • evm_storage_root is mounted before executing delegate code.
    • On success, the new storage root is persisted back into EthAccount state – see overlay_persist_success.rs.
    • On revert or transfer short‑circuit, the overlay is discarded and evm_storage_root is left unchanged – see delegated_call_mapping.rs and delegated_value_transfer_short_circuit.rs.
  • Tests to review

    • delegated_call_mapping.rs – success path and revert payload propagation.
    • delegated_event_emission.rs – topic and ABI word correctness for Delegated(address).
    • overlay_persist_success.rs – storage overlay persistence on success.
    • delegated_value_transfer_short_circuit.rs – value transfer failure semantics.
    • depth_limit.rs – depth=1 enforcement.
    • selfdestruct_noop_authority.rsSELFDESTRUCT no‑op.

4.2 EXTCODE* Pointer Projection

  • Runtime helper + syscall

    • New syscall actor::get_eth_delegate_to:
      • Kernel implementation: ../ref-fvm/fvm/src/syscalls/actor.rs:182.
      • SDK wrapper + pure helper:
        • extract_eth20 and get_eth_delegate_to in ../ref-fvm/sdk/src/actor.rs:180.
      • Behavior: returns the 20‑byte delegate_to if set; supports both 20‑byte and 32‑byte (ABI word) encodings by slicing the last 20 bytes.
  • Interpreter behavior

    • The EVM interpreter checks get_eth_delegate_to(target_id) when executing EXTCODE* on EOAs.
    • If a delegate is present:
      • EXTCODESIZE returns 23.
      • EXTCODEHASH returns keccak(pointer_code).
      • EXTCODECOPY returns the appropriate window into pointer_code, with zero‑fill on out‑of‑range offsets.
    • Validated by evm_extcode_projection.rs (windowing and zero‑fill) and by hash checks.
  • Helper tests

    • sdk/src/actor.rs has unit tests for extract_eth20 to ensure correct slicing behavior for short/20/32‑byte inputs.

4.3 Test Harness / Runner

  • ../ref-fvm/scripts/run_eip7702_tests.sh:
    • Builds the builtin‑actors bundle in Docker (with ref-fvm mounted) and then runs cargo test -p fvm.
    • Falls back to running tests inside Docker if the host toolchain fails.
    • Coverage includes EXTCODE* projection, depth limit, value transfer short‑circuit, overlay persistence, and event emission.

5. Lotus Client Behavior

5.1 Transaction Parsing and Encoding

  • RLP and magic constants

    • Eth7702TxArgs and EthAuthorization live in chain/types/ethtypes/eth_7702_transactions.go.
    • Per‑type RLP list length for 0x04 is enforced (13 elements) with per‑field parsing and yParity checks.
    • Magic constants and domain helpers:
      • SetCodeAuthorizationMagic = 0x05.
      • Pointer bytecode prefix and version: {Eip7702BytecodeMagicHi = 0xEF, MagicLo = 0x01, Version = 0x00}.
      • AuthorizationPreimage and AuthorizationKeccak implement the hashing logic used by EthAccount – see chain/types/ethtypes/eth_7702_magic.go.
  • ToUnsignedFilecoinMessageAtomic (eth_7702_transactions.go:121)

    • Enforces ChainID == buildconstants.Eip155ChainId.
    • Requires Eip7702FeatureEnabled and a configured EthAccountApplyAndCallActorAddr.
    • CBOR‑encodes the atomic params [ [tuples...], [to(20), value, input] ] and builds a types.Message:
      • To = EthAccountApplyAndCallActorAddr.
      • Method = MethodHash("ApplyAndCall") (FRC‑42).
      • Value = 0 (gas and fees only; outer call value is embedded in params).

5.2 Receipts & RPC Surface

  • Types

    • EthTx gains AuthorizationList []EthAuthorization.
    • EthTxReceipt gains:
      • AuthorizationList []EthAuthorization (copied from tx view), and
      • DelegatedTo []EthAddress (derived by Lotus) – see chain/types/ethtypes/eth_types.go:1260.
  • Receipt construction (node/impl/eth/utils.go:450)

    • newEthTxReceipt:
      • Builds a base receipt from Tx + MessageReceipt.
      • Copies AuthorizationList if present on the tx.
      • Defaults Status off the Filecoin ExitCode (1 on success, 0 otherwise).
      • Override for 0x04:
        • If tx.Type == 0x04 and the Filecoin return payload is non‑empty, decodeApplyAndCallReturnStatus parses [status(uint), output_data(bytes)] and sets Status = (status != 0).
        • This reflects the embedded outer call result from EthAccount, not the actor’s own exit code (which is always OK).
  • Delegation attribution (adjustReceiptForDelegation)

    • Called from both EthGetTransactionReceipt and EthGetBlockReceipts*
      – see node/impl/eth/transaction.go:345.
    • Behavior:
      • If AuthorizationList is non‑empty, DelegatedTo is populated from the tuple addresses.
      • If DelegatedTo is still empty, it scans receipt logs for topic keccak256("Delegated(address)") and:
        • For each matching log, treats data as a 32‑byte ABI word and copies the last 20 bytes into an EthAddress, appending to DelegatedTo.
      • This lets Lotus reconstruct delegatedTo either from tuples or from the synthetic event emitted by ref-fvm.
  • Tests to review

    • node/impl/eth/utils_7702_test.go – ensures AuthorizationList round‑trips into receipts.
    • node/impl/eth/receipt_7702_scaffold_test.go – exercises adjustReceiptForDelegation both from tuples and logs.
    • node/impl/eth/transaction_7702_receipts_test.go – validates end‑to‑end receipt behavior for 0x04.

5.3 Gas Estimation

  • Behavioral overhead only (node/impl/eth/gas_7702_scaffold.go)
    • compute7702IntrinsicOverhead(authCount int) int64 is a placeholder model:
      • 0 when authCount == 0.
      • baseOverheadGas + perAuthBaseGas * authCount otherwise.
    • countAuthInApplyAndCallParams(params []byte) int parses the CBOR ApplyAndCall payload and returns the number of tuples in the list; this is used by eth_estimateGas to add per‑tuple overhead when the target is EthAccount.ApplyAndCall.
    • Importantly, consensus gas accounting in FVM is unchanged; this is purely an estimation UX feature.

5.4 E2E Tests

  • itests/eth_7702_e2e_test.go (build tag eip7702_enabled)
    • TestEth7702_SendRoutesToEthAccount:
      • Constructs and signs a 0x04 tx with a non‑empty authorizationList.
      • Sends via eth_sendRawTransaction.
      • Asserts that the resulting Filecoin message in the mpool targets EthAccount.ApplyAndCall from the recovered f4 sender.
    • TestEth7702_ReceiptFields:
      • Mines a 0x04 tx and checks that the JSON‑RPC receipt exposes authorizationList and delegatedTo.

6. Security, Spec Compliance, and Edge Cases

  • Atomicity and persistence

    • EthAccount:
      • Applies delegation mapping and bumps auth_nonce inside a transaction before the outer call.
      • Always exits OK, with status embedded in return.
      • As a result, delegation mapping + nonce bumps always persist, even if the outer call fails or reverts.
    • ref-fvm:
      • Storage overlay (evm_storage_root) persists only on successful delegated CALLs; it is discarded on revert or transfer short‑circuit.
  • Pre‑existence policy

    • Authorities cannot be EVM contracts:
      • EthAccount rejects tuples whose recovered authority resolves to a builtin EVM actor.
      • This aligns with “code must be empty/pointer” semantics.
  • Tuple cap and duplicates

    • Message‑level tuple cap ≤ 64 enforced in EthAccount.
    • Duplicate authorities within authorizationList are rejected.
  • Signature robustness

    • Lotus uses minimally encoded big‑endian r/s.
    • EthAccount accepts 1..31 and 32 byte r/s and left‑pads to 32 bytes; rejects > 32.
    • Low‑s enforced after padding; zero r/s rejected.
    • Tests in apply_and_call_rs_padding.rs lock in the positive/negative cases.
  • Depth, SELFDESTRUCT, and reverts

    • Delegation chains are not followed beyond depth 1; VM intercept is disabled for nested authority context.
    • SELFDESTRUCT is a no‑op in authority context (no balance move, no tombstone).
    • Revert mapping:
      • Non‑success exit codes and revert data from the delegate trampoline are propagated back to the EVM caller; RETURNDATASIZE/RETURNDATACOPY see the delegate’s revert payload, subject to the minimal‑feature caveat in tests.
  • Pointer semantics

    • For an authority A delegated to B:
      • EXTCODESIZE(A) == 23.
      • EXTCODECOPY(A, 0, 0, 23)0xEF 0x01 0x00 || B(20).
      • EXTCODEHASH(A) == keccak(pointer_code).
    • All verified in evm_extcode_projection.rs.

7. How to Review (Per Repo)

  • builtin‑actors (../builtin-actors)

    • Focus on:
      • actors/ethaccount/src/lib.rs:187ApplyAndCall validation, nonce/mapping updates, pre‑existence checks, and outer call routing.
      • actors/ethaccount/src/state.rs:5 – state struct.
      • actors/evm/src/lib.rs – removal of legacy delegation entrypoints; presence and use of InvokeAsEoaWithRoot.
      • EthAccount test suite in actors/ethaccount/tests/*.
    • Validate:
      • Tuple validation matches Lotus’ AuthorizationKeccak encoding and RLP rules.
      • Mapping + nonce behavior (including persistence on outer call failure).
      • Pre‑existence policy (authorities are not EVM contracts).
      • Outer call routing correctly differentiates EVM vs non‑EVM targets.
  • ref-fvm (../ref-fvm)

    • Focus on:
      • Delegated CALL intercept and overlay persistence in fvm/src/call_manager/default.rs:560.
      • keccak32 and FRC‑42 helpers and their tests in the same file.
      • Syscall and SDK plumbing for get_eth_delegate_to:
        • fvm/src/syscalls/actor.rs:182.
        • sdk/src/sys/actor.rs and sdk/src/actor.rs:180.
      • E2E tests for delegation, EXTCODE*, depth, SELFDESTRUCT, and events in fvm/tests/*.rs.
    • Validate:
      • Intercept gating is correct (only InvokeEVM to EthAccount with active delegate_to).
      • Value transfer semantics and short‑circuit behavior.
      • Storage overlay is mounted and persisted only on success.
      • Event topic and ABI word match the Lotus receipt adjuster.
  • Lotus (./lotus)

    • Focus on:
      • 0x04 parsing and CBOR encoding in chain/types/ethtypes/eth_7702_transactions.go:121.
      • Magic constants and AuthorizationKeccak in chain/types/ethtypes/eth_7702_magic.go.
      • Receipt status override and AuthorizationList copying in node/impl/eth/utils.go:450.
      • adjustReceiptForDelegation and wiring in node/impl/eth/receipt_7702_scaffold.go:19 and node/impl/eth/transaction.go:345.
      • Gas estimation scaffolding in node/impl/eth/gas_7702_scaffold.go.
      • E2E tests in itests/eth_7702_e2e_test.go.
    • Validate:
      • TxHash / AuthorizationKeccak parity with EthAccount’s internal recovery logic.
      • EthTx / EthTxReceipt JSON surfaces match expectations (tooling should see authorizationList and delegatedTo).
      • Receipt status mapping correctly reflects ApplyAndCallReturn.status.
      • Gas estimation only depends on tuple count and does not bake in consensus constants.

8. How to Run the Relevant Tests

  • ref-fvm + builtin‑actors

    • Recommended: ../ref-fvm/scripts/run_eip7702_tests.sh (Docker bundle + cargo test -p fvm).
  • builtin‑actors (local)

    • make check
    • cargo test -p fil_actor_evm
    • cargo test -p fil_actor_ethaccount
  • Lotus

    • Unit / parser tests:
      • go test ./chain/types/ethtypes -run 7702 -count=1
      • go test ./node/impl/eth -run 7702 -count=1
    • E2E (requires updated wasm bundle and eip7702_enabled tag):
      • go test ./itests -run Eth7702 -tags eip7702_enabled -count=1

This guide should match the current EthAccount + VM‑intercept implementation across all three repos. If you want, I can now tailor a shorter reviewer checklist per PR (e.g., “things to look at commit‑by‑commit” for each repo).

snissn avatar Nov 12 '25 17:11 snissn

Codecov Report

:x: Patch coverage is 30.20528% with 238 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 76.65%. Comparing base (8a9321f) to head (d13136b). :warning: Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
fvm/src/call_manager/default.rs 22.67% 208 Missing :warning:
fvm/src/syscalls/actor.rs 0.00% 19 Missing :warning:
sdk/src/actor.rs 71.42% 10 Missing :warning:
fvm/src/kernel/default.rs 94.11% 1 Missing :warning:
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2227      +/-   ##
==========================================
- Coverage   77.58%   76.65%   -0.94%     
==========================================
  Files         147      147              
  Lines       15789    16130     +341     
==========================================
+ Hits        12250    12364     +114     
- Misses       3539     3766     +227     
Files with missing lines Coverage Δ
fvm/src/syscalls/mod.rs 97.15% <100.00%> (+0.01%) :arrow_up:
fvm/src/kernel/default.rs 82.47% <94.11%> (+0.24%) :arrow_up:
sdk/src/actor.rs 20.66% <71.42%> (+20.66%) :arrow_up:
fvm/src/syscalls/actor.rs 79.47% <0.00%> (-11.44%) :arrow_down:
fvm/src/call_manager/default.rs 71.42% <22.67%> (-18.63%) :arrow_down:

... and 2 files with indirect coverage changes

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov-commenter avatar Nov 12 '25 18:11 codecov-commenter

@copilot open a new pull request to apply changes based on the comments in this thread

snissn avatar Nov 21 '25 00:11 snissn

@copilot open a new pull request to apply changes based on the comments in this thread

BigLep avatar Dec 01 '25 19:12 BigLep

@snissn : it doesn't look like @copilot will do the work because it's a "cross-repository" change. Here is the error/warning I see:

image

BigLep avatar Dec 01 '25 19:12 BigLep