github.com/ledgerwatch/erigon-lib@v1.0.0/commitment/hex_patricia_hashed_fuzz_test.go (about) 1 //go:build !nofuzz 2 3 package commitment 4 5 import ( 6 "bytes" 7 "encoding/binary" 8 "encoding/hex" 9 "math/rand" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 "golang.org/x/crypto/sha3" 14 15 "github.com/ledgerwatch/erigon-lib/common/length" 16 ) 17 18 // go test -trimpath -v -fuzz=Fuzz_ProcessUpdate$ -fuzztime=300s ./commitment 19 20 func Fuzz_ProcessUpdate(f *testing.F) { 21 ha, _ := hex.DecodeString("13ccfe8074645cab4cb42b423625e055f0293c87") 22 hb, _ := hex.DecodeString("73f822e709a0016bfaed8b5e81b5f86de31d6895") 23 24 f.Add(uint64(2), ha, uint64(1235105), hb) 25 26 f.Fuzz(func(t *testing.T, balanceA uint64, accountA []byte, balanceB uint64, accountB []byte) { 27 if len(accountA) == 0 || len(accountA) > 20 || len(accountB) == 0 || len(accountB) > 20 { 28 t.Skip() 29 } 30 31 builder := NewUpdateBuilder(). 32 Balance(hex.EncodeToString(accountA), balanceA). 33 Balance(hex.EncodeToString(accountB), balanceB) 34 35 ms := NewMockState(t) 36 ms2 := NewMockState(t) 37 hph := NewHexPatriciaHashed(20, ms.branchFn, ms.accountFn, ms.storageFn) 38 hphAnother := NewHexPatriciaHashed(20, ms2.branchFn, ms2.accountFn, ms2.storageFn) 39 40 hph.SetTrace(false) 41 hphAnother.SetTrace(false) 42 43 plainKeys, hashedKeys, updates := builder.Build() 44 if err := ms.applyPlainUpdates(plainKeys, updates); err != nil { 45 t.Fatal(err) 46 } 47 if err := ms2.applyPlainUpdates(plainKeys, updates); err != nil { 48 t.Fatal(err) 49 } 50 51 rootHash, branchNodeUpdates, err := hph.ReviewKeys(plainKeys, hashedKeys) 52 if err != nil { 53 t.Fatal(err) 54 } 55 56 ms.applyBranchNodeUpdates(branchNodeUpdates) 57 if len(rootHash) != 32 { 58 t.Fatalf("invalid root hash length: expected 32 bytes, got %v", len(rootHash)) 59 } 60 61 rootHashAnother, branchNodeUpdates, err := hphAnother.ReviewKeys(plainKeys, hashedKeys) 62 if err != nil { 63 t.Fatal(err) 64 } 65 ms2.applyBranchNodeUpdates(branchNodeUpdates) 66 67 if len(rootHashAnother) > 32 { 68 t.Fatalf("invalid root hash length: expected 32 bytes, got %v", len(rootHash)) 69 } 70 if !bytes.Equal(rootHash, rootHashAnother) { 71 t.Fatalf("invalid second root hash with same updates: [%v] != [%v]", hex.EncodeToString(rootHash), hex.EncodeToString(rootHashAnother)) 72 } 73 }) 74 } 75 76 // go test -trimpath -v -fuzz=Fuzz_ProcessUpdates_ArbitraryUpdateCount -fuzztime=300s ./commitment 77 78 func Fuzz_ProcessUpdates_ArbitraryUpdateCount(f *testing.F) { 79 ha, _ := hex.DecodeString("0008852883b2850c7a48f4b0eea3ccc4c04e6cb6025e9e8f7db2589c7dae81517c514790cfd6f668903161349e") 80 81 f.Add(ha) 82 83 f.Fuzz(func(t *testing.T, build []byte) { 84 if len(build) < 12 { 85 t.Skip() 86 } 87 i := 0 88 keysCount := binary.BigEndian.Uint32(build[i : i+4]) 89 i += 4 90 ks := binary.BigEndian.Uint32(build[i : i+4]) 91 keysSeed := rand.New(rand.NewSource(int64(ks))) 92 i += 4 93 us := binary.BigEndian.Uint32(build[i : i+4]) 94 updateSeed := rand.New(rand.NewSource(int64(us))) 95 96 t.Logf("fuzzing %d keys keysSeed=%d updateSeed=%d", keysCount, ks, us) 97 98 builder := NewUpdateBuilder() 99 for k := uint32(0); k < keysCount; k++ { 100 var key [length.Addr]byte 101 n, err := keysSeed.Read(key[:]) 102 pkey := hex.EncodeToString(key[:]) 103 require.NoError(t, err) 104 require.EqualValues(t, length.Addr, n) 105 106 aux := make([]byte, 32) 107 108 flg := UpdateFlags(updateSeed.Intn(int(CodeUpdate | DeleteUpdate | StorageUpdate | NonceUpdate | BalanceUpdate))) 109 switch { 110 case flg&BalanceUpdate != 0: 111 builder.Balance(pkey, updateSeed.Uint64()).Nonce(pkey, updateSeed.Uint64()) 112 continue 113 case flg&CodeUpdate != 0: 114 keccak := sha3.NewLegacyKeccak256().(keccakState) 115 var s [8]byte 116 n, err := updateSeed.Read(s[:]) 117 require.NoError(t, err) 118 require.EqualValues(t, len(s), n) 119 keccak.Write(s[:]) 120 keccak.Read(aux) 121 122 builder.CodeHash(pkey, hex.EncodeToString(aux)) 123 continue 124 case flg&StorageUpdate != 0: 125 sz := updateSeed.Intn(length.Hash) 126 n, err = updateSeed.Read(aux[:sz]) 127 require.NoError(t, err) 128 require.EqualValues(t, sz, n) 129 130 loc := make([]byte, updateSeed.Intn(length.Hash-1)+1) 131 keysSeed.Read(loc) 132 builder.Storage(pkey, hex.EncodeToString(loc), hex.EncodeToString(aux[:sz])) 133 continue 134 case flg&DeleteUpdate != 0: 135 continue 136 default: 137 continue 138 } 139 } 140 141 ms := NewMockState(t) 142 ms2 := NewMockState(t) 143 hph := NewHexPatriciaHashed(20, ms.branchFn, ms.accountFn, ms.storageFn) 144 hphAnother := NewHexPatriciaHashed(20, ms2.branchFn, ms2.accountFn, ms2.storageFn) 145 146 plainKeys, hashedKeys, updates := builder.Build() 147 148 hph.SetTrace(false) 149 hphAnother.SetTrace(false) 150 151 err := ms.applyPlainUpdates(plainKeys, updates) 152 require.NoError(t, err) 153 154 rootHashReview, branchNodeUpdates, err := hph.ReviewKeys(plainKeys, hashedKeys) 155 require.NoError(t, err) 156 157 ms.applyBranchNodeUpdates(branchNodeUpdates) 158 require.Len(t, rootHashReview, length.Hash, "invalid root hash length") 159 160 err = ms2.applyPlainUpdates(plainKeys, updates) 161 require.NoError(t, err) 162 163 rootHashAnother, branchUpdatesAnother, err := hphAnother.ReviewKeys(plainKeys, hashedKeys) 164 require.NoError(t, err) 165 ms2.applyBranchNodeUpdates(branchUpdatesAnother) 166 167 require.Len(t, rootHashAnother, length.Hash, "invalid root hash length") 168 require.EqualValues(t, rootHashReview, rootHashAnother, "storage-based and update-based rootHash mismatch") 169 }) 170 } 171 172 func Fuzz_HexPatriciaHashed_ReviewKeys(f *testing.F) { 173 var ( 174 keysCount uint64 = 100 175 seed int64 = 1234123415 176 ) 177 178 f.Add(keysCount, seed) 179 180 f.Fuzz(func(t *testing.T, keysCount uint64, seed int64) { 181 if keysCount > 10e9 { 182 return 183 } 184 185 rnd := rand.New(rand.NewSource(seed)) 186 builder := NewUpdateBuilder() 187 188 // generate updates 189 for i := 0; i < int(keysCount); i++ { 190 key := make([]byte, length.Addr) 191 192 for j := 0; j < len(key); j++ { 193 key[j] = byte(rnd.Intn(256)) 194 } 195 builder.Balance(hex.EncodeToString(key), rnd.Uint64()) 196 } 197 198 ms := NewMockState(t) 199 hph := NewHexPatriciaHashed(length.Addr, ms.branchFn, ms.accountFn, ms.storageFn) 200 201 hph.SetTrace(false) 202 203 plainKeys, hashedKeys, updates := builder.Build() 204 if err := ms.applyPlainUpdates(plainKeys, updates); err != nil { 205 t.Fatal(err) 206 } 207 208 rootHash, branchNodeUpdates, err := hph.ReviewKeys(plainKeys, hashedKeys) 209 require.NoError(t, err) 210 211 ms.applyBranchNodeUpdates(branchNodeUpdates) 212 require.Lenf(t, rootHash, length.Hash, "invalid root hash length") 213 }) 214 }