feat: add version state debug system

This commit is contained in:
joeycli 2024-08-18 16:21:06 +08:00
parent f67f494346
commit 23c60a38a4
9 changed files with 425 additions and 136 deletions

@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@ -286,8 +287,41 @@ WARNING: This is a low-level operation which may cause database corruption!`,
Description: `This commands will read current offset from kvdb, which is the current offset and starting BlockNumber
of ancientStore, will also displays the reserved number of blocks in ancientStore `,
}
getVersionDBState = &cli.Command{
Action: getDebugVersionState,
Name: "get-debug-version-state",
Flags: []cli.Flag{
utils.DataDirFlag,
utils.BlockNumber,
},
}
)
func getDebugVersionState(ctx *cli.Context) error {
if !ctx.IsSet(utils.DataDirFlag.Name) {
return fmt.Errorf("please set `--datadir` flag")
}
if !ctx.IsSet(utils.BlockNumber.Name) {
return fmt.Errorf("please set `--block` flag")
}
dir := ctx.String(utils.DataDirFlag.Name)
block := ctx.Int64(utils.BlockNumber.Name)
db, err := rawdb.Open(rawdb.OpenOptions{
ReadOnly: true,
Type: "leveldb",
Directory: dir,
})
if err != nil {
return err
}
data, err := db.Get(state.DebugStateKey(block))
if err != nil {
return err
}
fmt.Println(string(data))
return nil
}
func removeDB(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)

@ -272,6 +272,7 @@ func init() {
blsCommand,
// See verkle.go
verkleCommand,
getVersionDBState,
}
if logTestCommand != nil {
app.Commands = append(app.Commands, logTestCommand)

@ -1135,6 +1135,11 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: params.DefaultExtraReserveForBlobRequests,
Category: flags.MiscCategory,
}
BlockNumber = &cli.Int64Flag{
Name: "block",
Value: int64(0),
}
)
var (

@ -1815,23 +1815,6 @@ func (p *Parlia) applyTransaction(
}
actualTx := (*receivedTxs)[0]
if !bytes.Equal(p.signer.Hash(actualTx).Bytes(), expectedHash.Bytes()) {
res := fmt.Sprintf("expected tx hash %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s",
expectedHash.String(),
expectedTx.Nonce(),
expectedTx.To().String(),
expectedTx.Value().String(),
expectedTx.Gas(),
expectedTx.GasPrice().String(),
hex.EncodeToString(expectedTx.Data()))
res += fmt.Sprintf("actual tx hash %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s",
actualTx.Hash().String(),
actualTx.Nonce(),
actualTx.To().String(),
actualTx.Value().String(),
actualTx.Gas(),
actualTx.GasPrice().String(),
hex.EncodeToString(actualTx.Data()))
log.Info(res)
return fmt.Errorf("expected tx hash %v, get %v, nonce %d, to %s, value %s, gas %d, gasPrice %s, data %s", expectedHash.String(), actualTx.Hash().String(),
expectedTx.Nonce(),
expectedTx.To().String(),

@ -2241,9 +2241,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if parent == nil {
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
}
log.Info("+++++++++++++start block", "number", block.NumberU64())
defer log.Info("+++++++++++++end block", "number", block.NumberU64())
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
defer bc.stateCache.Release()
if err != nil {
@ -2289,7 +2287,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
log.Error("validate state failed", "error", err)
bc.reportBlock(block, receipts, err)
statedb.StopPrefetcher()
statedb.DebugPrint(block.NumberU64(), true)
return it.index, err
}
vtime := time.Since(vstart)

@ -34,6 +34,8 @@ type cachingVersaDB struct {
root common.Hash
mode versa.StateMode
hasState atomic.Bool
debug *DebugVersionState
}
// NewVersaDatabase should be call by NewDatabaseWithNodeDB
@ -47,6 +49,7 @@ func NewVersaDatabase(db ethdb.Database, triedb *triedb.Database, mode versa.Sta
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
mode: mode,
state: versa.ErrStateHandler,
debug: NewDebugVersionState(db, triedb.VersaDB()), // TODO:: add config whether enable debug system
}
}
@ -63,7 +66,9 @@ func (cv *cachingVersaDB) Copy() Database {
if cv.hasState.Load() {
_, err := cp.OpenTrie(cv.root)
if err != nil {
log.Error("failed to open trie in copy caching versa db", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy caching versa db, error: %s", err.Error()))
}
return cp
}
}
@ -85,14 +90,18 @@ func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
}
tree, err := cv.OpenTrie(vtr.root)
if err != nil {
log.Error("failed to open trie in CopyTrie", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy versa trie, error: %s", err.Error()))
}
return nil
}
return tree
} else {
tree, err := cv.OpenStorageTrie(vtr.stateRoot, vtr.address, vtr.root, nil)
if err != nil {
log.Error("failed to open storage trie in CopyTrie", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open storage trie in copy versa trie, error: %s", err.Error()))
}
return nil
}
return tree
@ -113,13 +122,25 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
// TODO:: if root tree, versa db should ignore check version, temp use -1
state, err := cv.versionDB.OpenState(-1, root, cv.mode)
if err != nil {
log.Error("failed to open state", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open state, root:%s, error: %s", root.String(), err.Error()))
}
return nil, err
}
if cv.debug != nil {
cv.debug.OnOpenState(state)
version, err := cv.versionDB.GetStateVersion(state)
if err != nil {
cv.debug.OnError(fmt.Errorf("failed to get state version, root:%s, error: %s", root.String(), err.Error()))
}
cv.debug.SetVersion(version)
}
handler, err := cv.versionDB.OpenTree(state, -1, common.Hash{}, root)
if err != nil {
log.Error("failed to open trie", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open account trie, root:%s, error: %s", root.String(), err.Error()))
}
return nil, err
}
@ -129,6 +150,7 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
accountTree: true,
root: root,
mode: cv.mode,
debug: cv.debug,
}
cv.state = state
@ -136,13 +158,16 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
cv.accTree = tree
cv.root = root
if cv.debug != nil {
cv.debug.OnOpenTree(handler, common.Hash{}, common.Address{})
}
return tree, nil
}
func (cv *cachingVersaDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, _ Trie) (Trie, error) {
version, _, err := cv.accTree.getAccountWithVersion(address)
if err != nil {
log.Error("failed to open storage trie", "error", err)
return nil, err
}
return cv.openStorageTreeWithVersion(version, stateRoot, address, root)
@ -157,35 +182,54 @@ func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot co
panic(fmt.Sprintf("account root mismatch, on open storage tree, actual: %s, expect: %s", root.String(), cv.root.String()))
}
handler, err := cv.versionDB.OpenTree(cv.state, version, crypto.Keccak256Hash(address.Bytes()), root)
owner := crypto.Keccak256Hash(address.Bytes())
handler, err := cv.versionDB.OpenTree(cv.state, version, owner, root)
if err != nil {
log.Error("failed to open storage trie", "error", err)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open storage trie, version: %d,stateRoot:%s, address:%s, root: %s, error: %s",
version, stateRoot.String(), address.String(), root.String(), err.Error()))
}
return nil, err
}
log.Info("open storage tree", "address", address.String(), "hash address", crypto.Keccak256Hash(address.Bytes()).String())
if cv.debug != nil {
cv.debug.OnOpenTree(handler, owner, address)
}
tree := &VersaTree{
db: cv.versionDB,
handler: handler,
version: version,
root: root,
stateRoot: stateRoot,
root: stateRoot,
stateRoot: root,
address: address,
mode: cv.mode,
debug: cv.debug,
}
return tree, nil
}
// Flush unique to versa
func (cv *cachingVersaDB) Flush() error {
return cv.versionDB.Flush(cv.state)
err := cv.versionDB.Flush(cv.state)
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to flush state, version: %d, root:%s, mode:%d, error: %s",
cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
}
return err
}
// Release unique to versa
func (cv *cachingVersaDB) Release() error {
//log.Info("close state", "state info", cv.versionDB.ParseStateHandler(cv.state))
if cv.state != versa.ErrStateHandler {
if cv.debug != nil {
cv.debug.OnCloseState(cv.state)
}
if err := cv.versionDB.CloseState(cv.state); err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to close state in release, version: %d, root:%s, mode:%d, error: %s",
cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
}
return err
}
cv.hasState.Store(false)
@ -220,6 +264,9 @@ func (cv *cachingVersaDB) Scheme() string {
}
func (cv *cachingVersaDB) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) {
if cv.debug != nil {
cv.debug.OnGetCode(codeHash)
}
code, _ := cv.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
@ -273,6 +320,7 @@ type VersaTree struct {
handler versa.TreeHandler
version int64
accountTree bool
debug *DebugVersionState
// TODO:: debugging, used for logging
stateRoot common.Hash
@ -291,9 +339,6 @@ func (vt *VersaTree) GetKey(key []byte) []byte {
func (vt *VersaTree) GetAccount(address common.Address) (*types.StateAccount, error) {
_, res, err := vt.getAccountWithVersion(address)
if err != nil {
log.Error("failed to get account", "error", err)
}
return res, err
}
@ -301,11 +346,23 @@ func (vt *VersaTree) getAccountWithVersion(address common.Address) (int64, *type
vt.CheckAccountTree()
ver, res, err := vt.db.Get(vt.handler, address.Bytes())
if res == nil || err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to get account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
return ver, nil, err
}
ret := new(types.StateAccount)
err = rlp.DecodeBytes(res, ret)
log.Info("get account", "mode", vt.mode, "addr", address.String(), "nonce", ret.Nonce, "balance", ret.Balance, "root", ret.Root.String(), "code", common.Bytes2Hex(ret.CodeHash), "version", ver)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to rlp decode account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnGetAccount(address, ret)
}
return ver, ret, err
}
@ -316,12 +373,21 @@ func (vt *VersaTree) GetStorage(address common.Address, key []byte) ([]byte, err
vt.CheckStorageTree()
_, enc, err := vt.db.Get(vt.handler, key)
if err != nil || len(enc) == 0 {
if err != nil && vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to get storage, root: %s, stateRoot: %s, address:%s, key: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
return nil, err
}
_, content, _, err := rlp.Split(enc)
log.Info("get storage", "mode", vt.mode, "handler", vt.handler, "owner", address.String(), "key", common.Bytes2Hex(key), "val", common.Bytes2Hex(content), "stateRoot", vt.stateRoot.String(), "root", vt.root.String(), "version", vt.version)
if err != nil {
log.Error("failed to get storage", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to rlp decode storage, root: %s, stateRoot: %s, address: %s, key: %s,error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnGetStorage(vt.handler, address, key, content)
}
return content, err
}
@ -330,10 +396,15 @@ func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateA
vt.CheckAccountTree()
data, err := rlp.EncodeToBytes(account)
if err != nil {
log.Error("failed to update account", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to update account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
return err
}
log.Info("update account", "mode", vt.mode, "addr", address.String(), "nonce", account.Nonce, "balance", account.Balance, "root", account.Root.String(), "code", common.Bytes2Hex(account.CodeHash))
if vt.debug != nil {
vt.debug.OnUpdateAccount(address, account)
}
return vt.db.Put(vt.handler, address.Bytes(), data)
}
@ -343,10 +414,15 @@ func (vt *VersaTree) UpdateStorage(address common.Address, key, value []byte) er
}
vt.CheckStorageTree()
v, _ := rlp.EncodeToBytes(value)
log.Info("update storage", "mode", vt.mode, "handler", vt.handler, "owner", address.String(), "key", common.Bytes2Hex(key), "val", common.Bytes2Hex(value), "stateRoot", vt.stateRoot.String(), "root", vt.root.String())
err := vt.db.Put(vt.handler, key, v)
if err != nil {
log.Error("failed to update storage", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to update storage, root: %s, stateRoot: %s, address: %s, key: %s, val: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnUpdateStorage(vt.handler, address, key, value)
}
return err
}
@ -355,9 +431,14 @@ func (vt *VersaTree) DeleteAccount(address common.Address) error {
vt.CheckAccountTree()
err := vt.db.Delete(vt.handler, address.Bytes())
if err != nil {
log.Error("failed to delete account", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to delete account, root: %s, address: %s, error: %s",
vt.root.String(), address.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnDeleteAccount(address)
}
log.Info("delete account", "mode", vt.mode, "addr", address.String())
return err
}
@ -365,9 +446,14 @@ func (vt *VersaTree) DeleteStorage(address common.Address, key []byte) error {
vt.CheckStorageTree()
err := vt.db.Delete(vt.handler, key)
if err != nil {
log.Error("failed to delete storage", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to delete storage, root: %s, stateRoot: %s, address: %s, key: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnDeleteStorage(vt.handler, address, key)
}
log.Info("delete storage", "mode", vt.mode, "handler", vt.handler, "owner", address.String(), "key", common.Bytes2Hex(key), "stateRoot", vt.stateRoot.String(), "root", vt.root.String())
return err
}
@ -378,8 +464,10 @@ func (vt *VersaTree) UpdateContractCode(address common.Address, codeHash common.
func (vt *VersaTree) Hash() common.Hash {
hash, err := vt.db.CalcRootHash(vt.handler)
if err != nil {
// TODO:: debug code, will be change to log error
log.Crit("calc tree root hash", "tree handler info", vt.db.ParseTreeHandler(vt.handler), "error", err.Error())
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to calc root, root: %s, stateRoot%s, error:%s",
vt.root.String(), vt.stateRoot.String(), err.Error()))
}
}
return hash
}
@ -387,7 +475,13 @@ func (vt *VersaTree) Hash() common.Hash {
func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
hash, err := vt.db.Commit(vt.handler)
if err != nil {
log.Warn("failed to commit versa tree", "error", err)
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to commit versa tree, root: %s, stateRoot: %s, error: %s",
vt.root.String(), vt.stateRoot.String(), err.Error()))
}
}
if vt.debug != nil {
vt.debug.OnCommitTree(vt.handler)
}
return hash, nil, err
}

@ -1509,90 +1509,6 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
return incomplete, nil
}
func (s *StateDB) DebugPrint(block uint64, deleteEmptyObjects bool) {
if block != 373559 {
return
}
log.Info("================== block start ===============", "number", block)
hash := s.IntermediateRoot(deleteEmptyObjects)
log.Info("mpt root", "hash", hash)
addrs := make([]common.Address, 0)
for addr := range s.stateObjectsDirty {
if _, ok := s.stateObjects[addr]; ok {
addrs = append(addrs, addr)
}
}
sort.SliceStable(addrs, func(i, j int) bool {
return addrs[i].Cmp(addrs[j]) < 0
})
for _, addr := range addrs {
obj := s.stateObjects[addr]
log.Info("state object", "address", obj.address)
log.Info("state object", "addrHash", obj.addrHash)
log.Info("state object", "dirtyCode", obj.dirtyCode)
log.Info("state object", "selfDestructed", obj.selfDestructed)
log.Info("state object", "deleted", obj.deleted)
log.Info("state object", "created", obj.created)
log.Info("....................origin state object .......................")
if obj.origin != nil {
log.Info("state object origin", "Nonce", obj.origin.Nonce)
log.Info("state object origin", "Balance", obj.origin.Balance)
log.Info("state object origin", "Root", obj.origin.Root)
log.Info("state object origin", "CodeHash", common.Bytes2Hex(obj.origin.CodeHash))
} else {
log.Info("state object origin is nil")
}
log.Info("....................new state object.......................")
log.Info("state object new", "Nonce", obj.data.Nonce)
log.Info("state object new", "Balance", obj.data.Balance)
log.Info("state object new", "Root", obj.data.Root)
log.Info("state object new", "CodeHash", common.Bytes2Hex(obj.data.CodeHash))
log.Info("....................tree handler.......................")
if obj.trie != nil {
vtr := obj.trie.(*VersaTree)
log.Info(vtr.db.ParseTreeHandler(vtr.handler))
}
log.Info("....................originStorage.......................")
keys := make([]common.Hash, 0)
for key := range obj.originStorage {
keys = append(keys, key)
}
sort.SliceStable(keys, func(i, j int) bool {
return keys[i].Cmp(keys[j]) < 0
})
for _, k := range keys {
log.Info("originStorage,", "key: ", k.String(), "val: ", obj.originStorage[k].String())
}
log.Info("....................pendingStorage.......................")
keys = make([]common.Hash, 0)
for key := range obj.pendingStorage {
keys = append(keys, key)
}
sort.SliceStable(keys, func(i, j int) bool {
return keys[i].Cmp(keys[j]) < 0
})
for _, k := range keys {
log.Info("originStorage,", "key: ", k.String(), "val: ", obj.pendingStorage[k].String())
}
log.Info("..................dirtyStorage.........................")
keys = make([]common.Hash, 0)
for key := range obj.dirtyStorage {
keys = append(keys, key)
}
sort.SliceStable(keys, func(i, j int) bool {
return keys[i].Cmp(keys[j]) < 0
})
for _, k := range keys {
log.Info("originStorage,", "key: ", k.String(), "val: ", obj.dirtyStorage[k].String())
}
log.Info("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^")
}
log.Info("================== block end ================", "number", block)
log.Crit("exit....")
}
// Once the state is committed, tries cached in stateDB (including account
// trie, storage tries) will no longer be functional. A new state instance
// must be created with new root and updated database for accessing post-

255
core/state/statedb_debug.go Normal file

@ -0,0 +1,255 @@
package state
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"sync"
versa "github.com/bnb-chain/versioned-state-database"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)
type VersaAccountInfo struct {
Address common.Address
Account *types.StateAccount
}
type VersaStorageInfo struct {
Handler versa.TreeHandler
Address common.Address
Key string
Val string
}
type DebugVersionState struct {
disk ethdb.KeyValueStore
versionDB versa.Database
lock sync.Mutex
Version int64
PreState *versa.StateInfo
PostState *versa.StateInfo
AccessTrees []*versa.TreeInfo
CommitTrees []versa.TreeHandler
GetAccounts []*VersaAccountInfo
UpdateAccounts []*VersaAccountInfo
DeleteAccounts []common.Address
GetStorage []*VersaStorageInfo
UpdateStorage []*VersaStorageInfo
DeleteStorage []*VersaStorageInfo
StorageAddr2Owner map[common.Address]common.Hash
GetCode []common.Hash
UpdateCode []common.Hash
Errs []string
}
func NewDebugVersionState(disk ethdb.KeyValueStore, versionDB versa.Database) *DebugVersionState {
return &DebugVersionState{
disk: disk,
versionDB: versionDB,
AccessTrees: make([]*versa.TreeInfo, 0),
CommitTrees: make([]versa.TreeHandler, 0),
GetAccounts: make([]*VersaAccountInfo, 0),
UpdateAccounts: make([]*VersaAccountInfo, 0),
DeleteAccounts: make([]common.Address, 0),
GetStorage: make([]*VersaStorageInfo, 0),
UpdateStorage: make([]*VersaStorageInfo, 0),
DeleteStorage: make([]*VersaStorageInfo, 0),
StorageAddr2Owner: make(map[common.Address]common.Hash),
GetCode: make([]common.Hash, 0),
UpdateCode: make([]common.Hash, 0),
}
}
func (ds *DebugVersionState) SetVersion(version int64) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.Version = version
}
func (ds *DebugVersionState) OnOpenState(handler versa.StateHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
stateInfo, err := ds.versionDB.GetStateInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get state info on open state, err: %s", err.Error()))
}
ds.PreState = stateInfo
}
func (ds *DebugVersionState) OnOpenTree(handler versa.TreeHandler, owner common.Hash, address common.Address) {
ds.lock.Lock()
defer ds.lock.Unlock()
treeInfo, err := ds.versionDB.GetTreeInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get tree info on open tree, err: %s", err.Error()))
}
ds.AccessTrees = append(ds.AccessTrees, treeInfo)
if owner != (common.Hash{}) && address != (common.Address{}) {
ds.StorageAddr2Owner[address] = owner
}
}
func (ds *DebugVersionState) OnGetAccount(addr common.Address, acc *types.StateAccount) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.GetAccounts = append(ds.GetAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (ds *DebugVersionState) OnUpdateAccount(addr common.Address, acc *types.StateAccount) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.UpdateAccounts = append(ds.UpdateAccounts, &VersaAccountInfo{
Address: addr,
Account: acc,
})
}
func (ds *DebugVersionState) OnDeleteAccount(address common.Address) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.DeleteAccounts = append(ds.DeleteAccounts, address)
}
func (ds *DebugVersionState) OnGetStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.GetStorage = append(ds.GetStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (ds *DebugVersionState) OnUpdateStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.UpdateStorage = append(ds.UpdateStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
Val: common.Bytes2Hex(val),
})
}
func (ds *DebugVersionState) OnDeleteStorage(handler versa.TreeHandler, address common.Address, key []byte) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.DeleteStorage = append(ds.DeleteStorage, &VersaStorageInfo{
Handler: handler,
Address: address,
Key: common.Bytes2Hex(key),
})
}
func (ds *DebugVersionState) OnGetCode(codeHash common.Hash) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.GetCode = append(ds.GetCode, codeHash)
}
func (ds *DebugVersionState) OnUpdateCode(codeHash common.Hash) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.UpdateCode = append(ds.UpdateCode, codeHash)
}
func (ds *DebugVersionState) OnCommitTree(handler versa.TreeHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.CommitTrees = append(ds.CommitTrees, handler)
}
func (ds *DebugVersionState) OnError(err error) {
ds.lock.Lock()
defer ds.lock.Unlock()
ds.Errs = append(ds.Errs, err.Error())
}
func (ds *DebugVersionState) OnCloseState(handler versa.StateHandler) {
ds.lock.Lock()
defer ds.lock.Unlock()
stateInfo, err := ds.versionDB.GetStateInfo(handler)
if err != nil {
panic(fmt.Sprintf("failed to get state info on close state, err: %s", err.Error()))
}
ds.PostState = stateInfo
data, err := json.Marshal(ds)
if err != nil {
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
}
if len(ds.Errs) != 0 {
log.Info("version state occurs error", "debug info", string(data))
log.Crit("exit....")
}
err = ds.disk.Put(DebugStateKey(ds.Version), data)
if err != nil {
panic(fmt.Sprintf("failed to put debug version state into disk, err: %s", err.Error()))
}
}
func (ds *DebugVersionState) sortItems() {
sort.Slice(ds.GetAccounts, func(i, j int) bool {
return ds.GetAccounts[i].Address.Cmp(ds.GetAccounts[j].Address) < 0
})
sort.Slice(ds.UpdateAccounts, func(i, j int) bool {
return ds.UpdateAccounts[i].Address.Cmp(ds.UpdateAccounts[j].Address) < 0
})
sort.Slice(ds.DeleteAccounts, func(i, j int) bool {
return ds.DeleteAccounts[i].Cmp(ds.DeleteAccounts[j]) < 0
})
sort.Slice(ds.GetStorage, func(i, j int) bool {
if ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) == 0 {
return ds.GetStorage[i].Key < ds.GetStorage[j].Key
}
return ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) < 0
})
sort.Slice(ds.UpdateStorage, func(i, j int) bool {
if ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) == 0 {
return ds.UpdateStorage[i].Key < ds.UpdateStorage[j].Key
}
return ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) < 0
})
sort.Slice(ds.DeleteStorage, func(i, j int) bool {
if ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) == 0 {
return ds.DeleteStorage[i].Key < ds.DeleteStorage[j].Key
}
return ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) < 0
})
sort.Slice(ds.GetCode, func(i, j int) bool {
return ds.GetCode[i].Cmp(ds.GetCode[j]) < 0
})
sort.Slice(ds.UpdateCode, func(i, j int) bool {
return ds.UpdateCode[i].Cmp(ds.UpdateCode[j]) < 0
})
}
func DebugStateKey(version int64) []byte {
key := "debug_version_prefix" + strconv.FormatInt(version, 10)
return []byte(key)
}

@ -126,11 +126,15 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
onlyFullSync := false
if config.StateScheme == rawdb.VersionScheme {
config.SnapshotCache = 0
log.Info("version triedb has forbidden snapshot")
onlyFullSync = true
config.SyncMode = downloader.FullSync
log.Info("version triedb only support full sync")
}
// TODO:: debug code
config.SnapshotCache = 0
onlyFullSync = true
config.SyncMode = downloader.FullSync
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")