// makeTestState create a sample test state to test node-wise reconstruction. func makeTestState() (ethdb.Database, common.Hash, []*testAccount) { // Create an empty state db, _ := ethdb.NewMemDatabase() state, _ := New(common.Hash{}, db) // Fill it with some arbitrary data accounts := []*testAccount{} for i := byte(0); i < 96; i++ { obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i})) acc := &testAccount{address: common.BytesToAddress([]byte{i})} obj.AddBalance(big.NewInt(int64(11 * i))) acc.balance = big.NewInt(int64(11 * i)) obj.SetNonce(uint64(42 * i)) acc.nonce = uint64(42 * i) if i%3 == 0 { obj.SetCode([]byte{i, i, i, i, i}) acc.code = []byte{i, i, i, i, i} } state.UpdateStateObject(obj) accounts = append(accounts, acc) } root, _ := state.Commit() // Remove any potentially cached data from the test state creation trie.ClearGlobalCache() // Return the generated state return db, root, accounts }
func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { switch req := req.(type) { case *TrieRequest: t, _ := trie.New(req.root, odr.sdb) req.proof = t.Prove(req.key) trie.ClearGlobalCache() case *NodeDataRequest: req.data, _ = odr.sdb.Get(req.hash[:]) } req.StoreResult(odr.ldb) return nil }
// checkStateConsistency checks that all nodes in a state trie are indeed present. func checkStateConsistency(db ethdb.Database, root common.Hash) error { // Remove any potentially cached data from the test state creation or previous checks trie.ClearGlobalCache() // Create and iterate a state trie rooted in a sub-node if _, err := db.Get(root.Bytes()); err != nil { return nil // Consider a non existent state consistent } state, err := New(root, db) if err != nil { return err } it := NewNodeIterator(state) for it.Next() { } return it.Error }
// checkStateAccounts cross references a reconstructed state with an expected // account array. func checkStateAccounts(t *testing.T, db ethdb.Database, root common.Hash, accounts []*testAccount) { // Remove any potentially cached data from the state synchronisation trie.ClearGlobalCache() // Check root availability and state contents state, err := New(root, db) if err != nil { t.Fatalf("failed to create state trie at %x: %v", root, err) } if err := checkStateConsistency(db, root); err != nil { t.Fatalf("inconsistent state trie at %x: %v", root, err) } for i, acc := range accounts { if balance := state.GetBalance(acc.address); balance.Cmp(acc.balance) != 0 { t.Errorf("account %d: balance mismatch: have %v, want %v", i, balance, acc.balance) } if nonce := state.GetNonce(acc.address); nonce != acc.nonce { t.Errorf("account %d: nonce mismatch: have %v, want %v", i, nonce, acc.nonce) } if code := state.GetCode(acc.address); bytes.Compare(code, acc.code) != 0 { t.Errorf("account %d: code mismatch: have %x, want %x", i, code, acc.code) } } }
func TestLightStateDelete(t *testing.T) { root, sdb := makeTestState() ldb, _ := ethdb.NewMemDatabase() odr := &testOdr{sdb: sdb, ldb: ldb} ls := NewLightState(root, odr) ctx := context.Background() trie.ClearGlobalCache() addr := common.Address{42} b, err := ls.HasAccount(ctx, addr) if err != nil { t.Fatalf("HasAccount error: %v", err) } if !b { t.Fatalf("HasAccount returned false, expected true") } b, err = ls.IsDeleted(ctx, addr) if err != nil { t.Fatalf("IsDeleted error: %v", err) } if b { t.Fatalf("IsDeleted returned true, expected false") } ls.Delete(ctx, addr) b, err = ls.IsDeleted(ctx, addr) if err != nil { t.Fatalf("IsDeleted error: %v", err) } if !b { t.Fatalf("IsDeleted returned false, expected true") } }
func TestLightStateOdr(t *testing.T) { root, sdb := makeTestState() ldb, _ := ethdb.NewMemDatabase() odr := &testOdr{sdb: sdb, ldb: ldb} ls := NewLightState(root, odr) ctx := context.Background() trie.ClearGlobalCache() for i := byte(0); i < 100; i++ { addr := common.Address{i} err := ls.AddBalance(ctx, addr, big.NewInt(1000)) if err != nil { t.Fatalf("Error adding balance to acc[%d]: %v", i, err) } err = ls.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 100}) if err != nil { t.Fatalf("Error setting storage of acc[%d]: %v", i, err) } } addr := common.Address{100} _, err := ls.CreateStateObject(ctx, addr) if err != nil { t.Fatalf("Error creating state object: %v", err) } err = ls.SetCode(ctx, addr, []byte{100, 100, 100}) if err != nil { t.Fatalf("Error setting code: %v", err) } err = ls.AddBalance(ctx, addr, big.NewInt(1100)) if err != nil { t.Fatalf("Error adding balance to acc[100]: %v", err) } for j := byte(0); j < 101; j++ { err = ls.SetState(ctx, addr, common.Hash{j}, common.Hash{100, j}) if err != nil { t.Fatalf("Error setting storage of acc[100]: %v", err) } } err = ls.SetNonce(ctx, addr, 100) if err != nil { t.Fatalf("Error setting nonce for acc[100]: %v", err) } for i := byte(0); i < 101; i++ { addr := common.Address{i} bal, err := ls.GetBalance(ctx, addr) if err != nil { t.Fatalf("Error getting balance of acc[%d]: %v", i, err) } if bal.Int64() != int64(i)+1000 { t.Fatalf("Incorrect balance at acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) } nonce, err := ls.GetNonce(ctx, addr) if err != nil { t.Fatalf("Error getting nonce of acc[%d]: %v", i, err) } if nonce != 100 { t.Fatalf("Incorrect nonce at acc[%d]: expected %v, got %v", i, 100, nonce) } code, err := ls.GetCode(ctx, addr) exp := []byte{i, i, i} if err != nil { t.Fatalf("Error getting code of acc[%d]: %v", i, err) } if !bytes.Equal(code, exp) { t.Fatalf("Incorrect code at acc[%d]: expected %v, got %v", i, exp, code) } for j := byte(0); j < 101; j++ { exp := common.Hash{i, j} val, err := ls.GetState(ctx, addr, common.Hash{j}) if err != nil { t.Fatalf("Error retrieving acc[%d].storage[%d]: %v", i, j, err) } if val != exp { t.Fatalf("Retrieved wrong value from acc[%d].storage[%d]: expected %04x, got %04x", i, j, exp, val) } } } }
func TestLightStateSetCopy(t *testing.T) { root, sdb := makeTestState() ldb, _ := ethdb.NewMemDatabase() odr := &testOdr{sdb: sdb, ldb: ldb} ls := NewLightState(root, odr) ctx := context.Background() trie.ClearGlobalCache() for i := byte(0); i < 100; i++ { addr := common.Address{i} err := ls.AddBalance(ctx, addr, big.NewInt(1000)) if err != nil { t.Fatalf("Error adding balance to acc[%d]: %v", i, err) } err = ls.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 100}) if err != nil { t.Fatalf("Error setting storage of acc[%d]: %v", i, err) } } ls2 := ls.Copy() for i := byte(0); i < 100; i++ { addr := common.Address{i} err := ls2.AddBalance(ctx, addr, big.NewInt(1000)) if err != nil { t.Fatalf("Error adding balance to acc[%d]: %v", i, err) } err = ls2.SetState(ctx, addr, common.Hash{100}, common.Hash{i, 200}) if err != nil { t.Fatalf("Error setting storage of acc[%d]: %v", i, err) } } lsx := ls.Copy() ls.Set(ls2) ls2.Set(lsx) for i := byte(0); i < 100; i++ { addr := common.Address{i} // check balance in ls bal, err := ls.GetBalance(ctx, addr) if err != nil { t.Fatalf("Error getting balance to acc[%d]: %v", i, err) } if bal.Int64() != int64(i)+2000 { t.Fatalf("Incorrect balance at ls.acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) } // check balance in ls2 bal, err = ls2.GetBalance(ctx, addr) if err != nil { t.Fatalf("Error getting balance to acc[%d]: %v", i, err) } if bal.Int64() != int64(i)+1000 { t.Fatalf("Incorrect balance at ls.acc[%d]: expected %v, got %v", i, int64(i)+1000, bal.Int64()) } // check storage in ls exp := common.Hash{i, 200} val, err := ls.GetState(ctx, addr, common.Hash{100}) if err != nil { t.Fatalf("Error retrieving acc[%d].storage[100]: %v", i, err) } if val != exp { t.Fatalf("Retrieved wrong value from acc[%d].storage[100]: expected %04x, got %04x", i, exp, val) } // check storage in ls2 exp = common.Hash{i, 100} val, err = ls2.GetState(ctx, addr, common.Hash{100}) if err != nil { t.Fatalf("Error retrieving acc[%d].storage[100]: %v", i, err) } if val != exp { t.Fatalf("Retrieved wrong value from acc[%d].storage[100]: expected %04x, got %04x", i, exp, val) } } }