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/common/hexutil"
"github.com/ethereum/go-ethereum/console/prompt" "github.com/ethereum/go-ethereum/console/prompt"
"github.com/ethereum/go-ethereum/core/rawdb" "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/core/state/snapshot"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "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 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 `, 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 { func removeDB(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx) stack, config := makeConfigNode(ctx)

@ -272,6 +272,7 @@ func init() {
blsCommand, blsCommand,
// See verkle.go // See verkle.go
verkleCommand, verkleCommand,
getVersionDBState,
} }
if logTestCommand != nil { if logTestCommand != nil {
app.Commands = append(app.Commands, logTestCommand) 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, Value: params.DefaultExtraReserveForBlobRequests,
Category: flags.MiscCategory, Category: flags.MiscCategory,
} }
BlockNumber = &cli.Int64Flag{
Name: "block",
Value: int64(0),
}
) )
var ( var (

@ -1815,23 +1815,6 @@ func (p *Parlia) applyTransaction(
} }
actualTx := (*receivedTxs)[0] actualTx := (*receivedTxs)[0]
if !bytes.Equal(p.signer.Hash(actualTx).Bytes(), expectedHash.Bytes()) { 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(), 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.Nonce(),
expectedTx.To().String(), expectedTx.To().String(),

@ -2242,8 +2242,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) 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) statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
defer bc.stateCache.Release() defer bc.stateCache.Release()
if err != nil { 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) log.Error("validate state failed", "error", err)
bc.reportBlock(block, receipts, err) bc.reportBlock(block, receipts, err)
statedb.StopPrefetcher() statedb.StopPrefetcher()
statedb.DebugPrint(block.NumberU64(), true)
return it.index, err return it.index, err
} }
vtime := time.Since(vstart) vtime := time.Since(vstart)

@ -34,6 +34,8 @@ type cachingVersaDB struct {
root common.Hash root common.Hash
mode versa.StateMode mode versa.StateMode
hasState atomic.Bool hasState atomic.Bool
debug *DebugVersionState
} }
// NewVersaDatabase should be call by NewDatabaseWithNodeDB // 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), codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
mode: mode, mode: mode,
state: versa.ErrStateHandler, 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() { if cv.hasState.Load() {
_, err := cp.OpenTrie(cv.root) _, err := cp.OpenTrie(cv.root)
if err != nil { 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 return cp
} }
} }
@ -85,14 +90,18 @@ func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
} }
tree, err := cv.OpenTrie(vtr.root) tree, err := cv.OpenTrie(vtr.root)
if err != nil { 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 nil
} }
return tree return tree
} else { } else {
tree, err := cv.OpenStorageTrie(vtr.stateRoot, vtr.address, vtr.root, nil) tree, err := cv.OpenStorageTrie(vtr.stateRoot, vtr.address, vtr.root, nil)
if err != 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 nil
} }
return tree 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 // TODO:: if root tree, versa db should ignore check version, temp use -1
state, err := cv.versionDB.OpenState(-1, root, cv.mode) state, err := cv.versionDB.OpenState(-1, root, cv.mode)
if err != nil { 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 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) handler, err := cv.versionDB.OpenTree(state, -1, common.Hash{}, root)
if err != nil { 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 return nil, err
} }
@ -129,6 +150,7 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
accountTree: true, accountTree: true,
root: root, root: root,
mode: cv.mode, mode: cv.mode,
debug: cv.debug,
} }
cv.state = state cv.state = state
@ -136,13 +158,16 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
cv.accTree = tree cv.accTree = tree
cv.root = root cv.root = root
if cv.debug != nil {
cv.debug.OnOpenTree(handler, common.Hash{}, common.Address{})
}
return tree, nil return tree, nil
} }
func (cv *cachingVersaDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, _ Trie) (Trie, error) { func (cv *cachingVersaDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, _ Trie) (Trie, error) {
version, _, err := cv.accTree.getAccountWithVersion(address) version, _, err := cv.accTree.getAccountWithVersion(address)
if err != nil { if err != nil {
log.Error("failed to open storage trie", "error", err)
return nil, err return nil, err
} }
return cv.openStorageTreeWithVersion(version, stateRoot, address, root) 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())) 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 { 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 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{ tree := &VersaTree{
db: cv.versionDB, db: cv.versionDB,
handler: handler, handler: handler,
version: version, version: version,
root: root, root: stateRoot,
stateRoot: stateRoot, stateRoot: root,
address: address, address: address,
mode: cv.mode, mode: cv.mode,
debug: cv.debug,
} }
return tree, nil return tree, nil
} }
// Flush unique to versa // Flush unique to versa
func (cv *cachingVersaDB) Flush() error { 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 // Release unique to versa
func (cv *cachingVersaDB) Release() error { func (cv *cachingVersaDB) Release() error {
//log.Info("close state", "state info", cv.versionDB.ParseStateHandler(cv.state)) //log.Info("close state", "state info", cv.versionDB.ParseStateHandler(cv.state))
if cv.state != versa.ErrStateHandler { if cv.state != versa.ErrStateHandler {
if cv.debug != nil {
cv.debug.OnCloseState(cv.state)
}
if err := cv.versionDB.CloseState(cv.state); err != nil { 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 return err
} }
cv.hasState.Store(false) 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) { 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) code, _ := cv.codeCache.Get(codeHash)
if len(code) > 0 { if len(code) > 0 {
return code, nil return code, nil
@ -273,6 +320,7 @@ type VersaTree struct {
handler versa.TreeHandler handler versa.TreeHandler
version int64 version int64
accountTree bool accountTree bool
debug *DebugVersionState
// TODO:: debugging, used for logging // TODO:: debugging, used for logging
stateRoot common.Hash stateRoot common.Hash
@ -291,9 +339,6 @@ func (vt *VersaTree) GetKey(key []byte) []byte {
func (vt *VersaTree) GetAccount(address common.Address) (*types.StateAccount, error) { func (vt *VersaTree) GetAccount(address common.Address) (*types.StateAccount, error) {
_, res, err := vt.getAccountWithVersion(address) _, res, err := vt.getAccountWithVersion(address)
if err != nil {
log.Error("failed to get account", "error", err)
}
return res, err return res, err
} }
@ -301,11 +346,23 @@ func (vt *VersaTree) getAccountWithVersion(address common.Address) (int64, *type
vt.CheckAccountTree() vt.CheckAccountTree()
ver, res, err := vt.db.Get(vt.handler, address.Bytes()) ver, res, err := vt.db.Get(vt.handler, address.Bytes())
if res == nil || err != nil { 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 return ver, nil, err
} }
ret := new(types.StateAccount) ret := new(types.StateAccount)
err = rlp.DecodeBytes(res, ret) 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 return ver, ret, err
} }
@ -316,12 +373,21 @@ func (vt *VersaTree) GetStorage(address common.Address, key []byte) ([]byte, err
vt.CheckStorageTree() vt.CheckStorageTree()
_, enc, err := vt.db.Get(vt.handler, key) _, enc, err := vt.db.Get(vt.handler, key)
if err != nil || len(enc) == 0 { 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 return nil, err
} }
_, content, _, err := rlp.Split(enc) _, 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 { 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 return content, err
} }
@ -330,10 +396,15 @@ func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateA
vt.CheckAccountTree() vt.CheckAccountTree()
data, err := rlp.EncodeToBytes(account) data, err := rlp.EncodeToBytes(account)
if err != nil { 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 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) 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() vt.CheckStorageTree()
v, _ := rlp.EncodeToBytes(value) 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) err := vt.db.Put(vt.handler, key, v)
if err != nil { 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 return err
} }
@ -355,9 +431,14 @@ func (vt *VersaTree) DeleteAccount(address common.Address) error {
vt.CheckAccountTree() vt.CheckAccountTree()
err := vt.db.Delete(vt.handler, address.Bytes()) err := vt.db.Delete(vt.handler, address.Bytes())
if err != nil { 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 return err
} }
@ -365,9 +446,14 @@ func (vt *VersaTree) DeleteStorage(address common.Address, key []byte) error {
vt.CheckStorageTree() vt.CheckStorageTree()
err := vt.db.Delete(vt.handler, key) err := vt.db.Delete(vt.handler, key)
if err != nil { 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 return err
} }
@ -378,8 +464,10 @@ func (vt *VersaTree) UpdateContractCode(address common.Address, codeHash common.
func (vt *VersaTree) Hash() common.Hash { func (vt *VersaTree) Hash() common.Hash {
hash, err := vt.db.CalcRootHash(vt.handler) hash, err := vt.db.CalcRootHash(vt.handler)
if err != nil { if err != nil {
// TODO:: debug code, will be change to log error if vt.debug != nil {
log.Crit("calc tree root hash", "tree handler info", vt.db.ParseTreeHandler(vt.handler), "error", err.Error()) 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 return hash
} }
@ -387,7 +475,13 @@ func (vt *VersaTree) Hash() common.Hash {
func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
hash, err := vt.db.Commit(vt.handler) hash, err := vt.db.Commit(vt.handler)
if err != nil { 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 return hash, nil, err
} }

@ -1509,90 +1509,6 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
return incomplete, nil 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 // Once the state is committed, tries cached in stateDB (including account
// trie, storage tries) will no longer be functional. A new state instance // trie, storage tries) will no longer be functional. A new state instance
// must be created with new root and updated database for accessing post- // 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 onlyFullSync := false
if config.StateScheme == rawdb.VersionScheme { if config.StateScheme == rawdb.VersionScheme {
config.SnapshotCache = 0 config.SnapshotCache = 0
log.Info("version triedb has forbidden snapshot")
onlyFullSync = true onlyFullSync = true
config.SyncMode = downloader.FullSync 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 // Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync { if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated") return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")