github.com/c2s/go-ethereum@v1.9.7/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 "gopkg.in/check.v1" 33 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/core/rawdb" 36 "github.com/ethereum/go-ethereum/core/types" 37 ) 38 39 // Tests that updating a state trie does not leak any database writes prior to 40 // actually committing the state. 41 func TestUpdateLeaks(t *testing.T) { 42 // Create an empty state database 43 db := rawdb.NewMemoryDatabase() 44 state, _ := New(common.Hash{}, NewDatabase(db)) 45 46 // Update it with some accounts 47 for i := byte(0); i < 255; i++ { 48 addr := common.BytesToAddress([]byte{i}) 49 state.AddBalance(addr, big.NewInt(int64(11*i))) 50 state.SetNonce(addr, uint64(42*i)) 51 if i%2 == 0 { 52 state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i})) 53 } 54 if i%3 == 0 { 55 state.SetCode(addr, []byte{i, i, i, i, i}) 56 } 57 } 58 59 root := state.IntermediateRoot(false) 60 if err := state.Database().TrieDB().Commit(root, false); err != nil { 61 t.Errorf("can not commit trie %v to persistent database", root.Hex()) 62 } 63 64 // Ensure that no data was leaked into the database 65 it := db.NewIterator() 66 for it.Next() { 67 t.Errorf("State leaked into database: %x -> %x", it.Key(), it.Value()) 68 } 69 it.Release() 70 } 71 72 // Tests that no intermediate state of an object is stored into the database, 73 // only the one right before the commit. 74 func TestIntermediateLeaks(t *testing.T) { 75 // Create two state databases, one transitioning to the final state, the other final from the beginning 76 transDb := rawdb.NewMemoryDatabase() 77 finalDb := rawdb.NewMemoryDatabase() 78 transState, _ := New(common.Hash{}, NewDatabase(transDb)) 79 finalState, _ := New(common.Hash{}, NewDatabase(finalDb)) 80 81 modify := func(state *StateDB, addr common.Address, i, tweak byte) { 82 state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak))) 83 state.SetNonce(addr, uint64(42*i+tweak)) 84 if i%2 == 0 { 85 state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{}) 86 state.SetState(addr, common.Hash{i, i, i, tweak}, common.Hash{i, i, i, i, tweak}) 87 } 88 if i%3 == 0 { 89 state.SetCode(addr, []byte{i, i, i, i, i, tweak}) 90 } 91 } 92 93 // Modify the transient state. 94 for i := byte(0); i < 255; i++ { 95 modify(transState, common.Address{i}, i, 0) 96 } 97 // Write modifications to trie. 98 transState.IntermediateRoot(false) 99 100 // Overwrite all the data with new values in the transient database. 101 for i := byte(0); i < 255; i++ { 102 modify(transState, common.Address{i}, i, 99) 103 modify(finalState, common.Address{i}, i, 99) 104 } 105 106 // Commit and cross check the databases. 107 transRoot, err := transState.Commit(false) 108 if err != nil { 109 t.Fatalf("failed to commit transition state: %v", err) 110 } 111 if err = transState.Database().TrieDB().Commit(transRoot, false); err != nil { 112 t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) 113 } 114 115 finalRoot, err := finalState.Commit(false) 116 if err != nil { 117 t.Fatalf("failed to commit final state: %v", err) 118 } 119 if err = finalState.Database().TrieDB().Commit(finalRoot, false); err != nil { 120 t.Errorf("can not commit trie %v to persistent database", finalRoot.Hex()) 121 } 122 123 it := finalDb.NewIterator() 124 for it.Next() { 125 key, fvalue := it.Key(), it.Value() 126 tvalue, err := transDb.Get(key) 127 if err != nil { 128 t.Errorf("entry missing from the transition database: %x -> %x", key, fvalue) 129 } 130 if !bytes.Equal(fvalue, tvalue) { 131 t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue) 132 } 133 } 134 it.Release() 135 136 it = transDb.NewIterator() 137 for it.Next() { 138 key, tvalue := it.Key(), it.Value() 139 fvalue, err := finalDb.Get(key) 140 if err != nil { 141 t.Errorf("extra entry in the transition database: %x -> %x", key, it.Value()) 142 } 143 if !bytes.Equal(fvalue, tvalue) { 144 t.Errorf("the value associate key %x is mismatch,: %x in transition database ,%x in final database", key, tvalue, fvalue) 145 } 146 } 147 } 148 149 // TestCopy tests that copying a statedb object indeed makes the original and 150 // the copy independent of each other. This test is a regression test against 151 // https://github.com/ethereum/go-ethereum/pull/15549. 152 func TestCopy(t *testing.T) { 153 // Create a random state test to copy and modify "independently" 154 orig, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 155 156 for i := byte(0); i < 255; i++ { 157 obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 158 obj.AddBalance(big.NewInt(int64(i))) 159 orig.updateStateObject(obj) 160 } 161 orig.Finalise(false) 162 163 // Copy the state 164 copy := orig.Copy() 165 166 // Copy the copy state 167 ccopy := copy.Copy() 168 169 // modify all in memory 170 for i := byte(0); i < 255; i++ { 171 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 172 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 173 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 174 175 origObj.AddBalance(big.NewInt(2 * int64(i))) 176 copyObj.AddBalance(big.NewInt(3 * int64(i))) 177 ccopyObj.AddBalance(big.NewInt(4 * int64(i))) 178 179 orig.updateStateObject(origObj) 180 copy.updateStateObject(copyObj) 181 ccopy.updateStateObject(copyObj) 182 } 183 184 // Finalise the changes on all concurrently 185 finalise := func(wg *sync.WaitGroup, db *StateDB) { 186 defer wg.Done() 187 db.Finalise(true) 188 } 189 190 var wg sync.WaitGroup 191 wg.Add(3) 192 go finalise(&wg, orig) 193 go finalise(&wg, copy) 194 go finalise(&wg, ccopy) 195 wg.Wait() 196 197 // Verify that the three states have been updated independently 198 for i := byte(0); i < 255; i++ { 199 origObj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 200 copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 201 ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i})) 202 203 if want := big.NewInt(3 * int64(i)); origObj.Balance().Cmp(want) != 0 { 204 t.Errorf("orig obj %d: balance mismatch: have %v, want %v", i, origObj.Balance(), want) 205 } 206 if want := big.NewInt(4 * int64(i)); copyObj.Balance().Cmp(want) != 0 { 207 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, copyObj.Balance(), want) 208 } 209 if want := big.NewInt(5 * int64(i)); ccopyObj.Balance().Cmp(want) != 0 { 210 t.Errorf("copy obj %d: balance mismatch: have %v, want %v", i, ccopyObj.Balance(), want) 211 } 212 } 213 } 214 215 func TestSnapshotRandom(t *testing.T) { 216 config := &quick.Config{MaxCount: 1000} 217 err := quick.Check((*snapshotTest).run, config) 218 if cerr, ok := err.(*quick.CheckError); ok { 219 test := cerr.In[0].(*snapshotTest) 220 t.Errorf("%v:\n%s", test.err, test) 221 } else if err != nil { 222 t.Error(err) 223 } 224 } 225 226 // A snapshotTest checks that reverting StateDB snapshots properly undoes all changes 227 // captured by the snapshot. Instances of this test with pseudorandom content are created 228 // by Generate. 229 // 230 // The test works as follows: 231 // 232 // A new state is created and all actions are applied to it. Several snapshots are taken 233 // in between actions. The test then reverts each snapshot. For each snapshot the actions 234 // leading up to it are replayed on a fresh, empty state. The behaviour of all public 235 // accessor methods on the reverted state must match the return value of the equivalent 236 // methods on the replayed state. 237 type snapshotTest struct { 238 addrs []common.Address // all account addresses 239 actions []testAction // modifications to the state 240 snapshots []int // actions indexes at which snapshot is taken 241 err error // failure details are reported through this field 242 } 243 244 type testAction struct { 245 name string 246 fn func(testAction, *StateDB) 247 args []int64 248 noAddr bool 249 } 250 251 // newTestAction creates a random action that changes state. 252 func newTestAction(addr common.Address, r *rand.Rand) testAction { 253 actions := []testAction{ 254 { 255 name: "SetBalance", 256 fn: func(a testAction, s *StateDB) { 257 s.SetBalance(addr, big.NewInt(a.args[0])) 258 }, 259 args: make([]int64, 1), 260 }, 261 { 262 name: "AddBalance", 263 fn: func(a testAction, s *StateDB) { 264 s.AddBalance(addr, big.NewInt(a.args[0])) 265 }, 266 args: make([]int64, 1), 267 }, 268 { 269 name: "SetNonce", 270 fn: func(a testAction, s *StateDB) { 271 s.SetNonce(addr, uint64(a.args[0])) 272 }, 273 args: make([]int64, 1), 274 }, 275 { 276 name: "SetState", 277 fn: func(a testAction, s *StateDB) { 278 var key, val common.Hash 279 binary.BigEndian.PutUint16(key[:], uint16(a.args[0])) 280 binary.BigEndian.PutUint16(val[:], uint16(a.args[1])) 281 s.SetState(addr, key, val) 282 }, 283 args: make([]int64, 2), 284 }, 285 { 286 name: "SetCode", 287 fn: func(a testAction, s *StateDB) { 288 code := make([]byte, 16) 289 binary.BigEndian.PutUint64(code, uint64(a.args[0])) 290 binary.BigEndian.PutUint64(code[8:], uint64(a.args[1])) 291 s.SetCode(addr, code) 292 }, 293 args: make([]int64, 2), 294 }, 295 { 296 name: "CreateAccount", 297 fn: func(a testAction, s *StateDB) { 298 s.CreateAccount(addr) 299 }, 300 }, 301 { 302 name: "Suicide", 303 fn: func(a testAction, s *StateDB) { 304 s.Suicide(addr) 305 }, 306 }, 307 { 308 name: "AddRefund", 309 fn: func(a testAction, s *StateDB) { 310 s.AddRefund(uint64(a.args[0])) 311 }, 312 args: make([]int64, 1), 313 noAddr: true, 314 }, 315 { 316 name: "AddLog", 317 fn: func(a testAction, s *StateDB) { 318 data := make([]byte, 2) 319 binary.BigEndian.PutUint16(data, uint16(a.args[0])) 320 s.AddLog(&types.Log{Address: addr, Data: data}) 321 }, 322 args: make([]int64, 1), 323 }, 324 { 325 name: "AddPreimage", 326 fn: func(a testAction, s *StateDB) { 327 preimage := []byte{1} 328 hash := common.BytesToHash(preimage) 329 s.AddPreimage(hash, preimage) 330 }, 331 args: make([]int64, 1), 332 }, 333 } 334 action := actions[r.Intn(len(actions))] 335 var nameargs []string 336 if !action.noAddr { 337 nameargs = append(nameargs, addr.Hex()) 338 } 339 for i := range action.args { 340 action.args[i] = rand.Int63n(100) 341 nameargs = append(nameargs, fmt.Sprint(action.args[i])) 342 } 343 action.name += strings.Join(nameargs, ", ") 344 return action 345 } 346 347 // Generate returns a new snapshot test of the given size. All randomness is 348 // derived from r. 349 func (*snapshotTest) Generate(r *rand.Rand, size int) reflect.Value { 350 // Generate random actions. 351 addrs := make([]common.Address, 50) 352 for i := range addrs { 353 addrs[i][0] = byte(i) 354 } 355 actions := make([]testAction, size) 356 for i := range actions { 357 addr := addrs[r.Intn(len(addrs))] 358 actions[i] = newTestAction(addr, r) 359 } 360 // Generate snapshot indexes. 361 nsnapshots := int(math.Sqrt(float64(size))) 362 if size > 0 && nsnapshots == 0 { 363 nsnapshots = 1 364 } 365 snapshots := make([]int, nsnapshots) 366 snaplen := len(actions) / nsnapshots 367 for i := range snapshots { 368 // Try to place the snapshots some number of actions apart from each other. 369 snapshots[i] = (i * snaplen) + r.Intn(snaplen) 370 } 371 return reflect.ValueOf(&snapshotTest{addrs, actions, snapshots, nil}) 372 } 373 374 func (test *snapshotTest) String() string { 375 out := new(bytes.Buffer) 376 sindex := 0 377 for i, action := range test.actions { 378 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 379 fmt.Fprintf(out, "---- snapshot %d ----\n", sindex) 380 sindex++ 381 } 382 fmt.Fprintf(out, "%4d: %s\n", i, action.name) 383 } 384 return out.String() 385 } 386 387 func (test *snapshotTest) run() bool { 388 // Run all actions and create snapshots. 389 var ( 390 state, _ = New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 391 snapshotRevs = make([]int, len(test.snapshots)) 392 sindex = 0 393 ) 394 for i, action := range test.actions { 395 if len(test.snapshots) > sindex && i == test.snapshots[sindex] { 396 snapshotRevs[sindex] = state.Snapshot() 397 sindex++ 398 } 399 action.fn(action, state) 400 } 401 // Revert all snapshots in reverse order. Each revert must yield a state 402 // that is equivalent to fresh state with all actions up the snapshot applied. 403 for sindex--; sindex >= 0; sindex-- { 404 checkstate, _ := New(common.Hash{}, state.Database()) 405 for _, action := range test.actions[:test.snapshots[sindex]] { 406 action.fn(action, checkstate) 407 } 408 state.RevertToSnapshot(snapshotRevs[sindex]) 409 if err := test.checkEqual(state, checkstate); err != nil { 410 test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err) 411 return false 412 } 413 } 414 return true 415 } 416 417 // checkEqual checks that methods of state and checkstate return the same values. 418 func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { 419 for _, addr := range test.addrs { 420 var err error 421 checkeq := func(op string, a, b interface{}) bool { 422 if err == nil && !reflect.DeepEqual(a, b) { 423 err = fmt.Errorf("got %s(%s) == %v, want %v", op, addr.Hex(), a, b) 424 return false 425 } 426 return true 427 } 428 // Check basic accessor methods. 429 checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) 430 checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr)) 431 checkeq("GetBalance", state.GetBalance(addr), checkstate.GetBalance(addr)) 432 checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr)) 433 checkeq("GetCode", state.GetCode(addr), checkstate.GetCode(addr)) 434 checkeq("GetCodeHash", state.GetCodeHash(addr), checkstate.GetCodeHash(addr)) 435 checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr)) 436 // Check storage. 437 if obj := state.getStateObject(addr); obj != nil { 438 state.ForEachStorage(addr, func(key, value common.Hash) bool { 439 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 440 }) 441 checkstate.ForEachStorage(addr, func(key, value common.Hash) bool { 442 return checkeq("GetState("+key.Hex()+")", checkstate.GetState(addr, key), value) 443 }) 444 } 445 if err != nil { 446 return err 447 } 448 } 449 450 if state.GetRefund() != checkstate.GetRefund() { 451 return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", 452 state.GetRefund(), checkstate.GetRefund()) 453 } 454 if !reflect.DeepEqual(state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) { 455 return fmt.Errorf("got GetLogs(common.Hash{}) == %v, want GetLogs(common.Hash{}) == %v", 456 state.GetLogs(common.Hash{}), checkstate.GetLogs(common.Hash{})) 457 } 458 return nil 459 } 460 461 func (s *StateSuite) TestTouchDelete(c *check.C) { 462 s.state.GetOrNewStateObject(common.Address{}) 463 root, _ := s.state.Commit(false) 464 s.state.Reset(root) 465 466 snapshot := s.state.Snapshot() 467 s.state.AddBalance(common.Address{}, new(big.Int)) 468 469 if len(s.state.journal.dirties) != 1 { 470 c.Fatal("expected one dirty state object") 471 } 472 s.state.RevertToSnapshot(snapshot) 473 if len(s.state.journal.dirties) != 0 { 474 c.Fatal("expected no dirty state object") 475 } 476 } 477 478 // TestCopyOfCopy tests that modified objects are carried over to the copy, and the copy of the copy. 479 // See https://github.com/ethereum/go-ethereum/pull/15225#issuecomment-380191512 480 func TestCopyOfCopy(t *testing.T) { 481 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 482 addr := common.HexToAddress("aaaa") 483 state.SetBalance(addr, big.NewInt(42)) 484 485 if got := state.Copy().GetBalance(addr).Uint64(); got != 42 { 486 t.Fatalf("1st copy fail, expected 42, got %v", got) 487 } 488 if got := state.Copy().Copy().GetBalance(addr).Uint64(); got != 42 { 489 t.Fatalf("2nd copy fail, expected 42, got %v", got) 490 } 491 } 492 493 // Tests a regression where committing a copy lost some internal meta information, 494 // leading to corrupted subsequent copies. 495 // 496 // See https://github.com/ethereum/go-ethereum/issues/20106. 497 func TestCopyCommitCopy(t *testing.T) { 498 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 499 500 // Create an account and check if the retrieved balance is correct 501 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 502 skey := common.HexToHash("aaa") 503 sval := common.HexToHash("bbb") 504 505 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 506 state.SetCode(addr, []byte("hello")) // Change an external metadata 507 state.SetState(addr, skey, sval) // Change the storage trie 508 509 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 510 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 511 } 512 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 513 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 514 } 515 if val := state.GetState(addr, skey); val != sval { 516 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 517 } 518 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 519 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 520 } 521 // Copy the non-committed state database and check pre/post commit balance 522 copyOne := state.Copy() 523 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 524 t.Fatalf("first copy pre-commit balance mismatch: have %v, want %v", balance, 42) 525 } 526 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 527 t.Fatalf("first copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 528 } 529 if val := copyOne.GetState(addr, skey); val != sval { 530 t.Fatalf("first copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 531 } 532 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 533 t.Fatalf("first copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 534 } 535 536 copyOne.Commit(false) 537 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 538 t.Fatalf("first copy post-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 post-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 post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 545 } 546 if val := copyOne.GetCommittedState(addr, skey); val != sval { 547 t.Fatalf("first copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 548 } 549 // Copy the copy and check the balance once more 550 copyTwo := copyOne.Copy() 551 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 552 t.Fatalf("second copy balance mismatch: have %v, want %v", balance, 42) 553 } 554 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 555 t.Fatalf("second copy code mismatch: have %x, want %x", code, []byte("hello")) 556 } 557 if val := copyTwo.GetState(addr, skey); val != sval { 558 t.Fatalf("second copy non-committed storage slot mismatch: have %x, want %x", val, sval) 559 } 560 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 561 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 562 } 563 } 564 565 // Tests a regression where committing a copy lost some internal meta information, 566 // leading to corrupted subsequent copies. 567 // 568 // See https://github.com/ethereum/go-ethereum/issues/20106. 569 func TestCopyCopyCommitCopy(t *testing.T) { 570 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 571 572 // Create an account and check if the retrieved balance is correct 573 addr := common.HexToAddress("0xaffeaffeaffeaffeaffeaffeaffeaffeaffeaffe") 574 skey := common.HexToHash("aaa") 575 sval := common.HexToHash("bbb") 576 577 state.SetBalance(addr, big.NewInt(42)) // Change the account trie 578 state.SetCode(addr, []byte("hello")) // Change an external metadata 579 state.SetState(addr, skey, sval) // Change the storage trie 580 581 if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 582 t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42) 583 } 584 if code := state.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 585 t.Fatalf("initial code mismatch: have %x, want %x", code, []byte("hello")) 586 } 587 if val := state.GetState(addr, skey); val != sval { 588 t.Fatalf("initial non-committed storage slot mismatch: have %x, want %x", val, sval) 589 } 590 if val := state.GetCommittedState(addr, skey); val != (common.Hash{}) { 591 t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 592 } 593 // Copy the non-committed state database and check pre/post commit balance 594 copyOne := state.Copy() 595 if balance := copyOne.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 596 t.Fatalf("first copy balance mismatch: have %v, want %v", balance, 42) 597 } 598 if code := copyOne.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 599 t.Fatalf("first copy code mismatch: have %x, want %x", code, []byte("hello")) 600 } 601 if val := copyOne.GetState(addr, skey); val != sval { 602 t.Fatalf("first copy non-committed storage slot mismatch: have %x, want %x", val, sval) 603 } 604 if val := copyOne.GetCommittedState(addr, skey); val != (common.Hash{}) { 605 t.Fatalf("first copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 606 } 607 // Copy the copy and check the balance once more 608 copyTwo := copyOne.Copy() 609 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 610 t.Fatalf("second copy pre-commit balance mismatch: have %v, want %v", balance, 42) 611 } 612 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 613 t.Fatalf("second copy pre-commit code mismatch: have %x, want %x", code, []byte("hello")) 614 } 615 if val := copyTwo.GetState(addr, skey); val != sval { 616 t.Fatalf("second copy pre-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 617 } 618 if val := copyTwo.GetCommittedState(addr, skey); val != (common.Hash{}) { 619 t.Fatalf("second copy pre-commit committed storage slot mismatch: have %x, want %x", val, common.Hash{}) 620 } 621 copyTwo.Commit(false) 622 if balance := copyTwo.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 623 t.Fatalf("second copy post-commit balance mismatch: have %v, want %v", balance, 42) 624 } 625 if code := copyTwo.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 626 t.Fatalf("second copy post-commit code mismatch: have %x, want %x", code, []byte("hello")) 627 } 628 if val := copyTwo.GetState(addr, skey); val != sval { 629 t.Fatalf("second copy post-commit non-committed storage slot mismatch: have %x, want %x", val, sval) 630 } 631 if val := copyTwo.GetCommittedState(addr, skey); val != sval { 632 t.Fatalf("second copy post-commit committed storage slot mismatch: have %x, want %x", val, sval) 633 } 634 // Copy the copy-copy and check the balance once more 635 copyThree := copyTwo.Copy() 636 if balance := copyThree.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 { 637 t.Fatalf("third copy balance mismatch: have %v, want %v", balance, 42) 638 } 639 if code := copyThree.GetCode(addr); !bytes.Equal(code, []byte("hello")) { 640 t.Fatalf("third copy code mismatch: have %x, want %x", code, []byte("hello")) 641 } 642 if val := copyThree.GetState(addr, skey); val != sval { 643 t.Fatalf("third copy non-committed storage slot mismatch: have %x, want %x", val, sval) 644 } 645 if val := copyThree.GetCommittedState(addr, skey); val != sval { 646 t.Fatalf("third copy committed storage slot mismatch: have %x, want %x", val, sval) 647 } 648 } 649 650 // TestDeleteCreateRevert tests a weird state transition corner case that we hit 651 // while changing the internals of statedb. The workflow is that a contract is 652 // self destructed, then in a followup transaction (but same block) it's created 653 // again and the transaction reverted. 654 // 655 // The original statedb implementation flushed dirty objects to the tries after 656 // each transaction, so this works ok. The rework accumulated writes in memory 657 // first, but the journal wiped the entire state object on create-revert. 658 func TestDeleteCreateRevert(t *testing.T) { 659 // Create an initial state with a single contract 660 state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase())) 661 662 addr := toAddr([]byte("so")) 663 state.SetBalance(addr, big.NewInt(1)) 664 665 root, _ := state.Commit(false) 666 state.Reset(root) 667 668 // Simulate self-destructing in one transaction, then create-reverting in another 669 state.Suicide(addr) 670 state.Finalise(true) 671 672 id := state.Snapshot() 673 state.SetBalance(addr, big.NewInt(2)) 674 state.RevertToSnapshot(id) 675 676 // Commit the entire state and make sure we don't crash and have the correct state 677 root, _ = state.Commit(true) 678 state.Reset(root) 679 680 if state.getStateObject(addr) != nil { 681 t.Fatalf("self-destructed contract came alive") 682 } 683 }