github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/core/state/statedb_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "fmt" 23 "math" 24 "math/big" 25 "math/rand" 26 "reflect" 27 "strings" 28 "sync" 29 "testing" 30 "testing/quick" 31 32 "github.com/tirogen/go-ethereum/common" 33 "github.com/tirogen/go-ethereum/core/rawdb" 34 "github.com/tirogen/go-ethereum/core/types" 35 ) 36 37 // Tests that updating a state trie does not leak any database writes prior to 38 // actually committing the state. 39 func TestUpdateLeaks(t *testing.T) { 40 // Create an empty state database 41 db := rawdb.NewMemoryDatabase() 42 state, _ := New(common.Hash{}, NewDatabase(db), nil) 43 44 // Update it with some accounts 45 for i := byte(0); i < 255; i++ { 46 addr := common.BytesToAddress([]byte{i}) 47 state.AddBalance(addr, big.NewInt(int64(11*i))) 48 state.SetNonce(addr, uint64(42*i)) 49 if i%2 == 0 { 50 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 51 } 52 if i%3 == 0 { 53 state.SetCode(addr, []byte{i, i, i, i, i}) 54 } 55 } 56 57 root := state.IntermediateRoot(false) 58 if err := state.Database().TrieDB().Commit(root, false, nil); err != nil { 59 t.Errorf("can not commit trie %v to persistent database", root.Hex()) 60 } 61 62 // Ensure that no data was leaked into the database 63 it := db.NewIterator(nil, nil) 64 for it.Next() { 65 t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) 66 } 67 it.Release() 68 } 69 70 // Tests that no intermediate state of an object is stored into the database, 71 // only the one right before the commit. 72 func TestIntermediateLeaks(t *testing.T) { 73 // Create two state databases, one transitioning to the final state, the other final from the beginning 74 transDb := rawdb.NewMemoryDatabase() 75 finalDb := rawdb.NewMemoryDatabase() 76 transState, _ := New(common.Hash{}, NewDatabase(transDb), nil) 77 finalState, _ := New(common.Hash{}, NewDatabase(finalDb), nil) 78 79 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 80 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 81 state.SetNonce(addr, uint64(42*i+tweak)) 82 if i%2 == 0 { 83 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 84 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 85 } 86 if i%3 == 0 { 87 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 88 } 89 } 90 91 // Modify the transient state. 92 for i := byte(0); i < 255; i++ { 93 modify(transState, common.Address{i}, i, 0) 94 } 95 // Write modifications to trie. 96 transState.IntermediateRoot(false) 97 98 // Overwrite all the data with new values in the transient database. 99 for i := byte(0); i < 255; i++ { 100 modify(transState, common.Address{i}, i, 99) 101 modify(finalState, common.Address{i}, i, 99) 102 } 103 104 // Commit and cross check the databases. 105 transRoot, err := transState.Commit(false) 106 if err != nil { 107 t.Fatalf("failed to commit transition state: %v", err) 108 } 109 if err = transState.Database().TrieDB().Commit(transRoot, false, nil); err != nil { 110 t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) 111 } 112 113 finalRoot, err := finalState.Commit(false) 114 if err != nil { 115 t.Fatalf("failed to commit final state: %v", err) 116 } 117 if err = finalState.Database().TrieDB().Commit(finalRoot, false, nil); err != nil { 118 t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) 119 } 120 121 it := finalDb.NewIterator(nil, nil) 122 for it.Next() { 123 key, fvalue := it.Key(), it.Value() 124 tvalue, err := transDb.Get(key) 125 if err != nil { 126 t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue) 127 } 128 if !bytes.Equal(fvalue, tvalue) { 129 t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) 130 } 131 } 132 it.Release() 133 134 it = transDb.NewIterator(nil, nil) 135 for it.Next() { 136 key, tvalue := it.Key(), it.Value() 137 fvalue, err := finalDb.Get(key) 138 if err != nil { 139 t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) 140 } 141 if !bytes.Equal(fvalue, tvalue) { 142 t.Errorf("value mismatch at key %x: %x in transition database, %x in final database", key, tvalue, fvalue) 143 } 144 } 145 } 146 147 // TestCopy tests that copying a StateDB object indeed makes the original and 148 // the copy independent of each other. This test is a regression test against 149 // https://github.com/tirogen/go-ethereum/pull/15549. 150 func TestCopy(t *testing.T) { 151 // Create a random state test to copy and modify "independently" 152 orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 153 154 for i := byte(0); i < 255; i++ { 155 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 156 obj.AddBalance(big.NewInt(int64(i))) 157 orig.updateStateObject(obj) 158 } 159 orig.Finalise(false) 160 161 // Copy the state 162 copy := orig.Copy() 163 164 // Copy the copy state 165 ccopy := copy.Copy() 166 167 // modify all in memory 168 for i := byte(0); i < 255; i++ { 169 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 170 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 171 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 172 173 origObj.AddBalance(big.NewInt(2 * int64(i))) 174 copyObj.AddBalance(big.NewInt(3 * int64(i))) 175 ccopyObj.AddBalance(big.NewInt(4 * int64(i))) 176 177 orig.updateStateObject(origObj) 178 copy.updateStateObject(copyObj) 179 ccopy.updateStateObject(copyObj) 180 } 181 182 // Finalise the changes on all concurrently 183 finalise := func(wg *sync.WaitGroup, db *StateDB) { 184 defer wg.Done() 185 db.Finalise(true) 186 } 187 188 var wg sync.WaitGroup 189 wg.Add(3) 190 go finalise(&wg, orig) 191 go finalise(&wg, copy) 192 go finalise(&wg, ccopy) 193 wg.Wait() 194 195 // Verify that the three states have been updated independently 196 for i := byte(0); i < 255; i++ { 197 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 198 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 199 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 200 201 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 202 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 203 } 204 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 205 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 206 } 207 if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 { 208 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want) 209 } 210 } 211 } 212 213 func TestSnapshotRandom(t *testing.T) { 214 config := &quick.Config{MaxCount: 1000} 215 err := quick.Check((*snapshotTest).run, config) 216 if cerr, ok := err.(*quick.CheckError); ok { 217 test := cerr.In[0].(*snapshotTest) 218 t.Errorf("%v:\n%s", test.err, test) 219 } else if err != nil { 220 t.Error(err) 221 } 222 } 223 224 // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes 225 // captured by the snapshot. Instances of this test with pseudorandom content are created 226 // by Generate. 227 // 228 // The test works as follows: 229 // 230 // A new state is created and all actions are applied to it. Several snapshots are taken 231 // in between actions. The test then reverts each snapshot. For each snapshot the actions 232 // leading up to it are replayed on a fresh, empty state. The behaviour of all public 233 // accessor methods on the reverted state must match the return value of the equivalent 234 // methods on the replayed state. 235 type snapshotTest struct { 236 addrs []common.Address // all account addresses 237 actions []testAction // modifications to the state 238 snapshots []int // actions indexes at which snapshot is taken 239 err error // failure details are reported through this field 240 } 241 242 type testAction struct { 243 name string 244 fn func(testAction, *StateDB) 245 args []int64 246 noAddr bool 247 } 248 249 // newTestAction creates a random action that changes state. 250 func newTestAction(addr common.Address, r *rand.Rand) testAction { 251 actions := []testAction{ 252 { 253 name: "SetBalance", 254 fn: func(a testAction, s *StateDB) { 255 s.SetBalance(addr, big.NewInt(a.args[0])) 256 }, 257 args: make([]int64, 1), 258 }, 259 { 260 name: "AddBalance", 261 fn: func(a testAction, s *StateDB) { 262 s.AddBalance(addr, big.NewInt(a.args[0])) 263 }, 264 args: make([]int64, 1), 265 }, 266 { 267 name: "SetNonce", 268 fn: func(a testAction, s *StateDB) { 269 s.SetNonce(addr, uint64(a.args[0])) 270 }, 271 args: make([]int64, 1), 272 }, 273 { 274 name: "SetState", 275 fn: func(a testAction, s *StateDB) { 276 var key, val common.Hash 277 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 278 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 279 s.SetState(addr, key, val) 280 }, 281 args: make([]int64, 2), 282 }, 283 { 284 name: "SetCode", 285 fn: func(a testAction, s *StateDB) { 286 code := make([]byte, 16) 287 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 288 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 289 s.SetCode(addr, code) 290 }, 291 args: make([]int64, 2), 292 }, 293 { 294 name: "CreateAccount", 295 fn: func(a testAction, s *StateDB) { 296 s.CreateAccount(addr) 297 }, 298 }, 299 { 300 name: "Suicide", 301 fn: func(a testAction, s *StateDB) { 302 s.Suicide(addr) 303 }, 304 }, 305 { 306 name: "AddRefund", 307 fn: func(a testAction, s *StateDB) { 308 s.AddRefund(uint64(a.args[0])) 309 }, 310 args: make([]int64, 1), 311 noAddr: true, 312 }, 313 { 314 name: "AddLog", 315 fn: func(a testAction, s *StateDB) { 316 data := make([]byte, 2) 317 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 318 s.AddLog(&types.Log{Address: addr, Data: data}) 319 }, 320 args: make([]int64, 1), 321 }, 322 { 323 name: "AddPreimage", 324 fn: func(a testAction, s *StateDB) { 325 preimage := []byte{1} 326 hash := common.BytesToHash(preimage) 327 s.AddPreimage(hash, preimage) 328 }, 329 args: make([]int64, 1), 330 }, 331 { 332 name: "AddAddressToAccessList", 333 fn: func(a testAction, s *StateDB) { 334 s.AddAddressToAccessList(addr) 335 }, 336 }, 337 { 338 name: "AddSlotToAccessList", 339 fn: func(a testAction, s *StateDB) { 340 s.AddSlotToAccessList(addr, 341 common.Hash{byte(a.args[0])}) 342 }, 343 args: make([]int64, 1), 344 }, 345 { 346 name: "SetTransientState", 347 fn: func(a testAction, s *StateDB) { 348 var key, val common.Hash 349 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 350 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 351 s.SetTransientState(addr, key, val) 352 }, 353 args: make([]int64, 2), 354 }, 355 } 356 action := actions[r.Intn(len(actions))] 357 var nameargs []string 358 if !action.noAddr { 359 nameargs = append(nameargs, addr.Hex()) 360 } 361 for i := range action.args { 362 action.args[i] = rand.Int63n(100) 363 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 364 } 365 action.name += strings.Join(nameargs, ", ") 366 return action 367 } 368 369 // Generate returns a new snapshot test of the given size. All randomness is 370 // derived from r. 371 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 372 // Generate random actions. 373 addrs := make([]common.Address, 50) 374 for i := range addrs { 375 addrs[i][0] = byte(i) 376 } 377 actions := make([]testAction, size) 378 for i := range actions { 379 addr := addrs[r.Intn(len(addrs))] 380 actions[i] = newTestAction(addr, r) 381 } 382 // Generate snapshot indexes. 383 nsnapshots := int(math.Sqrt(float64(size))) 384 if size > 0 && nsnapshots == 0 { 385 nsnapshots = 1 386 } 387 snapshots := make([]int, nsnapshots) 388 snaplen := len(actions) / nsnapshots 389 for i := range snapshots { 390 // Try to place the snapshots some number of actions apart from each other. 391 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 392 } 393 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 394 } 395 396 func (test *snapshotTest) String() string { 397 out := new(bytes.Buffer) 398 sindex := 0 399 for i, action := range test.actions { 400 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 401 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 402 sindex++ 403 } 404 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 405 } 406 return out.String() 407 } 408 409 func (test *snapshotTest) run() bool { 410 // Run all actions and create snapshots. 411 var ( 412 state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 413 snapshotRevs = make([]int, len(test.snapshots)) 414 sindex = 0 415 ) 416 for i, action := range test.actions { 417 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 418 snapshotRevs[sindex] = state.Snapshot() 419 sindex++ 420 } 421 action.fn(action, state) 422 } 423 // Revert all snapshots in reverse order. Each revert must yield a state 424 // that is equivalent to fresh state with all actions up the snapshot applied. 425 for sindex--; sindex >= 0; sindex-- { 426 checkstate, _ := New(common.Hash{}, state.Database(), nil) 427 for _, action := range test.actions[:test.snapshots[sindex]] { 428 action.fn(action, checkstate) 429 } 430 state.RevertToSnapshot(snapshotRevs[sindex]) 431 if err := test.checkEqual(state, checkstate); err != nil { 432 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 433 return false 434 } 435 } 436 return true 437 } 438 439 // checkEqual checks that methods of state and checkstate return the same values. 440 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 441 for _, addr := range test.addrs { 442 var err error 443 checkeq := func(op string, a, b interface{}) bool { 444 if err == nil && !reflect.DeepEqual(a, b) { 445 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 446 return false 447 } 448 return true 449 } 450 // Check basic accessor methods. 451 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 452 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 453 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 454 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 455 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 456 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 457 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 458 // Check storage. 459 if obj := state.getStateObject(addr); obj != nil { 460 state.ForEachStorage(addr, func(key, value common.Hash) bool { 461 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 462 }) 463 checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { 464 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 465 }) 466 } 467 if err != nil { 468 return err 469 } 470 } 471 472 if state.GetRefund() != checkstate.GetRefund() { 473 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 474 state.GetRefund(), checkstate.GetRefund()) 475 } 476 if !reflect.DeepEqual(state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) { 477 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 478 state.GetLogs(common.Hash{}, 0, common.Hash{}), checkstate.GetLogs(common.Hash{}, 0, common.Hash{})) 479 } 480 return nil 481 } 482 483 func TestTouchDelete(t *testing.T) { 484 s := newStateTest() 485 s.state.GetOrNewStateObject(common.Address{}) 486 root, _ := s.state.Commit(false) 487 s.state, _ = New(root, s.state.db, s.state.snaps) 488 489 snapshot := s.state.Snapshot() 490 s.state.AddBalance(common.Address{}, new(big.Int)) 491 492 if len(s.state.journal.dirties) != 1 { 493 t.Fatal("expected one dirty state object") 494 } 495 s.state.RevertToSnapshot(snapshot) 496 if len(s.state.journal.dirties) != 0 { 497 t.Fatal("expected no dirty state object") 498 } 499 } 500 501 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 502 // See https://github.com/tirogen/go-ethereum/pull/15225#issuecomment-380191512 503 func TestCopyOfCopy(t *testing.T) { 504 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 505 addr := common.HexToAddress("aaaa") 506 state.SetBalance(addr, big.NewInt(42)) 507 508 if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { 509 t.Fatalf("1st copy fail, expected 42, got %v", got) 510 } 511 if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 512 t.Fatalf("2nd copy fail, expected 42, got %v", got) 513 } 514 } 515 516 // Tests a regression where committing a copy lost some internal meta information, 517 // leading to corrupted subsequent copies. 518 // 519 // See https://github.com/tirogen/go-ethereum/issues/20106. 520 func TestCopyCommitCopy(t *testing.T) { 521 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 522 523 // Create an account and check if the retrieved balance is correct 524 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 525 skey := common.HexToHash("aaa") 526 sval := common.HexToHash("bbb") 527 528 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 529 state.SetCode(addr, []byte("hello")) // Change an external metadata 530 state.SetState(addr, skey, sval) // Change the storage trie 531 532 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 533 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 534 } 535 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 536 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 537 } 538 if val := state.GetState(addr, skey); val != sval { 539 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 540 } 541 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 542 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 543 } 544 // Copy the non-committed state database and check pre/post commit balance 545 copyOne := state.Copy() 546 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 547 t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) 548 } 549 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 550 t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 551 } 552 if val := copyOne.GetState(addr, skey); val != sval { 553 t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 554 } 555 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 556 t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 557 } 558 559 copyOne.Commit(false) 560 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 561 t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42) 562 } 563 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 564 t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) 565 } 566 if val := copyOne.GetState(addr, skey); val != sval { 567 t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 568 } 569 if val := copyOne.GetCommittedState(addr, skey); val != sval { 570 t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 571 } 572 // Copy the copy and check the balance once more 573 copyTwo := copyOne.Copy() 574 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 575 t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) 576 } 577 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 578 t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) 579 } 580 if val := copyTwo.GetState(addr, skey); val != sval { 581 t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) 582 } 583 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 584 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 585 } 586 } 587 588 // Tests a regression where committing a copy lost some internal meta information, 589 // leading to corrupted subsequent copies. 590 // 591 // See https://github.com/tirogen/go-ethereum/issues/20106. 592 func TestCopyCopyCommitCopy(t *testing.T) { 593 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 594 595 // Create an account and check if the retrieved balance is correct 596 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 597 skey := common.HexToHash("aaa") 598 sval := common.HexToHash("bbb") 599 600 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 601 state.SetCode(addr, []byte("hello")) // Change an external metadata 602 state.SetState(addr, skey, sval) // Change the storage trie 603 604 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 605 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 606 } 607 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 608 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 609 } 610 if val := state.GetState(addr, skey); val != sval { 611 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 612 } 613 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 614 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 615 } 616 // Copy the non-committed state database and check pre/post commit balance 617 copyOne := state.Copy() 618 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 619 t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) 620 } 621 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 622 t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) 623 } 624 if val := copyOne.GetState(addr, skey); val != sval { 625 t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval) 626 } 627 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 628 t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 629 } 630 // Copy the copy and check the balance once more 631 copyTwo := copyOne.Copy() 632 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 633 t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) 634 } 635 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 636 t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 637 } 638 if val := copyTwo.GetState(addr, skey); val != sval { 639 t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 640 } 641 if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { 642 t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 643 } 644 copyTwo.Commit(false) 645 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 646 t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) 647 } 648 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 649 t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) 650 } 651 if val := copyTwo.GetState(addr, skey); val != sval { 652 t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 653 } 654 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 655 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 656 } 657 // Copy the copy-copy and check the balance once more 658 copyThree := copyTwo.Copy() 659 if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 660 t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) 661 } 662 if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 663 t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) 664 } 665 if val := copyThree.GetState(addr, skey); val != sval { 666 t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) 667 } 668 if val := copyThree.GetCommittedState(addr, skey); val != sval { 669 t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) 670 } 671 } 672 673 // TestDeleteCreateRevert tests a weird state transition corner case that we hit 674 // while changing the internals of StateDB. The workflow is that a contract is 675 // self-destructed, then in a follow-up transaction (but same block) it's created 676 // again and the transaction reverted. 677 // 678 // The original StateDB implementation flushed dirty objects to the tries after 679 // each transaction, so this works ok. The rework accumulated writes in memory 680 // first, but the journal wiped the entire state object on create-revert. 681 func TestDeleteCreateRevert(t *testing.T) { 682 // Create an initial state with a single contract 683 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 684 685 addr := common.BytesToAddress([]byte("so")) 686 state.SetBalance(addr, big.NewInt(1)) 687 688 root, _ := state.Commit(false) 689 state, _ = New(root, state.db, state.snaps) 690 691 // Simulate self-destructing in one transaction, then create-reverting in another 692 state.Suicide(addr) 693 state.Finalise(true) 694 695 id := state.Snapshot() 696 state.SetBalance(addr, big.NewInt(2)) 697 state.RevertToSnapshot(id) 698 699 // Commit the entire state and make sure we don't crash and have the correct state 700 root, _ = state.Commit(true) 701 state, _ = New(root, state.db, state.snaps) 702 703 if state.getStateObject(addr) != nil { 704 t.Fatalf("self-destructed contract came alive") 705 } 706 } 707 708 // TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie, 709 // the Commit operation fails with an error 710 // If we are missing trie nodes, we should not continue writing to the trie 711 func TestMissingTrieNodes(t *testing.T) { 712 // Create an initial state with a few accounts 713 memDb := rawdb.NewMemoryDatabase() 714 db := NewDatabase(memDb) 715 var root common.Hash 716 state, _ := New(common.Hash{}, db, nil) 717 addr := common.BytesToAddress([]byte("so")) 718 { 719 state.SetBalance(addr, big.NewInt(1)) 720 state.SetCode(addr, []byte{1, 2, 3}) 721 a2 := common.BytesToAddress([]byte("another")) 722 state.SetBalance(a2, big.NewInt(100)) 723 state.SetCode(a2, []byte{1, 2, 4}) 724 root, _ = state.Commit(false) 725 t.Logf("root: %x", root) 726 // force-flush 727 state.Database().TrieDB().Cap(0) 728 } 729 // Create a new state on the old root 730 state, _ = New(root, db, nil) 731 // Now we clear out the memdb 732 it := memDb.NewIterator(nil, nil) 733 for it.Next() { 734 k := it.Key() 735 // Leave the root intact 736 if !bytes.Equal(k, root[:]) { 737 t.Logf("key: %x", k) 738 memDb.Delete(k) 739 } 740 } 741 balance := state.GetBalance(addr) 742 // The removed elem should lead to it returning zero balance 743 if exp, got := uint64(0), balance.Uint64(); got != exp { 744 t.Errorf("expected %d, got %d", exp, got) 745 } 746 // Modify the state 747 state.SetBalance(addr, big.NewInt(2)) 748 root, err := state.Commit(false) 749 if err == nil { 750 t.Fatalf("expected error, got root :%x", root) 751 } 752 } 753 754 func TestStateDBAccessList(t *testing.T) { 755 // Some helpers 756 addr := func(a string) common.Address { 757 return common.HexToAddress(a) 758 } 759 slot := func(a string) common.Hash { 760 return common.HexToHash(a) 761 } 762 763 memDb := rawdb.NewMemoryDatabase() 764 db := NewDatabase(memDb) 765 state, _ := New(common.Hash{}, db, nil) 766 state.accessList = newAccessList() 767 768 verifyAddrs := func(astrings ...string) { 769 t.Helper() 770 // convert to common.Address form 771 var addresses []common.Address 772 var addressMap = make(map[common.Address]struct{}) 773 for _, astring := range astrings { 774 address := addr(astring) 775 addresses = append(addresses, address) 776 addressMap[address] = struct{}{} 777 } 778 // Check that the given addresses are in the access list 779 for _, address := range addresses { 780 if !state.AddressInAccessList(address) { 781 t.Fatalf("expected %x to be in access list", address) 782 } 783 } 784 // Check that only the expected addresses are present in the access list 785 for address := range state.accessList.addresses { 786 if _, exist := addressMap[address]; !exist { 787 t.Fatalf("extra address %x in access list", address) 788 } 789 } 790 } 791 verifySlots := func(addrString string, slotStrings ...string) { 792 if !state.AddressInAccessList(addr(addrString)) { 793 t.Fatalf("scope missing address/slots %v", addrString) 794 } 795 var address = addr(addrString) 796 // convert to common.Hash form 797 var slots []common.Hash 798 var slotMap = make(map[common.Hash]struct{}) 799 for _, slotString := range slotStrings { 800 s := slot(slotString) 801 slots = append(slots, s) 802 slotMap[s] = struct{}{} 803 } 804 // Check that the expected items are in the access list 805 for i, s := range slots { 806 if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { 807 t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) 808 } 809 } 810 // Check that no extra elements are in the access list 811 index := state.accessList.addresses[address] 812 if index >= 0 { 813 stateSlots := state.accessList.slots[index] 814 for s := range stateSlots { 815 if _, slotPresent := slotMap[s]; !slotPresent { 816 t.Fatalf("scope has extra slot %v (address %v)", s, addrString) 817 } 818 } 819 } 820 } 821 822 state.AddAddressToAccessList(addr("aa")) // 1 823 state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 824 state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 825 verifyAddrs("aa", "bb") 826 verifySlots("bb", "01", "02") 827 828 // Make a copy 829 stateCopy1 := state.Copy() 830 if exp, got := 4, state.journal.length(); exp != got { 831 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 832 } 833 834 // same again, should cause no journal entries 835 state.AddSlotToAccessList(addr("bb"), slot("01")) 836 state.AddSlotToAccessList(addr("bb"), slot("02")) 837 state.AddAddressToAccessList(addr("aa")) 838 if exp, got := 4, state.journal.length(); exp != got { 839 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 840 } 841 // some new ones 842 state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 843 state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 844 state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 845 state.AddAddressToAccessList(addr("cc")) 846 if exp, got := 8, state.journal.length(); exp != got { 847 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 848 } 849 850 verifyAddrs("aa", "bb", "cc") 851 verifySlots("aa", "01") 852 verifySlots("bb", "01", "02", "03") 853 verifySlots("cc", "01") 854 855 // now start rolling back changes 856 state.journal.revert(state, 7) 857 if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { 858 t.Fatalf("slot present, expected missing") 859 } 860 verifyAddrs("aa", "bb", "cc") 861 verifySlots("aa", "01") 862 verifySlots("bb", "01", "02", "03") 863 864 state.journal.revert(state, 6) 865 if state.AddressInAccessList(addr("cc")) { 866 t.Fatalf("addr present, expected missing") 867 } 868 verifyAddrs("aa", "bb") 869 verifySlots("aa", "01") 870 verifySlots("bb", "01", "02", "03") 871 872 state.journal.revert(state, 5) 873 if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { 874 t.Fatalf("slot present, expected missing") 875 } 876 verifyAddrs("aa", "bb") 877 verifySlots("bb", "01", "02", "03") 878 879 state.journal.revert(state, 4) 880 if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { 881 t.Fatalf("slot present, expected missing") 882 } 883 verifyAddrs("aa", "bb") 884 verifySlots("bb", "01", "02") 885 886 state.journal.revert(state, 3) 887 if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { 888 t.Fatalf("slot present, expected missing") 889 } 890 verifyAddrs("aa", "bb") 891 verifySlots("bb", "01") 892 893 state.journal.revert(state, 2) 894 if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { 895 t.Fatalf("slot present, expected missing") 896 } 897 verifyAddrs("aa", "bb") 898 899 state.journal.revert(state, 1) 900 if state.AddressInAccessList(addr("bb")) { 901 t.Fatalf("addr present, expected missing") 902 } 903 verifyAddrs("aa") 904 905 state.journal.revert(state, 0) 906 if state.AddressInAccessList(addr("aa")) { 907 t.Fatalf("addr present, expected missing") 908 } 909 if got, exp := len(state.accessList.addresses), 0; got != exp { 910 t.Fatalf("expected empty, got %d", got) 911 } 912 if got, exp := len(state.accessList.slots), 0; got != exp { 913 t.Fatalf("expected empty, got %d", got) 914 } 915 // Check the copy 916 // Make a copy 917 state = stateCopy1 918 verifyAddrs("aa", "bb") 919 verifySlots("bb", "01", "02") 920 if got, exp := len(state.accessList.addresses), 2; got != exp { 921 t.Fatalf("expected empty, got %d", got) 922 } 923 if got, exp := len(state.accessList.slots), 1; got != exp { 924 t.Fatalf("expected empty, got %d", got) 925 } 926 } 927 928 // Tests that account and storage tries are flushed in the correct order and that 929 // no data loss occurs. 930 func TestFlushOrderDataLoss(t *testing.T) { 931 // Create a state trie with many accounts and slots 932 var ( 933 memdb = rawdb.NewMemoryDatabase() 934 statedb = NewDatabase(memdb) 935 state, _ = New(common.Hash{}, statedb, nil) 936 ) 937 for a := byte(0); a < 10; a++ { 938 state.CreateAccount(common.Address{a}) 939 for s := byte(0); s < 10; s++ { 940 state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) 941 } 942 } 943 root, err := state.Commit(false) 944 if err != nil { 945 t.Fatalf("failed to commit state trie: %v", err) 946 } 947 statedb.TrieDB().Reference(root, common.Hash{}) 948 if err := statedb.TrieDB().Cap(1024); err != nil { 949 t.Fatalf("failed to cap trie dirty cache: %v", err) 950 } 951 if err := statedb.TrieDB().Commit(root, false, nil); err != nil { 952 t.Fatalf("failed to commit state trie: %v", err) 953 } 954 // Reopen the state trie from flushed disk and verify it 955 state, err = New(root, NewDatabase(memdb), nil) 956 if err != nil { 957 t.Fatalf("failed to reopen state trie: %v", err) 958 } 959 for a := byte(0); a < 10; a++ { 960 for s := byte(0); s < 10; s++ { 961 if have := state.GetState(common.Address{a}, common.Hash{a, s}); have != (common.Hash{a, s}) { 962 t.Errorf("account %d: slot %d: state mismatch: have %x, want %x", a, s, have, common.Hash{a, s}) 963 } 964 } 965 } 966 } 967 968 func TestStateDBTransientStorage(t *testing.T) { 969 memDb := rawdb.NewMemoryDatabase() 970 db := NewDatabase(memDb) 971 state, _ := New(common.Hash{}, db, nil) 972 973 key := common.Hash{0x01} 974 value := common.Hash{0x02} 975 addr := common.Address{} 976 977 state.SetTransientState(addr, key, value) 978 if exp, got := 1, state.journal.length(); exp != got { 979 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 980 } 981 // the retrieved value should equal what was set 982 if got := state.GetTransientState(addr, key); got != value { 983 t.Fatalf("transient storage mismatch: have %x, want %x", got, value) 984 } 985 986 // revert the transient state being set and then check that the 987 // value is now the empty hash 988 state.journal.revert(state, 0) 989 if got, exp := state.GetTransientState(addr, key), (common.Hash{}); exp != got { 990 t.Fatalf("transient storage mismatch: have %x, want %x", got, exp) 991 } 992 993 // set transient state and then copy the statedb and ensure that 994 // the transient state is copied 995 state.SetTransientState(addr, key, value) 996 cpy := state.Copy() 997 if got := cpy.GetTransientState(addr, key); got != value { 998 t.Fatalf("transient storage mismatch: have %x, want %x", got, value) 999 } 1000 }