Skip to content

Conversation

@Tristan-Wilson
Copy link
Member

@Tristan-Wilson Tristan-Wilson commented Dec 18, 2025

Arbitrum needs to track all addresses touched during transaction execution to support address-based filtering at the sequencer level. This enables compliance use cases on certain chains where transactions interacting with certain addresses must be rejected before inclusion.

The implementation follows the existing arbTxFilter pattern in ArbitrumExtraData, adding a touchedAddresses map that collects addresses during execution. Three methods are added to the StateDB interface: AddTouchedAddress, GetTouchedAddresses, and ClearTouchedAddresses. The collection is automatically cleared at transaction boundaries via SetTxContext.

SELFDESTRUCT is handled by adding the SELFDESTRUCT beneficiary to touched addresses. The beneficiary address is captured in opSelfdestruct and opSelfdestruct6780.

pulled in by OffchainLabs/nitro#4157

fixes: NIT-4221

Arbitrum needs to track all addresses touched during transaction
execution to support address-based filtering at the sequencer level.
This enables compliance use cases where transactions interacting with
certain addresses must be rejected before inclusion.

The implementation follows the existing arbTxFilter pattern in
ArbitrumExtraData, adding a touchedAddresses map that collects
addresses during execution. Three methods are added to the StateDB
interface: AddTouchedAddress, GetTouchedAddresses, and
ClearTouchedAddresses. The collection is automatically cleared at
transaction boundaries via SetTxContext.
@Tristan-Wilson Tristan-Wilson changed the title Add touched address tracking to StateDB for tx filtering [core] Add touched address tracking to StateDB for tx filtering Dec 18, 2025
@Tristan-Wilson Tristan-Wilson changed the title [core] Add touched address tracking to StateDB for tx filtering core: Add touched address tracking to StateDB for tx filtering Dec 18, 2025
@Tristan-Wilson Tristan-Wilson marked this pull request as ready for review December 18, 2025 16:39
Tristan-Wilson and others added 2 commits December 19, 2025 10:19
Capture the beneficiary address in opSelfdestruct and opSelfdestruct6780
for transaction filtering.

// Arbitrum
AddTouchedAddress(addr common.Address)
GetTouchedAddresses() []common.Address
Copy link
Contributor

Choose a reason for hiding this comment

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

After thinking a lot.. this has two problems:

  1. it does unnecessary work for normal chains where there is no filter required, and for normal nodes which aren't sequencers.
  2. it doesn't allow room for starting to check addresses while the transaction is being processed.

I think it's better to register an address filter inside the stateDB, so stateDB will pass immediately any touchedaddress to the filter, and the filter could chose to start checking in parallel or not. Also, normal nodes/chians will just use an oopFilter that will do nothing in relation to AddTouchedAddress.

In that case - GetTouchedAddresses and ClearTouchedAddresses are not needed. StateDb willl pass through IsTxFiltered and ClearTxFilter to the filter.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the comment, I think I've addressed it now and I think it simplifies the design a lot.

Implement address filtering that checks addresses immediately as they're
touched during execution, rather than collecting them for later checking.

The AddressFilter interface is registered in StateDB, and TouchAddress()
checks the filter immediately, calling FilterTx() if the address is filtered.
// AddressFilter checks if addresses should be filtered from transactions.
// Used by Arbitrum for transaction filtering based on touched addresses.
type AddressFilter interface {
IsFiltered(addr common.Address) bool
Copy link
Contributor

Choose a reason for hiding this comment

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

this requires the filter to return a synchronous response per address.
I want the filter to have (not exact names):

  • TouchAddress - submits the address, called by TouchAddress (can also return an immediate filter if beneficiary, or possibly just an error)
  • IsFiltered - checks if any address was filtered, called by IsTxFiletered
  • ClearAddresses - resets previous addresses, called by ClearTxFiler

That way we could look in large databases using separate goroutines while main thread is executing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Addressed it with a stateless and stateful part of the filter.

Address review feedback requesting async-capable address filtering:
- TouchAddress submits addresses for checking (can start async checks)
- IsFiltered blocks until all checks complete and returns result
- Fresh state created per-tx in SetTxContext (replaces ClearAddresses)

This design allows implementations to check addresses in parallel using
separate goroutines while the main thread executes, enabling lookups in
large databases without blocking execution.

The two-part interface (AddressChecker/AddressCheckerState) lets each
implementation choose its own synchronization strategy (sync, WaitGroup,
channels, batch RPC) without coupling StateDB to a specific pattern.
Copy link
Contributor

@tsahee tsahee left a comment

Choose a reason for hiding this comment

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

LGTM

@tsahee tsahee merged commit d74712f into master Jan 2, 2026
17 checks passed
@tsahee tsahee deleted the statedb-touched-addresses branch January 2, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants