mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
Previously, the account trie for a given state root was resolved immediately when the stateDB was created, implying that the trie was always required by the stateDB. However, this assumption no longer holds, especially for path archive nodes, where historical states can be accessed even if the corresponding trie data does not exist.
207 lines
8.6 KiB
Go
207 lines
8.6 KiB
Go
// Copyright 2014 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package state
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/triedb"
|
|
"github.com/holiman/uint256"
|
|
)
|
|
|
|
type stateEnv struct {
|
|
state *StateDB
|
|
}
|
|
|
|
func newStateEnv() *stateEnv {
|
|
sdb, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
|
return &stateEnv{state: sdb}
|
|
}
|
|
|
|
func TestDump(t *testing.T) {
|
|
db := rawdb.NewMemoryDatabase()
|
|
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
|
tdb := NewDatabase(triedb, nil)
|
|
sdb, _ := New(types.EmptyRootHash, tdb)
|
|
s := &stateEnv{state: sdb}
|
|
|
|
// generate a few entries
|
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
|
obj1.AddBalance(uint256.NewInt(22))
|
|
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
|
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
|
|
obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
|
obj3.SetBalance(uint256.NewInt(44))
|
|
|
|
// write some of them to the trie
|
|
root, _ := s.state.Commit(0, false, false)
|
|
|
|
// check that DumpToCollector contains the state objects that are in trie
|
|
s.state, _ = New(root, tdb)
|
|
got := string(s.state.Dump(nil))
|
|
want := `{
|
|
"root": "71edff0130dd2385947095001c73d9e28d862fc286fca2b922ca6f6f3cddfdd2",
|
|
"accounts": {
|
|
"0x0000000000000000000000000000000000000001": {
|
|
"balance": "22",
|
|
"nonce": 0,
|
|
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
|
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
"address": "0x0000000000000000000000000000000000000001",
|
|
"key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"
|
|
},
|
|
"0x0000000000000000000000000000000000000002": {
|
|
"balance": "44",
|
|
"nonce": 0,
|
|
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
|
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
|
"address": "0x0000000000000000000000000000000000000002",
|
|
"key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"
|
|
},
|
|
"0x0000000000000000000000000000000000000102": {
|
|
"balance": "0",
|
|
"nonce": 0,
|
|
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
|
"codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
|
|
"code": "0x03030303030303",
|
|
"address": "0x0000000000000000000000000000000000000102",
|
|
"key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"
|
|
}
|
|
}
|
|
}`
|
|
if got != want {
|
|
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
func TestIterativeDump(t *testing.T) {
|
|
db := rawdb.NewMemoryDatabase()
|
|
triedb := triedb.NewDatabase(db, &triedb.Config{Preimages: true})
|
|
tdb := NewDatabase(triedb, nil)
|
|
sdb, _ := New(types.EmptyRootHash, tdb)
|
|
s := &stateEnv{state: sdb}
|
|
|
|
// generate a few entries
|
|
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
|
|
obj1.AddBalance(uint256.NewInt(22))
|
|
obj2 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
|
|
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
|
|
obj3 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x02}))
|
|
obj3.SetBalance(uint256.NewInt(44))
|
|
obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
|
|
obj4.AddBalance(uint256.NewInt(1337))
|
|
|
|
// write some of them to the trie
|
|
root, _ := s.state.Commit(0, false, false)
|
|
s.state, _ = New(root, tdb)
|
|
|
|
b := &bytes.Buffer{}
|
|
s.state.IterativeDump(nil, json.NewEncoder(b))
|
|
// check that DumpToCollector contains the state objects that are in trie
|
|
got := b.String()
|
|
want := `{"root":"0xd5710ea8166b7b04bc2bfb129d7db12931cee82f75ca8e2d075b4884322bf3de"}
|
|
{"balance":"22","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000001","key":"0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"}
|
|
{"balance":"1337","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000000","key":"0x5380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312a"}
|
|
{"balance":"0","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3","code":"0x03030303030303","address":"0x0000000000000000000000000000000000000102","key":"0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"}
|
|
{"balance":"44","nonce":0,"root":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","codeHash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","address":"0x0000000000000000000000000000000000000002","key":"0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"}
|
|
`
|
|
if got != want {
|
|
t.Errorf("DumpToCollector mismatch:\ngot: %s\nwant: %s\n", got, want)
|
|
}
|
|
}
|
|
|
|
func TestNull(t *testing.T) {
|
|
s := newStateEnv()
|
|
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
|
|
s.state.CreateAccount(address)
|
|
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
|
var value common.Hash
|
|
|
|
s.state.SetState(address, common.Hash{}, value)
|
|
s.state.Commit(0, false, false)
|
|
|
|
if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) {
|
|
t.Errorf("expected empty current value, got %x", value)
|
|
}
|
|
if value := s.state.GetCommittedState(address, common.Hash{}); value != (common.Hash{}) {
|
|
t.Errorf("expected empty committed value, got %x", value)
|
|
}
|
|
}
|
|
|
|
func TestSnapshot(t *testing.T) {
|
|
stateobjaddr := common.BytesToAddress([]byte("aa"))
|
|
var storageaddr common.Hash
|
|
data1 := common.BytesToHash([]byte{42})
|
|
data2 := common.BytesToHash([]byte{43})
|
|
s := newStateEnv()
|
|
|
|
// snapshot the genesis state
|
|
genesis := s.state.Snapshot()
|
|
|
|
// set initial state object value
|
|
s.state.SetState(stateobjaddr, storageaddr, data1)
|
|
snapshot := s.state.Snapshot()
|
|
|
|
// set a new state object value, revert it and ensure correct content
|
|
s.state.SetState(stateobjaddr, storageaddr, data2)
|
|
s.state.RevertToSnapshot(snapshot)
|
|
|
|
if v := s.state.GetState(stateobjaddr, storageaddr); v != data1 {
|
|
t.Errorf("wrong storage value %v, want %v", v, data1)
|
|
}
|
|
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
|
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
|
|
}
|
|
|
|
// revert up to the genesis state and ensure correct content
|
|
s.state.RevertToSnapshot(genesis)
|
|
if v := s.state.GetState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
|
t.Errorf("wrong storage value %v, want %v", v, common.Hash{})
|
|
}
|
|
if v := s.state.GetCommittedState(stateobjaddr, storageaddr); v != (common.Hash{}) {
|
|
t.Errorf("wrong committed storage value %v, want %v", v, common.Hash{})
|
|
}
|
|
}
|
|
|
|
func TestSnapshotEmpty(t *testing.T) {
|
|
s := newStateEnv()
|
|
s.state.RevertToSnapshot(s.state.Snapshot())
|
|
}
|
|
|
|
func TestCreateObjectRevert(t *testing.T) {
|
|
state, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
|
|
addr := common.BytesToAddress([]byte("so0"))
|
|
snap := state.Snapshot()
|
|
|
|
state.CreateAccount(addr)
|
|
so0 := state.getStateObject(addr)
|
|
so0.SetBalance(uint256.NewInt(42))
|
|
so0.SetNonce(43)
|
|
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
|
|
state.setStateObject(so0)
|
|
|
|
state.RevertToSnapshot(snap)
|
|
if state.Exist(addr) {
|
|
t.Error("Unexpected account after revert")
|
|
}
|
|
}
|