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