gitlab.com/flarenetwork/coreth@v0.1.1/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/ethereum/go-ethereum/common" 43 "github.com/ethereum/go-ethereum/crypto" 44 "gitlab.com/flarenetwork/coreth/core/rawdb" 45 "gitlab.com/flarenetwork/coreth/core/state/snapshot" 46 "gitlab.com/flarenetwork/coreth/core/types" 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) 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) 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) 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) 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) 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) 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) 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 715 // Create an initial state with a few accounts 716 memDb := rawdb.NewMemoryDatabase() 717 db := NewDatabase(memDb) 718 var root common.Hash 719 state, _ := New(common.Hash{}, db, nil) 720 addr := common.BytesToAddress([]byte("so")) 721 { 722 state.SetBalance(addr, big.NewInt(1)) 723 state.SetCode(addr, []byte{1, 2, 3}) 724 a2 := common.BytesToAddress([]byte("another")) 725 state.SetBalance(a2, big.NewInt(100)) 726 state.SetCode(a2, []byte{1, 2, 4}) 727 root, _ = state.Commit(false) 728 t.Logf("root: %x", root) 729 // force-flush 730 state.Database().TrieDB().Cap(0) 731 } 732 // Create a new state on the old root 733 state, _ = New(root, db, nil) 734 // Now we clear out the memdb 735 it := memDb.NewIterator(nil, nil) 736 for it.Next() { 737 k := it.Key() 738 // Leave the root intact 739 if !bytes.Equal(k, root[:]) { 740 t.Logf("key: %x", k) 741 memDb.Delete(k) 742 } 743 } 744 balance := state.GetBalance(addr) 745 // The removed elem should lead to it returning zero balance 746 if exp, got := uint64(0), balance.Uint64(); got != exp { 747 t.Errorf("expected %d, got %d", exp, got) 748 } 749 // Modify the state 750 state.SetBalance(addr, big.NewInt(2)) 751 root, err := state.Commit(false) 752 if err == nil { 753 t.Fatalf("expected error, got root :%x", root) 754 } 755 } 756 757 func TestStateDBAccessList(t *testing.T) { 758 // Some helpers 759 addr := func(a string) common.Address { 760 return common.HexToAddress(a) 761 } 762 slot := func(a string) common.Hash { 763 return common.HexToHash(a) 764 } 765 766 memDb := rawdb.NewMemoryDatabase() 767 db := NewDatabase(memDb) 768 state, _ := New(common.Hash{}, db, nil) 769 state.accessList = newAccessList() 770 771 verifyAddrs := func(astrings ...string) { 772 t.Helper() 773 // convert to common.Address form 774 var addresses []common.Address 775 var addressMap = make(map[common.Address]struct{}) 776 for _, astring := range astrings { 777 address := addr(astring) 778 addresses = append(addresses, address) 779 addressMap[address] = struct{}{} 780 } 781 // Check that the given addresses are in the access list 782 for _, address := range addresses { 783 if !state.AddressInAccessList(address) { 784 t.Fatalf("expected %x to be in access list", address) 785 } 786 } 787 // Check that only the expected addresses are present in the acesslist 788 for address := range state.accessList.addresses { 789 if _, exist := addressMap[address]; !exist { 790 t.Fatalf("extra address %x in access list", address) 791 } 792 } 793 } 794 verifySlots := func(addrString string, slotStrings ...string) { 795 if !state.AddressInAccessList(addr(addrString)) { 796 t.Fatalf("scope missing address/slots %v", addrString) 797 } 798 var address = addr(addrString) 799 // convert to common.Hash form 800 var slots []common.Hash 801 var slotMap = make(map[common.Hash]struct{}) 802 for _, slotString := range slotStrings { 803 s := slot(slotString) 804 slots = append(slots, s) 805 slotMap[s] = struct{}{} 806 } 807 // Check that the expected items are in the access list 808 for i, s := range slots { 809 if _, slotPresent := state.SlotInAccessList(address, s); !slotPresent { 810 t.Fatalf("input %d: scope missing slot %v (address %v)", i, s, addrString) 811 } 812 } 813 // Check that no extra elements are in the access list 814 index := state.accessList.addresses[address] 815 if index >= 0 { 816 stateSlots := state.accessList.slots[index] 817 for s := range stateSlots { 818 if _, slotPresent := slotMap[s]; !slotPresent { 819 t.Fatalf("scope has extra slot %v (address %v)", s, addrString) 820 } 821 } 822 } 823 } 824 825 state.AddAddressToAccessList(addr("aa")) // 1 826 state.AddSlotToAccessList(addr("bb"), slot("01")) // 2,3 827 state.AddSlotToAccessList(addr("bb"), slot("02")) // 4 828 verifyAddrs("aa", "bb") 829 verifySlots("bb", "01", "02") 830 831 // Make a copy 832 stateCopy1 := state.Copy() 833 if exp, got := 4, state.journal.length(); exp != got { 834 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 835 } 836 837 // same again, should cause no journal entries 838 state.AddSlotToAccessList(addr("bb"), slot("01")) 839 state.AddSlotToAccessList(addr("bb"), slot("02")) 840 state.AddAddressToAccessList(addr("aa")) 841 if exp, got := 4, state.journal.length(); exp != got { 842 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 843 } 844 // some new ones 845 state.AddSlotToAccessList(addr("bb"), slot("03")) // 5 846 state.AddSlotToAccessList(addr("aa"), slot("01")) // 6 847 state.AddSlotToAccessList(addr("cc"), slot("01")) // 7,8 848 state.AddAddressToAccessList(addr("cc")) 849 if exp, got := 8, state.journal.length(); exp != got { 850 t.Fatalf("journal length mismatch: have %d, want %d", got, exp) 851 } 852 853 verifyAddrs("aa", "bb", "cc") 854 verifySlots("aa", "01") 855 verifySlots("bb", "01", "02", "03") 856 verifySlots("cc", "01") 857 858 // now start rolling back changes 859 state.journal.revert(state, 7) 860 if _, ok := state.SlotInAccessList(addr("cc"), slot("01")); ok { 861 t.Fatalf("slot present, expected missing") 862 } 863 verifyAddrs("aa", "bb", "cc") 864 verifySlots("aa", "01") 865 verifySlots("bb", "01", "02", "03") 866 867 state.journal.revert(state, 6) 868 if state.AddressInAccessList(addr("cc")) { 869 t.Fatalf("addr present, expected missing") 870 } 871 verifyAddrs("aa", "bb") 872 verifySlots("aa", "01") 873 verifySlots("bb", "01", "02", "03") 874 875 state.journal.revert(state, 5) 876 if _, ok := state.SlotInAccessList(addr("aa"), slot("01")); ok { 877 t.Fatalf("slot present, expected missing") 878 } 879 verifyAddrs("aa", "bb") 880 verifySlots("bb", "01", "02", "03") 881 882 state.journal.revert(state, 4) 883 if _, ok := state.SlotInAccessList(addr("bb"), slot("03")); ok { 884 t.Fatalf("slot present, expected missing") 885 } 886 verifyAddrs("aa", "bb") 887 verifySlots("bb", "01", "02") 888 889 state.journal.revert(state, 3) 890 if _, ok := state.SlotInAccessList(addr("bb"), slot("02")); ok { 891 t.Fatalf("slot present, expected missing") 892 } 893 verifyAddrs("aa", "bb") 894 verifySlots("bb", "01") 895 896 state.journal.revert(state, 2) 897 if _, ok := state.SlotInAccessList(addr("bb"), slot("01")); ok { 898 t.Fatalf("slot present, expected missing") 899 } 900 verifyAddrs("aa", "bb") 901 902 state.journal.revert(state, 1) 903 if state.AddressInAccessList(addr("bb")) { 904 t.Fatalf("addr present, expected missing") 905 } 906 verifyAddrs("aa") 907 908 state.journal.revert(state, 0) 909 if state.AddressInAccessList(addr("aa")) { 910 t.Fatalf("addr present, expected missing") 911 } 912 if got, exp := len(state.accessList.addresses), 0; got != exp { 913 t.Fatalf("expected empty, got %d", got) 914 } 915 if got, exp := len(state.accessList.slots), 0; got != exp { 916 t.Fatalf("expected empty, got %d", got) 917 } 918 // Check the copy 919 // Make a copy 920 state = stateCopy1 921 verifyAddrs("aa", "bb") 922 verifySlots("bb", "01", "02") 923 if got, exp := len(state.accessList.addresses), 2; got != exp { 924 t.Fatalf("expected empty, got %d", got) 925 } 926 if got, exp := len(state.accessList.slots), 1; got != exp { 927 t.Fatalf("expected empty, got %d", got) 928 } 929 } 930 931 func TestMultiCoinOperations(t *testing.T) { 932 s := newStateTest() 933 addr := common.Address{1} 934 assetID := common.Hash{2} 935 936 s.state.GetOrNewStateObject(addr) 937 root, _ := s.state.Commit(false) 938 s.state, _ = NewWithSnapshot(root, s.state.db, s.state.snap) 939 940 s.state.AddBalance(addr, new(big.Int)) 941 942 balance := s.state.GetBalanceMultiCoin(addr, assetID) 943 if balance.Cmp(big.NewInt(0)) != 0 { 944 t.Fatal("expected zero multicoin balance") 945 } 946 947 s.state.SetBalanceMultiCoin(addr, assetID, big.NewInt(10)) 948 s.state.SubBalanceMultiCoin(addr, assetID, big.NewInt(5)) 949 s.state.AddBalanceMultiCoin(addr, assetID, big.NewInt(3)) 950 951 balance = s.state.GetBalanceMultiCoin(addr, assetID) 952 if balance.Cmp(big.NewInt(8)) != 0 { 953 t.Fatal("expected multicoin balance to be 8") 954 } 955 } 956 957 func TestMultiCoinSnapshot(t *testing.T) { 958 db := rawdb.NewMemoryDatabase() 959 sdb := NewDatabase(db) 960 961 // Create empty snapshot.Tree and StateDB 962 root := common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") 963 // Use the root as both the stateRoot and blockHash for this test. 964 snapTree := snapshot.NewTestTree(db, root, root) 965 966 addr := common.Address{1} 967 assetID1 := common.Hash{1} 968 assetID2 := common.Hash{2} 969 970 var stateDB *StateDB 971 assertBalances := func(regular, multicoin1, multicoin2 int64) { 972 balance := stateDB.GetBalance(addr) 973 if balance.Cmp(big.NewInt(regular)) != 0 { 974 t.Fatal("incorrect non-multicoin balance") 975 } 976 balance = stateDB.GetBalanceMultiCoin(addr, assetID1) 977 if balance.Cmp(big.NewInt(multicoin1)) != 0 { 978 t.Fatal("incorrect multicoin1 balance") 979 } 980 balance = stateDB.GetBalanceMultiCoin(addr, assetID2) 981 if balance.Cmp(big.NewInt(multicoin2)) != 0 { 982 t.Fatal("incorrect multicoin2 balance") 983 } 984 } 985 986 // Create new state 987 stateDB, _ = New(root, sdb, snapTree) 988 assertBalances(0, 0, 0) 989 990 stateDB.AddBalance(addr, big.NewInt(10)) 991 assertBalances(10, 0, 0) 992 993 // Commit and get the new root 994 root, _ = stateDB.Commit(false) 995 assertBalances(10, 0, 0) 996 997 // Create a new state from the latest root, add a multicoin balance, and 998 // commit it to the tree. 999 stateDB, _ = New(root, sdb, snapTree) 1000 stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(10)) 1001 root, _ = stateDB.Commit(false) 1002 assertBalances(10, 10, 0) 1003 1004 // Add more layers than the cap and ensure the balances and layers are correct 1005 for i := 0; i < 256; i++ { 1006 stateDB, _ = New(root, sdb, snapTree) 1007 stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1)) 1008 stateDB.AddBalanceMultiCoin(addr, assetID2, big.NewInt(2)) 1009 root, _ = stateDB.Commit(false) 1010 } 1011 assertBalances(10, 266, 512) 1012 1013 // Do one more add, including the regular balance which is now in the 1014 // collapsed snapshot 1015 stateDB, _ = New(root, sdb, snapTree) 1016 stateDB.AddBalance(addr, big.NewInt(1)) 1017 stateDB.AddBalanceMultiCoin(addr, assetID1, big.NewInt(1)) 1018 _, _ = stateDB.Commit(false) 1019 assertBalances(11, 267, 512) 1020 } 1021 1022 func TestGenerateMultiCoinAccounts(t *testing.T) { 1023 var ( 1024 diskdb = rawdb.NewMemoryDatabase() 1025 database = NewDatabase(diskdb) 1026 1027 addr = common.BytesToAddress([]byte("addr1")) 1028 addrHash = crypto.Keccak256Hash(addr[:]) 1029 1030 assetID = common.BytesToHash([]byte("coin1")) 1031 assetBalance = big.NewInt(10) 1032 ) 1033 1034 stateDB, err := New(common.Hash{}, database, nil) 1035 if err != nil { 1036 t.Fatal(err) 1037 } 1038 stateDB.SetBalanceMultiCoin(addr, assetID, assetBalance) 1039 root, err := stateDB.Commit(false) 1040 if err != nil { 1041 t.Fatal(err) 1042 } 1043 1044 triedb := database.TrieDB() 1045 if err := triedb.Commit(root, true, nil); err != nil { 1046 t.Fatal(err) 1047 } 1048 // Build snapshot from scratch 1049 snaps, err := snapshot.New(diskdb, triedb, 16, common.Hash{}, root, false, true, false) 1050 if err != nil { 1051 t.Error("Unexpected error while rebuilding snapshot:", err) 1052 } 1053 1054 // Get latest snapshot and make sure it has the correct account and storage 1055 snap := snaps.Snapshot(root) 1056 snapAccount, err := snap.Account(addrHash) 1057 if err != nil { 1058 t.Fatal(err) 1059 } 1060 if !snapAccount.IsMultiCoin { 1061 t.Fatalf("Expected SnapAccount to return IsMultiCoin: true, found: %v", snapAccount.IsMultiCoin) 1062 } 1063 1064 NormalizeCoinID(&assetID) 1065 assetHash := crypto.Keccak256Hash(assetID.Bytes()) 1066 storageBytes, err := snap.Storage(addrHash, assetHash) 1067 if err != nil { 1068 t.Fatal(err) 1069 } 1070 1071 actualAssetBalance := new(big.Int).SetBytes(storageBytes) 1072 if actualAssetBalance.Cmp(assetBalance) != 0 { 1073 t.Fatalf("Expected asset balance: %v, found %v", assetBalance, actualAssetBalance) 1074 } 1075 }