Skip to content

doc(execution-validation): denylist.rs claims execution-level enforcement but the check is never called from EVM pre_execution #495

Open

Description

@forumevi

Summary

The module-level doc comment in crates/execution-validation/src/denylist.rs states:

Call from both mempool and execution/Revm.

In practice the is_denylisted helper is called only from the txpool validator (crates/execution-txpool/src/validator.rs:352).
It is not called from ArcEvmHandler::pre_execution, ArcEvm::before_frame_init, or anywhere else in the EVM execution path.

Reproduction (code trace)

  1. crates/evm/src/handler.rs ArcEvmHandler::pre_execution calls check_blocklist (which reads NativeCoinControl) then delegates to mainnet.pre_execution. No call to is_denylisted.
  2. crates/evm/src/evm.rs ArcEvm::before_frame_init performs the blocklist + EIP-7708 log path. No call to is_denylisted.
  3. crates/execution-validation/src/denylist.rs is_denylisted is only imported in crates/execution-txpool/src/validator.rs.
  4. ArcConsensus::validate_block_post_execution delegates to reth's standard function with no denylist check.

Impact

The docstring creates a false expectation that a denylisted address is blocked at execution time (for example, during engine API block import) as well as at the mempool level.
Under the current code, a node operator who bypasses the mempool (direct engine-API payload or a custom block proposal) could execute a transaction from or to a denylisted address.

For Arc's current trust model (Circle-operated, permissioned validator set) this may be an accepted design choice.
If so, the docstring should be corrected. If execution-level enforcement is intended, handler.rs pre_execution is the natural place to call is_denylisted for the sender and (for value-bearing calls) the recipient.

Suggested fix (documentation path)

--- a/crates/execution-validation/src/denylist.rs
+++ b/crates/execution-validation/src/denylist.rs
-//! Call from both mempool and execution/Revm.
+//! Currently called only from mempool (txpool) validation.
+//! Execution-level enforcement is not implemented; the current trust model
+//! relies on the permissioned validator set to exclude denylisted transactions
+//! from proposed blocks.

Or, if execution-level enforcement is desired, ArcEvmHandler::pre_execution would need to call is_denylisted for tx.caller() (and tx.to() for value-bearing transactions) before delegating to the mainnet handler.

Activity

  1. osr21 commented on Oct 29, 2026

    @osr21

    One design boundary worth making explicit is whether this denylist is a txpool-admission filter or a consensus/execution invariant.

    If it is txpool-only, update the module-level comment and docs to say that local transaction-pool filtering does not guarantee rejection of transactions in imported blocks. If it must be consensus-enforced, put the check on a common block-validation/execution path rather than only a local submission path, and test both locally built payloads and imported blocks. It would also help to define whether the rule covers senders, recipients, contract creation, and internal calls. That keeps validators from applying different block-validity rules based on local txpool policy.

  2. forumevi commented on Oct 30, 2026

    @forumevi
    Author

    Good point on the design boundary. To add to this: the current check_blocklist in ArcEvmHandler::pre_execution (handler.rs) reads from NativeCoinControl storage -- a separate enforcement path from is_denylisted. So there are actually two distinct denylist mechanisms running in parallel, with different call sites and different storage backends. Making that separation explicit in the docs (or collapsing them into one path) would also prevent future confusion about which list is being enforced where.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions