Skip to content

Update TouchAddress and IsFiltered to propagate filtering reasons#4557

Open
MishkaRogachev wants to merge 6 commits intomasterfrom
update-touchaddress-and-hashedaddresscheckerstateisfiltered
Open

Update TouchAddress and IsFiltered to propagate filtering reasons#4557
MishkaRogachev wants to merge 6 commits intomasterfrom
update-touchaddress-and-hashedaddresscheckerstateisfiltered

Conversation

@MishkaRogachev
Copy link
Copy Markdown
Contributor

@MishkaRogachev MishkaRogachev commented Mar 24, 2026

Fixes NIT-4642
Pulls in OffchainLabs/go-ethereum#642

  • Updates all call sites to pass FilteredAddressRecord to TouchAddress and destructure IsFiltered return. Each call site annotates the reason (from, to, dealiased_from, retryable_*, event_rule, contract_address, contract_caller, selfdestruct_beneficiary).
  • HashedAddressCheckerState uses mutex-gated slice to collect filtered records.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

❌ Patch coverage is 18.46154% with 53 lines in your changes missing coverage. Please review.
✅ Project coverage is 34.54%. Comparing base (21e0cea) to head (6819ceb).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4557      +/-   ##
==========================================
+ Coverage   34.30%   34.54%   +0.24%     
==========================================
  Files         498      498              
  Lines       59096    59121      +25     
==========================================
+ Hits        20270    20424     +154     
+ Misses      35238    35077     -161     
- Partials     3588     3620      +32     

@MishkaRogachev MishkaRogachev force-pushed the update-touchaddress-and-hashedaddresscheckerstateisfiltered branch from 4081e00 to d5ebca5 Compare March 24, 2026 15:22
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 24, 2026

❌ 7 Tests Failed:

Tests completed Failed Passed Skipped
4691 7 4684 0
View the top 3 failed tests by shortest run time
TestAliasingFlaky
Stack Traces | -0.000s run time
=== RUN   TestAliasingFlaky
=== PAUSE TestAliasingFlaky
=== CONT  TestAliasingFlaky
    common_test.go:777: BuildL1 deployConfig: DeployBold=true, DeployReferenceDAContracts=false
INFO [04-01|15:15:10.952] Submitted contract creation              hash=0x399184f9977f0f6ea1e1f807698efdd88b4fcbb85106214486ecbfdf28b60683 from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=0  contract=0xA46C59ce2FCaF445F96f66F0411e06A94D34BF45 value=0
WARN [04-01|15:15:10.952] Served eth_getTransactionReceipt         reqid=7 duration="37.37µs" err="transaction indexing is in progress" errdata="\"transaction indexing is in progress\""
INFO [04-01|15:15:10.952] Starting work on payload                 id=0x03f1852593b40fb7
INFO [04-01|15:15:10.953] Updated payload                          id=0x03f1852593b40fb7                      number=1 hash=07dc74..200879 txs=1  withdrawals=0 gas=854,353 fees=8.54353e-07 root=fde2e1..e3e477 elapsed="344.471µs"
INFO [04-01|15:15:10.953] Starting peer-to-peer node               instance=test-stack-name/linux-amd64/go1.25.8
WARN [04-01|15:15:10.953] P2P server will be useless, neither dialing nor listening
INFO [04-01|15:15:10.953] Stopping work on payload                 id=0x03f1852593b40fb7                      reason=delivery
WARN [04-01|15:15:10.953] Getting file info                        dir= error="stat : no such file or directory"
INFO [04-01|15:15:10.953] Started log indexer
TestBatchPosterL1SurplusMatchesBatchGasFlaky
Stack Traces | 0.540s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
panic: runtime error: invalid memory address or nil pointer dereference [recovered, repanicked]
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x207b852]

goroutine 12 [running]:
testing.tRunner.func1.2({0x37e0de0, 0x61f49b0})
	/opt/hostedtoolcache/go/1.25.8/x64/src/testing/testing.go:1872 +0x237
testing.tRunner.func1()
	/opt/hostedtoolcache/go/1.25.8/x64/src/testing/testing.go:1875 +0x35b
panic({0x37e0de0?, 0x61f49b0?})
	/opt/hostedtoolcache/go/1.25.8/x64/src/runtime/panic.go:783 +0x132
github.com/offchainlabs/nitro/arbnode.(*InboxTracker).GetBatchCount(0x1b85f900?)
	/home/runner/work/nitro/nitro/arbnode/inbox_tracker.go:210 +0x12
github.com/offchainlabs/nitro/arbnode.(*InboxTracker).FindInboxBatchContainingMessage(0x0, 0x8)
	/home/runner/work/nitro/nitro/arbnode/inbox_tracker.go:225 +0x2f
github.com/offchainlabs/nitro/system_tests.TestBatchPosterL1SurplusMatchesBatchGasFlaky(0xc000379dc0)
	/home/runner/work/nitro/nitro/system_tests/batch_poster_test.go:839 +0x725
testing.tRunner(0xc000379dc0, 0x41b2ed8)
	/opt/hostedtoolcache/go/1.25.8/x64/src/testing/testing.go:1934 +0xea
created by testing.(*T).Run in goroutine 1
	/opt/hostedtoolcache/go/1.25.8/x64/src/testing/testing.go:1997 +0x465
TestParentChainEthConfigForkTransition
Stack Traces | 2.480s run time
... [CONTENT TRUNCATED: Keeping last 20 lines]
INFO [04-01|17:19:51.148] Deploying ospMem
WARN [04-01|17:19:51.148] Served eth_getTransactionReceipt         reqid=1   duration="27.14µs"   err="transaction indexing is in progress" errdata="\"transaction indexing is in progress\""
INFO [04-01|17:19:51.149] Submitted contract creation              hash=0xece084c28b88193acca65de5e7f532b73e8c3f5500c48e7df028612bbcea9451 from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=13 contract=0xc917c6b60239C48bd6C7155A6BEeFF79978C8cBd value=0
INFO [04-01|17:19:51.150] Deploying ospMem
INFO [04-01|17:19:51.154] Submitted contract creation              hash=0x461b693c0ba9c2cb76bad83d1c0a4a967510a8ff3fc95972b4153766d13c08f8 from=0x57Ff0F473737a1c161bfF9efDF016F7991585088 nonce=14 contract=0xF34C2fac45527E55ED122f80a969e79A40547e6D value=0
INFO [04-01|17:19:51.154] Deploying ospMath
INFO [04-01|17:19:51.154] Starting work on payload                 id=0x0320367725014aa4
INFO [04-01|17:19:51.155] Updated payload                          id=0x0320367725014aa4 number=14 hash=5145f9..daec40 txs=1 withdrawals=0 gas=2,931,634  fees=2.931634e-06  root=367618..421885 elapsed="783.606µs"
INFO [04-01|17:19:51.156] Stopping work on payload                 id=0x0320367725014aa4 reason=delivery
INFO [04-01|17:19:51.158] Imported new potential chain segment     number=14 hash=5145f9..daec40 blocks=1 txs=1 mgas=2.932  elapsed=2.588ms     mgasps=1132.562 triediffs=49.39KiB  triedirty=0.00B
INFO [04-01|17:19:51.158] Chain head was updated                   number=14 hash=5145f9..daec40 root=367618..421885 elapsed="352.915µs"
WARN [04-01|17:19:51.159] empty sequencer message
WARN [04-01|17:19:51.159] reading virtual delayed message segment  delayedMessagesRead=0 afterDelayedMessages=1
INFO [04-01|17:19:51.159] InboxTracker                             sequencerBatchCount=1 messageCount=1 l1Block=30 l1Timestamp=2026-04-01T17:20:18+0000
INFO [04-01|17:19:51.159] Submitted transaction                    hash=0xba866342b0628290745d1c22808eaa6f0efc6f9bc20356dc2802dcb9c4ed143c from=0x26E554a8acF9003b83495c7f45F06edCB803d4e3 nonce=7  recipient=0x0C709F340F0BB2e361229e345B7e26999d0969Ab value=1
INFO [04-01|17:19:51.161] chosen sequencer changing                recommended=stdio://A
WARN [04-01|17:19:51.162] Getting file info                        dir= error="stat : no such file or directory"
WARN [04-01|17:19:51.162] signature not found for msg              pos=0
WARN [04-01|17:19:51.162] sequencer is not synced                  error="no consensus sync data available"
--- FAIL: TestParentChainEthConfigForkTransition (2.48s)

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

@MishkaRogachev MishkaRogachev marked this pull request as ready for review March 24, 2026 15:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Nitro’s transaction/address filtering plumbing so that touched addresses carry an explicit filtering reason and filtering queries can return the relevant records, enabling richer downstream filtering reports (NIT-4642; pulls in OffchainLabs/go-ethereum#642).

Changes:

  • Update TouchAddress call sites to pass a FilteredAddressRecord annotated with a concrete reason (from/to/event rules/retryable fields/contract context).
  • Update address-filter checker state to aggregate and return filtered address records (not just a boolean).
  • Extend unit tests and add a changelog entry documenting the API behavior change.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
execution/gethexec/sequencer.go Annotate touched addresses (from/to/event_rule) with filtering reasons; adapt to IsAddressFiltered() returning a tuple.
execution/gethexec/executionengine.go Propagate filtering reasons through delayed sequencing hooks, event filter touches, and retryable-related touches; adapt IsAddressFiltered() usage.
execution/gethexec/addressfilter/address_checker_test.go Update tests to pass filtering reasons and assert returned filtered records.
execution/gethexec/addressfilter/address_checker.go Replace atomic boolean with mutex-gated collection of FilteredAddressRecord results and return them from IsFiltered().
changelog/mrogachev-nit-4642.md Document the TouchAddress/IsFiltered API change for internal release notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

statedb.TouchAddress(addr)
statedb.TouchAddress(filter.FilteredAddressRecord{
Address: addr,
FilterReason: filter.FilterReason{Reason: filter.ReasonEventRule},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The other fields related to filter.ReasonEventRule will need to be filled here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

db.TouchAddress(addr)
db.TouchAddress(filter.FilteredAddressRecord{
Address: addr,
FilterReason: filter.FilterReason{Reason: filter.ReasonEventRule},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The other fields related to filter.ReasonEventRule will need to be filled here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

case <-s.checker.GetContext().Done():
// shutting down, conservatively mark filtered
s.report(true)
s.report(record, true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should not include the record in this case.
We don't want to report to an external system that a transaction was denied because the node was shutting down.
One idea is to report receive a pointer, and here we pass nil.
report will only add to s.filteredAddresses if the pointer is not nil.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

// If the checker is stopped, conservatively mark filtered
if s.checker.Stopped() {
s.report(true)
s.report(record, true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

state3.TouchAddress(filter.FilteredAddressRecord{Address: addrFiltered, FilterReason: filter.FilterReason{Reason: filter.ReasonTo}})
filtered3, records3 := state3.IsFiltered()
assert.True(t, filtered3, "expected transaction with mixed addresses to be filtered")
require.Len(t, records3, 1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lets create a test case that returns more than 1 records

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added in tx 4

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +782 to 783
if addressFiltered, _ := statedb.IsAddressFiltered(); statedb.IsTxFiltered() || addressFiltered {
return state.ErrArbTxFilter
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

IsAddressFiltered() is evaluated unconditionally in the if initializer, which removes the previous short-circuit behavior where IsTxFiltered() could skip the (potentially blocking) address-filter wait. Consider checking IsTxFiltered() first, then only calling IsAddressFiltered() if needed to avoid unnecessary waiting/latency when the tx is already filtered.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

pre-existing behaviour

Comment on lines +798 to 799
if addressFiltered, _ := statedb.IsAddressFiltered(); statedb.IsTxFiltered() || addressFiltered {
return state.ErrArbTxFilter
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

Same as above: IsAddressFiltered() now runs even when IsTxFiltered() is true due to the initializer form, which can add avoidable blocking/latency. Consider splitting the condition so address filtering is only awaited if tx filtering didn’t already reject.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

pre-existing behaviour

Comment on lines 90 to 99
// Tx 6: queue overflow should not panic and must be conservative
overflowChecker := NewHashedAddressChecker(
store,
/* workerCount */ 1,
/* queueSize */ 0,
)
overflowChecker.Start(context.Background())

// Tx 5: synchronous call
// Tx 6: synchronous call
overflowState := mustState(t, overflowChecker.NewTxState())
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

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

The comment says “queue overflow”, but queueSize is set to 0, which makes the channel unbuffered/synchronous rather than testing overflow of a bounded queue. Consider updating the comment (and/or adjusting the test to actually exercise the full-queue behavior if that’s what you want to validate).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed comment

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