Skip to content

Add scenario access list support with placeholder resolution#588

Merged
zeroXbrock merged 3 commits into
flashbots:mainfrom
jelias2:jelias/access-list-with-placeholders
Jun 5, 2026
Merged

Add scenario access list support with placeholder resolution#588
zeroXbrock merged 3 commits into
flashbots:mainfrom
jelias2:jelias/access-list-with-placeholders

Conversation

@jelias2

@jelias2 jelias2 commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Builds on #581 to address @zeroXbrock's reviewer feedback: allow {placeholder} strings in access list address and storageKeys.

PR #581 currently uses alloy's typed AccessListItem on both the loose and strict sides, which cannot hold placeholder strings during the loose-to-strict conversion phase. This PR:

  • Adds LooseAccessListItem { address: String, storage_keys: Vec<String> } on the loose side (keeps storageKeys camelCase from Add scenario access list support #581).
  • Keeps the strict side as alloy's typed AccessListItem (per @zeroXbrock's design).
  • Resolves placeholders in make_strict_call via the existing templater + DB-driven map, parsing into Address / B256.
  • Extends find_fncall_placeholders to scan access list strings so the DB lookup pre-populates referenced contract addresses.
  • openrpc.json regenerated by cli/build.rs.

Example

[[spam.tx.access_list]]
address = "{SpamMe5}"
storageKeys = [
    "{testkey1}",
    "{testkey2}",
]

Relationship to #581

This branch was built on top of #581 (scenario-access-list-support, head 6460cb4). If #581 is the preferred merge vehicle, this PR could be re-targeted at karlfloersch's branch so the placeholder support lands inside the existing review thread. Filing here against main as the more flexible default — happy to retarget.

Tests

  • cargo +1.94 test -p contender_core access_list --lib — 3 passed
  • cargo +1.94 test -p contender_testfile --lib — 22 passed
  • cargo +1.94 fmt --check — clean
  • Two new placeholder tests added:
    • access_list_parses_placeholders_from_toml (contender_core)
    • parses_spam_tx_access_list_with_placeholders_toml (contender_testfile)
  • Release binary built and smoke-tested via an external benchmarker invocation against a real devnet for backwards compatibility.

Test plan

  • Unit tests in both crates pass
  • cargo fmt --check clean
  • Backwards compat: existing scenarios without access_list still build and broadcast correctly
  • Manual: scenarios with hard-coded address + storageKeys still work (no placeholder)
  • Manual: scenarios with {Contract} placeholder for address resolve correctly
  • Manual: scenarios with {slot} placeholder for storage keys resolve correctly
  • Reviewer test against an L2 with EIP-2930 enforcement

@jelias2
jelias2 requested a review from zeroXbrock as a code owner May 29, 2026 20:42
@jelias2
jelias2 force-pushed the jelias/access-list-with-placeholders branch from 77f485b to 8cf063a Compare May 29, 2026 21:11
@zeroXbrock

Copy link
Copy Markdown
Member

thanks @jelias2. Could you re-target to #581? Will be much easier to review with just the diff over karl's previous code.

@jelias2

jelias2 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Re-targeted per @zeroXbrock's request — reopened as a clean diff on top of #581 here: karlfloersch#1 (base scenario-access-list-support). Closing this one in favor of that. The diff there is just the placeholder layer (~140 lines across 5 files).

@jelias2 jelias2 closed this Jun 2, 2026
@jelias2

jelias2 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@zeroXbrock rebased this on top of #581 (scenario-access-list-support) so it's now stacked on Karl's work rather than reimplementing it. My commit is a single layer on top: LooseAccessListItem (string address/storageKeys that accept {placeholder} tokens) resolved into alloy's strict AccessListItem during loose→strict conversion via the existing templater + DB map. Diff over Karl's branch is just 5 files / +141 / -7 (placeholder resolution + tests + regenerated openrpc.json).

I couldn't re-point the PR base to scenario-access-list-support directly: that branch lives only on Karl's fork, and GitHub requires the base branch to exist in flashbots/contender (I don't have push access to do that). So this PR still targets main and shows Karl's access-list changes + mine combined. Once #581 merges (or the branch lands in upstream), I'm happy to re-point the base so it shows just the diff on top.

Build + access-list tests green on 1.94.0.

@jelias2 jelias2 reopened this Jun 2, 2026
@jelias2

jelias2 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

For the clean diff-over-Karl review, I opened a fork-to-fork PR against scenario-access-list-support directly: karlfloersch#1 — it shows just this change layered on #581 (5 files / +141 / -11), without Karl's underlying changes mixed in.

@zeroXbrock zeroXbrock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @jelias2 -- design looks fine, but I'm having trouble testing it. I updated scenarios/simple.toml with this:

[[spam]]
[spam.tx]
to = "{SpamMe5}"
signature = "callPrecompile(string memory method, uint256 iterations)"
args = ["ecMul", "5"]
[[access_list]]
address = "{SpamMe5}"
storageKeys = [
    "0x0100000000000000000000000000000000000000000000000000000000000000",
    "0x0300000000000000000000000000000000000000000000000000000000000000",
]

but I'm not seeing access_list in the transactions that are being sent.

Could you also resolve the merge conflicts?

@jelias2

jelias2 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for testing @zeroXbrock. That's a TOML pathing gotcha, not the feature itself. [[access_list]] is an array-of-tables at the root, so it never attaches to spam.tx and gets dropped from the FunctionCallDefinition (hence no access list on the tx). It needs the fully-qualified header [[spam.tx.access_list]]:

[[spam]]
[spam.tx]
to = "{SpamMe5}"
signature = "callPrecompile(string memory method, uint256 iterations)"
args = ["ecMul", "5"]

[[spam.tx.access_list]]
address = "{SpamMe5}"
storageKeys = [
    "0x0100000000000000000000000000000000000000000000000000000000000000",
    "0x0300000000000000000000000000000000000000000000000000000000000000",
]

Parse check of the two forms:

  • [[access_list]]spam.tx = {to, signature, args}; stray access_list sits at the root and is ignored.
  • [[spam.tx.access_list]]spam.tx includes access_list

@jelias2

jelias2 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

Confirmed live with the fully-qualified path: spamming interop sendMessage with [[spam.tx.access_list]], the access list lands on-chain.

tx 0x8ce4ffe838829529368cc4dce4a1087838e13c58d44acf495d1552f5268ae53b:

to:         0x4200000000000000000000000000000000000023  (L2ToL2CrossDomainMessenger)
type:       0x2
accessList: [{ address: 0x...dead, storageKeys: [0x0100...00, 0x0300...00] }]
receipt:    status 0x1, emits SentMessage (topic 0x382409ac...)

@zeroXbrock zeroXbrock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @jelias2, you're right. I can't see the diff where I got that code from -- it was in the docs but appears to be patched now. Working on my end, looks good!

thanks again, appreciate your contribution @jelias2 🙏

Supersedes flashbots#581. Adds an `access_list` field to FunctionCallDefinition
that accepts {placeholder} strings in `address` and `storageKeys`,
resolved during the loose-to-strict conversion via the existing
templater + DB map.

Coexists with max_priority_fee_per_gas (flashbots#580) and alloy 2.0 (flashbots#561).
@jelias2
jelias2 force-pushed the jelias/access-list-with-placeholders branch from 37cd34a to 025f0d3 Compare June 4, 2026 02:55
@zeroXbrock

Copy link
Copy Markdown
Member

@jelias2 is there any way you could revise this branch to include @karlfloersch's commits? This PR strips his credit.
To get around the confusion with permissions, I'd just make a new branch that forks from #581 (I use gh pr checkout) and merge this branch into it, then resolve any merge conflicts. Then you could either force-push that to this branch or make a new PR, whichever is easier.

@karlfloersch

Copy link
Copy Markdown

Appreciate it @zeroXbrock but we don't need to give me credit, that way if something goes wrong folks point their finger at @jelias2 instead of at me 😁

Let's ship! Thanks yall

@zeroXbrock zeroXbrock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @jelias2 @karlfloersch, works great! Just made a little change to support [env] placeholders as well.

@zeroXbrock
zeroXbrock merged commit daa8fb7 into flashbots:main Jun 5, 2026
6 of 7 checks passed
This was referenced Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants