44package txfilter
55
66import (
7+ "crypto/sha256"
78 "sync"
89 "testing"
910
11+ "github.com/stretchr/testify/assert"
12+ "github.com/stretchr/testify/require"
13+
1014 "github.com/ethereum/go-ethereum/common"
11- "github.com/ethereum/go-ethereum/crypto"
15+
16+ "github.com/offchainlabs/nitro/restrictedaddr"
1217)
1318
19+ func mustState (t * testing.T , s any ) * HashedAddressCheckerState {
20+ t .Helper ()
21+ state , ok := s .(* HashedAddressCheckerState )
22+ require .Truef (t , ok , "unexpected AddressCheckerState type %T" , s )
23+ return state
24+ }
25+
1426func TestHashedAddressCheckerSimple (t * testing.T ) {
1527 salt := []byte ("test-salt" )
1628
1729 addrFiltered := common .HexToAddress ("0x000000000000000000000000000000000000dead" )
1830 addrAllowed := common .HexToAddress ("0x000000000000000000000000000000000000beef" )
1931
20- filteredHash := crypto .Keccak256Hash (addrFiltered .Bytes (), salt )
32+ store := restrictedaddr .NewHashStore ()
33+
34+ filteredHash := sha256 .Sum256 (append (salt , addrFiltered .Bytes ()... ))
35+ store .Load (salt , [][32 ]byte {filteredHash }, "test" )
2136
2237 checker := NewHashedAddressChecker (
23- []common.Hash {filteredHash },
24- salt ,
25- /* hashCacheSize */ 16 ,
38+ store ,
2639 /* workerCount */ 2 ,
2740 /* queueSize */ 8 ,
2841 )
2942
3043 // Tx 1: filtered address
31- //nolint:errcheck
32- state1 := checker .NewTxState ().(* HashedAddressCheckerState )
44+ state1 := mustState (t , checker .NewTxState ())
3345 state1 .TouchAddress (addrFiltered )
34-
35- if ! state1 .IsFiltered () {
36- t .Fatalf ("expected transaction to be filtered" )
37- }
46+ assert .True (t , state1 .IsFiltered (), "expected transaction to be filtered" )
3847
3948 // Tx 2: allowed address
40- //nolint:errcheck
41- state2 := checker .NewTxState ().(* HashedAddressCheckerState )
49+ state2 := mustState (t , checker .NewTxState ())
4250 state2 .TouchAddress (addrAllowed )
43-
44- if state2 .IsFiltered () {
45- t .Fatalf ("expected transaction NOT to be filtered" )
46- }
51+ assert .False (t , state2 .IsFiltered (), "expected transaction NOT to be filtered" )
4752
4853 // Tx 3: mixed addresses
49- //nolint:errcheck
50- state3 := checker .NewTxState ().(* HashedAddressCheckerState )
54+ state3 := mustState (t , checker .NewTxState ())
5155 state3 .TouchAddress (addrAllowed )
5256 state3 .TouchAddress (addrFiltered )
57+ assert .True (t , state3 .IsFiltered (), "expected transaction with mixed addresses to be filtered" )
5358
54- if ! state3 .IsFiltered () {
55- t .Fatalf ("expected transaction with mixed addresses to be filtered" )
56- }
57-
58- // Tx 4: reuse hash cache across txs
59- // Touch the same filtered address again; this must hit the hash cache
60- //nolint:errcheck
61- state4 := checker .NewTxState ().(* HashedAddressCheckerState )
59+ // Tx 4: reuse HashStore cache across txs
60+ state4 := mustState (t , checker .NewTxState ())
6261 state4 .TouchAddress (addrFiltered )
63-
64- if ! state4 .IsFiltered () {
65- t .Fatalf ("expected cached filtered address to still be filtered" )
66- }
62+ assert .True (t , state4 .IsFiltered (), "expected cached filtered address to still be filtered" )
6763
6864 // Tx 5: queue overflow should not panic and must be conservative
69- // Create a checker with zero queue size to force drops
7065 overflowChecker := NewHashedAddressChecker (
71- []common.Hash {filteredHash },
72- salt ,
73- /* hashCacheSize */ 16 ,
66+ store ,
7467 /* workerCount */ 1 ,
7568 /* queueSize */ 0 ,
7669 )
7770
78- //nolint:errcheck
79- overflowState := overflowChecker .NewTxState ().(* HashedAddressCheckerState )
71+ overflowState := mustState (t , overflowChecker .NewTxState ())
8072 overflowState .TouchAddress (addrFiltered )
8173
82- // Queue is full, work is dropped; result may be false, but must not panic
83- _ = overflowState .IsFiltered ()
74+ // false negative allowed
75+ assert .False (
76+ t ,
77+ overflowState .IsFiltered (),
78+ "expected overflowed check to be unfiltered (false negative allowed)" ,
79+ )
8480}
8581
8682func TestHashedAddressCheckerHeavy (t * testing.T ) {
8783 salt := []byte ("heavy-salt" )
8884
8985 const filteredCount = 500
9086 filteredAddrs := make ([]common.Address , filteredCount )
91- filteredHashes := make ([]common. Hash , filteredCount )
87+ filteredHashes := make ([][ 32 ] byte , filteredCount )
9288
9389 for i := range filteredAddrs {
9490 addr := common .BytesToAddress ([]byte {byte (i + 1 )})
9591 filteredAddrs [i ] = addr
96- filteredHashes [i ] = crypto . Keccak256Hash ( addr .Bytes (), salt )
92+ filteredHashes [i ] = sha256 . Sum256 ( append ( salt , addr .Bytes ()... ) )
9793 }
9894
95+ store := restrictedaddr .NewHashStore ()
96+ store .Load (salt , filteredHashes , "heavy" )
97+
9998 checker := NewHashedAddressChecker (
100- filteredHashes ,
101- salt ,
102- /* hashCacheSize */ 256 ,
99+ store ,
103100 /* workerCount */ 4 ,
104101 /* queueSize */ 32 ,
105102 )
@@ -116,14 +113,13 @@ func TestHashedAddressCheckerHeavy(t *testing.T) {
116113 go func (tx int ) {
117114 defer wg .Done ()
118115
119- //nolint:errcheck
120- state := checker .NewTxState ().(* HashedAddressCheckerState )
116+ state := mustState (t , checker .NewTxState ())
121117
122118 for i := range touchesPerTx {
123119 if i % 10 == 0 {
124120 state .TouchAddress (filteredAddrs [i % filteredCount ])
125121 } else {
126- addr := common .BytesToAddress ([]byte {byte (200 + i )})
122+ addr := common .BytesToAddress ([]byte {byte (200 + i * tx )})
127123 state .TouchAddress (addr )
128124 }
129125 }
@@ -135,15 +131,17 @@ func TestHashedAddressCheckerHeavy(t *testing.T) {
135131 wg .Wait ()
136132 close (results )
137133
138- // Post-conditions
139134 filteredTxs := 0
140135 for r := range results {
141136 if r {
142137 filteredTxs ++
143138 }
144139 }
145140
146- if filteredTxs == 0 {
147- t .Fatalf ("expected at least some transactions to be filtered under load" )
148- }
141+ assert .Greater (
142+ t ,
143+ filteredTxs ,
144+ 0 ,
145+ "expected at least some transactions to be filtered under load" ,
146+ )
149147}
0 commit comments