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