feat: add version state debug system
This commit is contained in:
parent
f67f494346
commit
23c60a38a4
@ -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(),
|
||||
|
@ -2242,8 +2242,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
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
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")
|
||||
|
Loading…
Reference in New Issue
Block a user