github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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/scroll-tech/go-ethereum/common" 33 "github.com/scroll-tech/go-ethereum/core/rawdb" 34 "github.com/scroll-tech/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/scroll-tech/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 action := actions[r.Intn(len(actions))] 347 var nameargs []string 348 if !action.noAddr { 349 nameargs = append(nameargs, addr.Hex()) 350 } 351 for i := range action.args { 352 action.args[i] = rand.Int63n(100) 353 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 354 } 355 action.name += strings.Join(nameargs, ", ") 356 return action 357 } 358 359 // Generate returns a new snapshot test of the given size. All randomness is 360 // derived from r. 361 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 362 // Generate random actions. 363 addrs := make([]common.Address, 50) 364 for i := range addrs { 365 addrs[i][0] = byte(i) 366 } 367 actions := make([]testAction, size) 368 for i := range actions { 369 addr := addrs[r.Intn(len(addrs))] 370 actions[i] = newTestAction(addr, r) 371 } 372 // Generate snapshot indexes. 373 nsnapshots := int(math.Sqrt(float64(size))) 374 if size > 0 && nsnapshots == 0 { 375 nsnapshots = 1 376 } 377 snapshots := make([]int, nsnapshots) 378 snaplen := len(actions) / nsnapshots 379 for i := range snapshots { 380 // Try to place the snapshots some number of actions apart from each other. 381 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 382 } 383 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 384 } 385 386 func (test *snapshotTest) String() string { 387 out := new(bytes.Buffer) 388 sindex := 0 389 for i, action := range test.actions { 390 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 391 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 392 sindex++ 393 } 394 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 395 } 396 return out.String() 397 } 398 399 func (test *snapshotTest) run() bool { 400 // Run all actions and create snapshots. 401 var ( 402 state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 403 snapshotRevs = make([]int, len(test.snapshots)) 404 sindex = 0 405 ) 406 for i, action := range test.actions { 407 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 408 snapshotRevs[sindex] = state.Snapshot() 409 sindex++ 410 } 411 action.fn(action, state) 412 } 413 // Revert all snapshots in reverse order. Each revert must yield a state 414 // that is equivalent to fresh state with all actions up the snapshot applied. 415 for sindex--; sindex >= 0; sindex-- { 416 checkstate, _ := New(common.Hash{}, state.Database(), nil) 417 for _, action := range test.actions[:test.snapshots[sindex]] { 418 action.fn(action, checkstate) 419 } 420 state.RevertToSnapshot(snapshotRevs[sindex]) 421 if err := test.checkEqual(state, checkstate); err != nil { 422 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 423 return false 424 } 425 } 426 return true 427 } 428 429 // checkEqual checks that methods of state and checkstate return the same values. 430 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 431 for _, addr := range test.addrs { 432 var err error 433 checkeq := func(op string, a, b interface{}) bool { 434 if err == nil && !reflect.DeepEqual(a, b) { 435 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 436 return false 437 } 438 return true 439 } 440 // Check basic accessor methods. 441 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 442 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 443 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 444 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 445 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 446 checkeq("GetKeccakCodeHash", state.GetKeccakCodeHash(addr), checkstate.GetKeccakCodeHash(addr)) 447 checkeq("GetPoseidonCodeHash", state.GetPoseidonCodeHash(addr), checkstate.GetPoseidonCodeHash(addr)) 448 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 449 // Check storage. 450 if obj := state.getStateObject(addr); obj != nil { 451 state.ForEachStorage(addr, func(key, value common.Hash) bool { 452 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 453 }) 454 checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { 455 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 456 }) 457 } 458 if err != nil { 459 return err 460 } 461 } 462 463 if state.GetRefund() != checkstate.GetRefund() { 464 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 465 state.GetRefund(), checkstate.GetRefund()) 466 } 467 if !reflect.DeepEqual(state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{})) { 468 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 469 state.GetLogs(common.Hash{}, common.Hash{}), checkstate.GetLogs(common.Hash{}, common.Hash{})) 470 } 471 return nil 472 } 473 474 func TestTouchDelete(t *testing.T) { 475 s := newStateTest() 476 s.state.GetOrNewStateObject(common.Address{}) 477 root, _ := s.state.Commit(false) 478 s.state, _ = New(root, s.state.db, s.state.snaps) 479 480 snapshot := s.state.Snapshot() 481 s.state.AddBalance(common.Address{}, new(big.Int)) 482 483 if len(s.state.journal.dirties) != 1 { 484 t.Fatal("expected one dirty state object") 485 } 486 s.state.RevertToSnapshot(snapshot) 487 if len(s.state.journal.dirties) != 0 { 488 t.Fatal("expected no dirty state object") 489 } 490 } 491 492 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 493 // See https://github.com/scroll-tech/go-ethereum/pull/15225#issuecomment-380191512 494 func TestCopyOfCopy(t *testing.T) { 495 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 496 addr := common.HexToAddress("aaaa") 497 state.SetBalance(addr, big.NewInt(42)) 498 499 if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { 500 t.Fatalf("1st copy fail, expected 42, got %v", got) 501 } 502 if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 503 t.Fatalf("2nd copy fail, expected 42, got %v", got) 504 } 505 } 506 507 // Tests a regression where committing a copy lost some internal meta information, 508 // leading to corrupted subsequent copies. 509 // 510 // See https://github.com/scroll-tech/go-ethereum/issues/20106. 511 func TestCopyCommitCopy(t *testing.T) { 512 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 513 514 // Create an account and check if the retrieved balance is correct 515 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 516 skey := common.HexToHash("aaa") 517 sval := common.HexToHash("bbb") 518 519 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 520 state.SetCode(addr, []byte("hello")) // Change an external metadata 521 state.SetState(addr, skey, sval) // Change the storage trie 522 523 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 524 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 525 } 526 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 527 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 528 } 529 if val := state.GetState(addr, skey); val != sval { 530 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 531 } 532 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 533 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 534 } 535 // Copy the non-committed state database and check pre/post commit balance 536 copyOne := state.Copy() 537 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 538 t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) 539 } 540 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 541 t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 542 } 543 if val := copyOne.GetState(addr, skey); val != sval { 544 t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 545 } 546 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 547 t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 548 } 549 550 copyOne.Commit(false) 551 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 552 t.Fatalf("first copy post-commit balance mismatch: have %v, want %v", balance, 42) 553 } 554 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 555 t.Fatalf("first copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) 556 } 557 if val := copyOne.GetState(addr, skey); val != sval { 558 t.Fatalf("first copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 559 } 560 if val := copyOne.GetCommittedState(addr, skey); val != sval { 561 t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 562 } 563 // Copy the copy and check the balance once more 564 copyTwo := copyOne.Copy() 565 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 566 t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) 567 } 568 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 569 t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) 570 } 571 if val := copyTwo.GetState(addr, skey); val != sval { 572 t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) 573 } 574 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 575 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 576 } 577 } 578 579 // Tests a regression where committing a copy lost some internal meta information, 580 // leading to corrupted subsequent copies. 581 // 582 // See https://github.com/scroll-tech/go-ethereum/issues/20106. 583 func TestCopyCopyCommitCopy(t *testing.T) { 584 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 585 586 // Create an account and check if the retrieved balance is correct 587 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 588 skey := common.HexToHash("aaa") 589 sval := common.HexToHash("bbb") 590 591 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 592 state.SetCode(addr, []byte("hello")) // Change an external metadata 593 state.SetState(addr, skey, sval) // Change the storage trie 594 595 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 596 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 597 } 598 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 599 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 600 } 601 if val := state.GetState(addr, skey); val != sval { 602 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 603 } 604 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 605 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 606 } 607 // Copy the non-committed state database and check pre/post commit balance 608 copyOne := state.Copy() 609 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 610 t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) 611 } 612 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 613 t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) 614 } 615 if val := copyOne.GetState(addr, skey); val != sval { 616 t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval) 617 } 618 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 619 t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 620 } 621 // Copy the copy and check the balance once more 622 copyTwo := copyOne.Copy() 623 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 624 t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) 625 } 626 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 627 t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 628 } 629 if val := copyTwo.GetState(addr, skey); val != sval { 630 t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 631 } 632 if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { 633 t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 634 } 635 copyTwo.Commit(false) 636 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 637 t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) 638 } 639 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 640 t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) 641 } 642 if val := copyTwo.GetState(addr, skey); val != sval { 643 t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 644 } 645 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 646 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 647 } 648 // Copy the copy-copy and check the balance once more 649 copyThree := copyTwo.Copy() 650 if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 651 t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) 652 } 653 if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 654 t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) 655 } 656 if val := copyThree.GetState(addr, skey); val != sval { 657 t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) 658 } 659 if val := copyThree.GetCommittedState(addr, skey); val != sval { 660 t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) 661 } 662 } 663 664 // TestDeleteCreateRevert tests a weird state transition corner case that we hit 665 // while changing the internals of StateDB. The workflow is that a contract is 666 // self-destructed, then in a follow-up transaction (but same block) it's created 667 // again and the transaction reverted. 668 // 669 // The original StateDB implementation flushed dirty objects to the tries after 670 // each transaction, so this works ok. The rework accumulated writes in memory 671 // first, but the journal wiped the entire state object on create-revert. 672 func TestDeleteCreateRevert(t *testing.T) { 673 // Create an initial state with a single contract 674 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil) 675 676 addr := common.BytesToAddress([]byte("so")) 677 state.SetBalance(addr, big.NewInt(1)) 678 679 root, _ := state.Commit(false) 680 state, _ = New(root, state.db, state.snaps) 681 682 // Simulate self-destructing in one transaction, then create-reverting in another 683 state.Suicide(addr) 684 state.Finalise(true) 685 686 id := state.Snapshot() 687 state.SetBalance(addr, big.NewInt(2)) 688 state.RevertToSnapshot(id) 689 690 // Commit the entire state and make sure we don't crash and have the correct state 691 root, _ = state.Commit(true) 692 state, _ = New(root, state.db, state.snaps) 693 694 if state.getStateObject(addr) != nil { 695 t.Fatalf("self-destructed contract came alive") 696 } 697 } 698 699 // TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie, 700 // the Commit operation fails with an error 701 // If we are missing trie nodes, we should not continue writing to the trie 702 func TestMissingTrieNodes(t *testing.T) { 703 704 // Create an initial state with a few accounts 705 memDb := rawdb.NewMemoryDatabase() 706 db := NewDatabase(memDb) 707 var root common.Hash 708 state, _ := New(common.Hash{}, db, nil) 709 addr := common.BytesToAddress([]byte("so")) 710 { 711 state.SetBalance(addr, big.NewInt(1)) 712 state.SetCode(addr, []byte{1, 2, 3}) 713 a2 := common.BytesToAddress([]byte("another")) 714 state.SetBalance(a2, big.NewInt(100)) 715 state.SetCode(a2, []byte{1, 2, 4}) 716 root, _ = state.Commit(false) 717 t.Logf("root: %x", root) 718 // force-flush 719 state.Database().TrieDB().Cap(0) 720 } 721 // Create a new state on the old root 722 state, _ = New(root, db, nil) 723 // Now we clear out the memdb 724 it := memDb.NewIterator(nil, nil) 725 for it.Next() { 726 k := it.Key() 727 // Leave the root intact 728 if !bytes.Equal(k, root[:]) { 729 t.Logf("key: %x", k) 730 memDb.Delete(k) 731 } 732 } 733 balance := state.GetBalance(addr) 734 // The removed elem should lead to it returning zero balance 735 if exp, got := uint64(0), balance.Uint64(); got != exp { 736 t.Errorf("expected %d, got %d", exp, got) 737 } 738 // Modify the state 739 state.SetBalance(addr, big.NewInt(2)) 740 root, err := state.Commit(false) 741 if err == nil { 742 t.Fatalf("expected error, got root :%x", root) 743 } 744 } 745 746 func TestStateDBAccessList(t *testing.T) { 747 // Some helpers 748 addr := func(a string) common.Address { 749 return common.HexToAddress(a) 750 } 751 slot := func(a string) common.Hash { 752 return common.HexToHash(a) 753 } 754 755 memDb := rawdb.NewMemoryDatabase() 756 db := NewDatabase(memDb) 757 state, _ := New(common.Hash{}, db, nil) 758 state.accessList = newAccessList() 759 760 verifyAddrs := func(astrings ...string) { 761 t.Helper() 762 // convert to common.Address form 763 var addresses []common.Address 764 var addressMap = make(map[common.Address]struct{}) 765 for _, astring := range astrings { 766 address := addr(astring) 767 addresses = append(addresses, address) 768 addressMap[address] = struct{}{} 769 } 770 // Check that the given addresses are in the access list 771 for _, address := range addresses { 772 if !state.AddressInAccessList(address) { 773 t.Fatalf("expected %x to be in access list", address) 774 } 775 } 776 // Check that only the expected addresses are present in the acesslist 777 for address := range state.accessList.addresses { 778 if _, exist := addressMap[address]; !exist { 779 t.Fatalf("extra address %x in access list", address) 780 } 781 } 782 } 783 verifySlots := func(addrString string, slotStrings ...string) { 784 if !state.AddressInAccessList(addr(addrString)) { 785 t.Fatalf("scope missing address/slots %v", addrString) 786 } 787 var address = addr(addrString) 788 // convert to common.Hash form 789 var slots []common.Hash 790 var slotMap = make(map[common.Hash]struct{}) 791 for _, slotString := range slotStrings { 792 s := slot(slotString) 793 slots = append(slots, s) 794 slotMap[s] = struct{}{} 795 } 796 // Check that the expected items are in the access list 797 for i, s := range slots { 798 if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { 799 t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) 800 } 801 } 802 // Check that no extra elements are in the access list 803 index := state.accessList.addresses[address] 804 if index >= 0 { 805 stateSlots := state.accessList.slots[index] 806 for s := range stateSlots { 807 if _, slotPresent := slotMap[s]; !slotPresent { 808 t.Fatalf("scope has extra slot %v (address %v)", s, addrString) 809 } 810 } 811 } 812 } 813 814 state.AddAddressToAccessList(addr("aa")) // 1 815 state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 816 state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 817 verifyAddrs("aa", "bb") 818 verifySlots("bb", "01", "02") 819 820 // Make a copy 821 stateCopy1 := state.Copy() 822 if exp, got := 4, state.journal.length(); exp != got { 823 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 824 } 825 826 // same again, should cause no journal entries 827 state.AddSlotToAccessList(addr("bb"), slot("01")) 828 state.AddSlotToAccessList(addr("bb"), slot("02")) 829 state.AddAddressToAccessList(addr("aa")) 830 if exp, got := 4, state.journal.length(); exp != got { 831 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 832 } 833 // some new ones 834 state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 835 state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 836 state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 837 state.AddAddressToAccessList(addr("cc")) 838 if exp, got := 8, state.journal.length(); exp != got { 839 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 840 } 841 842 verifyAddrs("aa", "bb", "cc") 843 verifySlots("aa", "01") 844 verifySlots("bb", "01", "02", "03") 845 verifySlots("cc", "01") 846 847 // now start rolling back changes 848 state.journal.revert(state, 7) 849 if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { 850 t.Fatalf("slot present, expected missing") 851 } 852 verifyAddrs("aa", "bb", "cc") 853 verifySlots("aa", "01") 854 verifySlots("bb", "01", "02", "03") 855 856 state.journal.revert(state, 6) 857 if state.AddressInAccessList(addr("cc")) { 858 t.Fatalf("addr present, expected missing") 859 } 860 verifyAddrs("aa", "bb") 861 verifySlots("aa", "01") 862 verifySlots("bb", "01", "02", "03") 863 864 state.journal.revert(state, 5) 865 if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { 866 t.Fatalf("slot present, expected missing") 867 } 868 verifyAddrs("aa", "bb") 869 verifySlots("bb", "01", "02", "03") 870 871 state.journal.revert(state, 4) 872 if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { 873 t.Fatalf("slot present, expected missing") 874 } 875 verifyAddrs("aa", "bb") 876 verifySlots("bb", "01", "02") 877 878 state.journal.revert(state, 3) 879 if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { 880 t.Fatalf("slot present, expected missing") 881 } 882 verifyAddrs("aa", "bb") 883 verifySlots("bb", "01") 884 885 state.journal.revert(state, 2) 886 if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { 887 t.Fatalf("slot present, expected missing") 888 } 889 verifyAddrs("aa", "bb") 890 891 state.journal.revert(state, 1) 892 if state.AddressInAccessList(addr("bb")) { 893 t.Fatalf("addr present, expected missing") 894 } 895 verifyAddrs("aa") 896 897 state.journal.revert(state, 0) 898 if state.AddressInAccessList(addr("aa")) { 899 t.Fatalf("addr present, expected missing") 900 } 901 if got, exp := len(state.accessList.addresses), 0; got != exp { 902 t.Fatalf("expected empty, got %d", got) 903 } 904 if got, exp := len(state.accessList.slots), 0; got != exp { 905 t.Fatalf("expected empty, got %d", got) 906 } 907 // Check the copy 908 // Make a copy 909 state = stateCopy1 910 verifyAddrs("aa", "bb") 911 verifySlots("bb", "01", "02") 912 if got, exp := len(state.accessList.addresses), 2; got != exp { 913 t.Fatalf("expected empty, got %d", got) 914 } 915 if got, exp := len(state.accessList.slots), 1; got != exp { 916 t.Fatalf("expected empty, got %d", got) 917 } 918 }