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