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