Compare commits

...

2 Commits

Author SHA1 Message Date
joeycli
0af2fb4324 feat: support rewind for versa db
fix: rewind ancient store
2024-09-02 17:32:56 +08:00
joeycli
3e8e74d5c2 feat: delete statedb debug system 2024-08-27 09:29:24 +08:00
6 changed files with 468 additions and 400 deletions

View File

@@ -424,78 +424,101 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// Make sure the state associated with the block is available, or log out
// if there is no available state, waiting for state sync.
head := bc.CurrentBlock()
if !bc.HasState(head.Root) {
if head.Number.Uint64() == 0 {
// The genesis state is missing, which is only possible in the path-based
// scheme. This situation occurs when the initial state sync is not finished
// yet, or the chain head is rewound below the pivot point. In both scenarios,
// there is no possible recovery approach except for rerunning a snap sync.
// Do nothing here until the state syncer picks it up.
log.Info("Genesis state is missing, wait state sync")
} else {
// Head state is missing, before the state recovery, find out the
// disk layer point of snapshot(if it's enabled). Make sure the
// rewound point is lower than disk layer.
var diskRoot common.Hash
if bc.cacheConfig.SnapshotLimit > 0 {
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
}
if bc.triedb.Scheme() == rawdb.PathScheme && !bc.NoTries() {
recoverable, _ := bc.triedb.Recoverable(diskRoot)
if !bc.HasState(diskRoot) && !recoverable {
diskRoot = bc.triedb.Head()
}
}
if diskRoot != (common.Hash{}) {
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
if err != nil {
return nil, err
}
// Chain rewound, persist old snapshot number to indicate recovery procedure
if snapDisk != 0 {
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
}
if bc.triedb.Scheme() != rawdb.VersionScheme {
if !bc.HasState(head.Root) {
if head.Number.Uint64() == 0 {
// The genesis state is missing, which is only possible in the path-based
// scheme. This situation occurs when the initial state sync is not finished
// yet, or the chain head is rewound below the pivot point. In both scenarios,
// there is no possible recovery approach except for rerunning a snap sync.
// Do nothing here until the state syncer picks it up.
log.Info("Genesis state is missing, wait state sync")
} else {
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil {
// Head state is missing, before the state recovery, find out the
// disk layer point of snapshot(if it's enabled). Make sure the
// rewound point is lower than disk layer.
var diskRoot common.Hash
if bc.cacheConfig.SnapshotLimit > 0 {
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
}
if bc.triedb.Scheme() == rawdb.PathScheme && !bc.NoTries() {
recoverable, _ := bc.triedb.Recoverable(diskRoot)
if !bc.HasState(diskRoot) && !recoverable {
diskRoot = bc.triedb.Head()
}
}
if diskRoot != (common.Hash{}) {
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
if err != nil {
return nil, err
}
// Chain rewound, persist old snapshot number to indicate recovery procedure
if snapDisk != 0 {
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
}
} else {
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil {
return nil, err
}
}
}
}
} else {
log.Warn("versa db no recovery, rewind in load state")
}
// Ensure that a previous crash in SetHead doesn't leave extra ancients
if bc.triedb.Scheme() != rawdb.VersionScheme {
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.BlockStore().Ancients()
if err != nil {
return nil, err
}
var (
needRewind bool
low uint64
)
// The head full block may be rolled back to a very low height due to
// blockchain repair. If the head full block is even lower than the ancient
// chain, truncate the ancient store.
fullBlock := bc.CurrentBlock()
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
needRewind = true
low = fullBlock.Number.Uint64()
}
// In snap sync, it may happen that ancient data has been written to the
// ancient store, but the LastFastBlock has not been updated, truncate the
// extra data here.
snapBlock := bc.CurrentSnapBlock()
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
needRewind = true
if snapBlock.Number.Uint64() < low || low == 0 {
low = snapBlock.Number.Uint64()
}
}
if needRewind {
log.Error("Truncating ancient chain", "from", bc.CurrentHeader().Number.Uint64(), "to", low)
if err := bc.SetHead(low); err != nil {
return nil, err
}
}
}
}
// Ensure that a previous crash in SetHead doesn't leave extra ancients
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.BlockStore().Ancients()
} else {
//TODO:: need consider the offline and inline prune block
frozen, err := bc.db.BlockStore().Ancients()
if err != nil {
return nil, err
}
items, err := bc.db.BlockStore().ItemAmountInAncient()
if err != nil {
return nil, err
}
var (
needRewind bool
low uint64
)
// The head full block may be rolled back to a very low height due to
// blockchain repair. If the head full block is even lower than the ancient
// chain, truncate the ancient store.
fullBlock := bc.CurrentBlock()
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
needRewind = true
low = fullBlock.Number.Uint64()
}
// In snap sync, it may happen that ancient data has been written to the
// ancient store, but the LastFastBlock has not been updated, truncate the
// extra data here.
snapBlock := bc.CurrentSnapBlock()
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
needRewind = true
if snapBlock.Number.Uint64() < low || low == 0 {
low = snapBlock.Number.Uint64()
}
}
if needRewind {
log.Error("Truncating ancient chain", "from", bc.CurrentHeader().Number.Uint64(), "to", low)
if err := bc.SetHead(low); err != nil {
log.Info("version mode rewind ancient store", "target", fullBlock.Number.Uint64(), "old head", frozen, "items", items, "offset", bc.db.BlockStore().AncientOffSet())
if frozen >= fullBlock.Number.Uint64() {
if _, err = bc.db.BlockStore().TruncateTail(fullBlock.Number.Uint64()); err != nil {
return nil, err
}
}
@@ -702,20 +725,54 @@ func (bc *BlockChain) getFinalizedNumber(header *types.Header) uint64 {
// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
func (bc *BlockChain) loadLastState() error {
// Restore the last known head block
head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) {
// Corrupt or empty database, init from scratch
log.Warn("Empty database, resetting chain")
return bc.Reset()
}
// Make sure the entire head block is available
headBlock := bc.GetBlockByHash(head)
if headBlock == nil {
// Corrupt or empty database, init from scratch
log.Warn("Head block missing, resetting chain", "hash", head)
return bc.Reset()
// TODO:: before versa db support recovery, only rewind
var headBlock *types.Block
if bc.triedb.Scheme() == rawdb.VersionScheme {
head := rawdb.ReadHeadBlockHash(bc.db)
headBlock = bc.GetBlockByHash(head)
versa := bc.triedb.VersaDB()
archiveVersion, _ := versa.LatestStoreDiskVersionInfo()
// empty chain
if archiveVersion == -1 {
archiveVersion = 0
}
if int64(headBlock.NumberU64()) < archiveVersion {
log.Crit("versa db disk version large than header block", "head number", headBlock.NumberU64(), "versa archive number", archiveVersion)
}
log.Info("begin rewind versa db head", "target", archiveVersion)
for {
if int64(headBlock.NumberU64()) == archiveVersion {
rawdb.WriteCanonicalHash(bc.db, headBlock.Hash(), headBlock.NumberU64())
rawdb.WriteHeadHeaderHash(bc.db, headBlock.Hash())
rawdb.WriteHeadBlockHash(bc.db, headBlock.Hash())
rawdb.WriteHeadFastBlockHash(bc.db, headBlock.Hash())
log.Info("reset versa db head block", "number", headBlock.NumberU64(), "hash", headBlock.Hash())
break
}
headBlock = rawdb.ReadBlock(bc.db, headBlock.ParentHash(), headBlock.NumberU64()-1)
if headBlock == nil {
panic("versa db rewind head is nil")
}
}
} else {
// Restore the last known head block
head := rawdb.ReadHeadBlockHash(bc.db)
if head == (common.Hash{}) {
// Corrupt or empty database, init from scratch
log.Warn("Empty database, resetting chain")
return bc.Reset()
}
// Make sure the entire head block is available
headBlock = bc.GetBlockByHash(head)
if headBlock == nil {
// Corrupt or empty database, init from scratch
log.Warn("Head block missing, resetting chain", "hash", head)
return bc.Reset()
}
}
log.Info("load state head block", "number", headBlock.NumberU64())
// Everything seems to be fine, set as the head block
bc.currentBlock.Store(headBlock.Header())

View File

@@ -36,7 +36,7 @@ type cachingVersaDB struct {
mode versa.StateMode
hasState atomic.Bool
debug *DebugVersionState
//debug *DebugVersionState
}
// NewVersaDatabase should be call by NewDatabaseWithNodeDB
@@ -66,9 +66,9 @@ func (cv *cachingVersaDB) Copy() Database {
if cv.hasState.Load() {
_, err := cp.OpenTrie(cv.root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy caching versa db, error: %s", err.Error()))
}
//if cv.debug != nil {
// cv.debug.OnError(fmt.Errorf("failed to open trie in copy caching versa db, error: %s", err.Error()))
//}
return cp
}
}
@@ -90,18 +90,18 @@ func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
}
tree, err := cv.OpenTrie(vtr.root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open trie in copy versa trie, error: %s", err.Error()))
}
//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 {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open storage trie in copy versa trie, error: %s", err.Error()))
}
//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
@@ -122,20 +122,20 @@ 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(cv.version, root, cv.mode)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open state, root:%s, error: %s", root.String(), err.Error()))
}
//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)
}
//if cv.debug != nil {
// cv.debug.OnOpenState(state)
//}
handler, err := cv.versionDB.OpenTree(state, cv.version, common.Hash{}, root)
if err != nil {
if cv.debug != nil {
cv.debug.OnError(fmt.Errorf("failed to open account trie, root:%s, error: %s", root.String(), err.Error()))
}
//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
}
@@ -145,7 +145,7 @@ func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
accountTree: true,
root: root,
mode: cv.mode,
debug: cv.debug,
//debug: cv.debug,
}
cv.state = state
@@ -153,9 +153,9 @@ 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{})
}
//if cv.debug != nil {
// cv.debug.OnOpenTree(handler, common.Hash{}, common.Address{})
//}
return tree, nil
}
@@ -180,16 +180,16 @@ func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot co
owner := crypto.Keccak256Hash(address.Bytes())
handler, err := cv.versionDB.OpenTree(cv.state, version, owner, root)
if err != nil {
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()))
}
//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
}
if cv.debug != nil {
cv.debug.OnOpenTree(handler, owner, address)
}
//if cv.debug != nil {
// cv.debug.OnOpenTree(handler, owner, address)
//}
tree := &VersaTree{
db: cv.versionDB,
handler: handler,
@@ -198,7 +198,7 @@ func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot co
stateRoot: root,
address: address,
mode: cv.mode,
debug: cv.debug,
//debug: cv.debug,
}
return tree, nil
}
@@ -206,17 +206,17 @@ func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot co
// Flush unique to versa
func (cv *cachingVersaDB) Flush() error {
err := cv.versionDB.Flush(cv.state)
if err != nil && 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()))
}
//if err != nil && 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
}
func (cv *cachingVersaDB) SetVersion(version int64) {
cv.version = version - 1
cv.debug = NewDebugVersionState(cv.codeDB, cv.versionDB)
cv.debug.Version = version
//cv.debug = NewDebugVersionState(cv.codeDB, cv.versionDB)
//cv.debug.Version = version
}
func (cv *cachingVersaDB) GetVersion() int64 {
@@ -227,21 +227,21 @@ func (cv *cachingVersaDB) GetVersion() int64 {
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 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()))
}
//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)
cv.accTree = nil
cv.state = versa.ErrStateHandler
cv.root = common.Hash{}
cv.debug = nil
//cv.debug = nil
}
return nil
}
@@ -270,9 +270,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(addr, codeHash)
}
//if cv.debug != nil {
// cv.debug.OnGetCode(addr, codeHash)
//}
code, _ := cv.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
@@ -326,7 +326,7 @@ type VersaTree struct {
handler versa.TreeHandler
version int64
accountTree bool
debug *DebugVersionState
//debug *DebugVersionState
// TODO:: debugging, used for logging
stateRoot common.Hash
@@ -352,23 +352,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 err != nil && 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()))
}
//if err != nil && 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)
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)
//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
}
@@ -379,22 +379,22 @@ 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()))
}
//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)
if err != nil {
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)
//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
}
@@ -402,15 +402,15 @@ func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateA
vt.CheckAccountTree()
data, err := rlp.EncodeToBytes(account)
if err != nil {
if vt.debug != nil {
vt.debug.OnError(fmt.Errorf("failed to update account, root: %s, address: %s, account: %s, error: %s",
vt.root.String(), address.String(), account.String(), err.Error()))
}
//if vt.debug != nil {
// vt.debug.OnError(fmt.Errorf("failed to update account, root: %s, address: %s, account: %s, error: %s",
// vt.root.String(), address.String(), account.String(), err.Error()))
//}
return err
}
if vt.debug != nil {
vt.debug.OnUpdateAccount(address, account)
}
//if vt.debug != nil {
// vt.debug.OnUpdateAccount(address, account)
//}
return vt.db.Put(vt.handler, address.Bytes(), data)
}
@@ -422,14 +422,14 @@ func (vt *VersaTree) UpdateStorage(address common.Address, key, value []byte) er
v, _ := rlp.EncodeToBytes(value)
err := vt.db.Put(vt.handler, key, v)
if err != nil {
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)
//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
}
@@ -437,14 +437,14 @@ func (vt *VersaTree) DeleteAccount(address common.Address) error {
vt.CheckAccountTree()
err := vt.db.Delete(vt.handler, address.Bytes())
if err != nil {
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)
//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)
//}
return err
}
@@ -452,14 +452,14 @@ func (vt *VersaTree) DeleteStorage(address common.Address, key []byte) error {
vt.CheckStorageTree()
err := vt.db.Delete(vt.handler, key)
if err != nil {
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)
//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)
//}
return err
}
@@ -470,29 +470,29 @@ 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 {
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()))
}
}
if vt.debug != nil {
vt.debug.OnCalcHash(vt.address, hash)
//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()))
//}
}
//if vt.debug != nil {
// vt.debug.OnCalcHash(vt.address, hash)
//}
return hash
}
func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
hash, err := vt.db.Commit(vt.handler)
if err != nil {
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.OnCalcHash(vt.address, hash)
vt.debug.OnCommitTree(vt.address, vt.handler)
//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.OnCalcHash(vt.address, hash)
// vt.debug.OnCommitTree(vt.address, vt.handler)
//}
return hash, nil, err
}

View File

@@ -227,7 +227,7 @@ type cachingDB struct {
triedb *triedb.Database
noTries bool
debug *DebugHashState
//debug *DebugHashState
}
// OpenTrie opens the main account trie at a specific root hash.
@@ -240,22 +240,23 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
}
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil {
if db.debug != nil {
db.debug.OnError(fmt.Errorf("failed to open tree, root: %s, error: %s", root.String(), err.Error()))
}
//if db.debug != nil {
// db.debug.OnError(fmt.Errorf("failed to open tree, root: %s, error: %s", root.String(), err.Error()))
//}
return nil, err
}
ht := &HashTrie{
trie: tr,
root: root,
address: common.Address{},
owner: common.Hash{},
debug: db.debug,
}
if db.debug != nil {
db.debug.OnOpenTree(root, common.Hash{}, common.Address{})
}
return ht, nil
//ht := &HashTrie{
// trie: tr,
// root: root,
// address: common.Address{},
// owner: common.Hash{},
// debug: db.debug,
//}
//if db.debug != nil {
// db.debug.OnOpenTree(root, common.Hash{}, common.Address{})
//}
//return ht, nil
return tr, nil
}
// OpenStorageTrie opens the storage trie of an account.
@@ -273,24 +274,25 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
owner := crypto.Keccak256Hash(address.Bytes())
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, owner, root), db.triedb)
if err != nil {
if db.debug != nil {
db.debug.OnError(fmt.Errorf("failed to storage open tree, stateRoot: %s, address: %s, root: %s, error: %s",
stateRoot.String(), address.String(), root.String(), err.Error()))
}
//if db.debug != nil {
// db.debug.OnError(fmt.Errorf("failed to storage open tree, stateRoot: %s, address: %s, root: %s, error: %s",
// stateRoot.String(), address.String(), root.String(), err.Error()))
//}
return nil, err
}
ht := &HashTrie{
trie: tr,
root: stateRoot,
statRoot: root,
address: address,
owner: owner,
debug: db.debug,
}
if db.debug != nil {
db.debug.OnOpenTree(root, owner, address)
}
return ht, nil
//ht := &HashTrie{
// trie: tr,
// root: stateRoot,
// statRoot: root,
// address: address,
// owner: owner,
// debug: db.debug,
//}
//if db.debug != nil {
// db.debug.OnOpenTree(root, owner, address)
//}
//return ht, nil
return tr, nil
}
func (db *cachingDB) NoTries() bool {
@@ -307,8 +309,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
return t.Copy()
case *trie.EmptyTrie:
return t.Copy()
case *HashTrie:
return db.CopyTrie(t.trie)
//case *HashTrie:
// return db.CopyTrie(t.trie)
default:
panic(fmt.Errorf("unknown trie type %T", t))
}
@@ -316,9 +318,9 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
// ContractCode retrieves a particular contract's code.
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
if db.debug != nil {
db.debug.OnGetCode(address, codeHash)
}
//if db.debug != nil {
// db.debug.OnGetCode(address, codeHash)
//}
code, _ := db.codeCache.Get(codeHash)
if len(code) > 0 {
return code, nil
@@ -381,18 +383,19 @@ func (db *cachingDB) Flush() error {
}
func (db *cachingDB) Release() error {
db.debug.flush()
db.debug = nil
//db.debug.flush()
//db.debug = nil
return nil
}
func (db *cachingDB) SetVersion(version int64) {
db.debug = NewDebugHashState(db.disk)
db.debug.Version = version
//db.debug = NewDebugHashState(db.disk)
//db.debug.Version = version
}
func (db *cachingDB) GetVersion() int64 {
return db.debug.Version
//return db.debug.Version
return 0
}
func (db *cachingDB) Copy() Database {
@@ -408,137 +411,137 @@ func (db *cachingDB) HasTreeExpired(_ Trie) bool {
return false
}
type HashTrie struct {
trie Trie
root common.Hash
statRoot common.Hash
address common.Address
owner common.Hash
debug *DebugHashState
}
func (ht *HashTrie) GetKey(key []byte) []byte {
return ht.trie.GetKey(key)
}
func (ht *HashTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
acc, err := ht.trie.GetAccount(address)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to get account, address: %s, error: %s", address.String(), err.Error()))
}
return nil, err
}
if ht.debug != nil {
ht.debug.OnGetAccount(address, acc)
}
return acc, nil
}
func (ht *HashTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
val, err := ht.trie.GetStorage(addr, key)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to get storage, address: %s, error: %s", addr.String(), err.Error()))
}
return val, err
}
if ht.debug != nil {
ht.debug.OnGetStorage(addr, key, val)
}
return val, err
}
func (ht *HashTrie) UpdateAccount(address common.Address, account *types.StateAccount) error {
err := ht.trie.UpdateAccount(address, account)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update account, address: %s, account: %s, error: %s",
address.String(), account.String(), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnUpdateAccount(address, account)
}
return nil
}
func (ht *HashTrie) UpdateStorage(addr common.Address, key, value []byte) error {
err := ht.trie.UpdateStorage(addr, key, value)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, val: %s, error: %s",
addr.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnUpdateStorage(addr, key, value)
}
return nil
}
func (ht *HashTrie) DeleteAccount(address common.Address) error {
err := ht.trie.DeleteAccount(address)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to delete account, address: %s, error: %s", address.String(), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnDeleteAccount(address)
}
return nil
}
func (ht *HashTrie) DeleteStorage(addr common.Address, key []byte) error {
err := ht.trie.DeleteStorage(addr, key)
if err != nil {
if ht.debug != nil {
ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, error: %s",
addr.String(), common.Bytes2Hex(key), err.Error()))
}
return err
}
if ht.debug != nil {
ht.debug.OnDeleteStorage(addr, key)
}
return nil
}
func (ht *HashTrie) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
return ht.trie.UpdateContractCode(address, codeHash, code)
}
func (ht *HashTrie) Hash() common.Hash {
root := ht.trie.Hash()
if ht.debug != nil {
ht.debug.OnCalcHash(ht.address, root)
}
return root
}
func (ht *HashTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
hash, set, err := ht.trie.Commit(collectLeaf)
if err != nil {
ht.debug.OnError(fmt.Errorf("failed to commit tree, address: %s, error: %s",
ht.address.String(), err.Error()))
return hash, set, err
}
if ht.debug != nil {
ht.debug.OnCalcHash(ht.address, hash)
ht.debug.OnCommitTree(ht.address, hash)
}
return hash, set, nil
}
func (ht *HashTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
return ht.trie.NodeIterator(startKey)
}
func (ht *HashTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
return ht.trie.Prove(key, proofDb)
}
//type HashTrie struct {
// trie Trie
// root common.Hash
// statRoot common.Hash
// address common.Address
// owner common.Hash
//
// debug *DebugHashState
//}
//
//func (ht *HashTrie) GetKey(key []byte) []byte {
// return ht.trie.GetKey(key)
//}
//
//func (ht *HashTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
// acc, err := ht.trie.GetAccount(address)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to get account, address: %s, error: %s", address.String(), err.Error()))
// }
// return nil, err
// }
// if ht.debug != nil {
// ht.debug.OnGetAccount(address, acc)
// }
// return acc, nil
//}
//
//func (ht *HashTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
// val, err := ht.trie.GetStorage(addr, key)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to get storage, address: %s, error: %s", addr.String(), err.Error()))
// }
// return val, err
// }
// if ht.debug != nil {
// ht.debug.OnGetStorage(addr, key, val)
// }
// return val, err
//}
//
//func (ht *HashTrie) UpdateAccount(address common.Address, account *types.StateAccount) error {
// err := ht.trie.UpdateAccount(address, account)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to update account, address: %s, account: %s, error: %s",
// address.String(), account.String(), err.Error()))
// }
// return err
// }
// if ht.debug != nil {
// ht.debug.OnUpdateAccount(address, account)
// }
// return nil
//}
//
//func (ht *HashTrie) UpdateStorage(addr common.Address, key, value []byte) error {
// err := ht.trie.UpdateStorage(addr, key, value)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, val: %s, error: %s",
// addr.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
// }
// return err
// }
// if ht.debug != nil {
// ht.debug.OnUpdateStorage(addr, key, value)
// }
// return nil
//}
//
//func (ht *HashTrie) DeleteAccount(address common.Address) error {
// err := ht.trie.DeleteAccount(address)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to delete account, address: %s, error: %s", address.String(), err.Error()))
// }
// return err
// }
// if ht.debug != nil {
// ht.debug.OnDeleteAccount(address)
// }
// return nil
//}
//
//func (ht *HashTrie) DeleteStorage(addr common.Address, key []byte) error {
// err := ht.trie.DeleteStorage(addr, key)
// if err != nil {
// if ht.debug != nil {
// ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, error: %s",
// addr.String(), common.Bytes2Hex(key), err.Error()))
// }
// return err
// }
// if ht.debug != nil {
// ht.debug.OnDeleteStorage(addr, key)
// }
// return nil
//}
//
//func (ht *HashTrie) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
// return ht.trie.UpdateContractCode(address, codeHash, code)
//}
//
//func (ht *HashTrie) Hash() common.Hash {
// root := ht.trie.Hash()
// if ht.debug != nil {
// ht.debug.OnCalcHash(ht.address, root)
// }
// return root
//}
//
//func (ht *HashTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
// hash, set, err := ht.trie.Commit(collectLeaf)
// if err != nil {
// ht.debug.OnError(fmt.Errorf("failed to commit tree, address: %s, error: %s",
// ht.address.String(), err.Error()))
// return hash, set, err
// }
// if ht.debug != nil {
// ht.debug.OnCalcHash(ht.address, hash)
// ht.debug.OnCommitTree(ht.address, hash)
// }
// return hash, set, nil
//}
//
//func (ht *HashTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
// return ht.trie.NodeIterator(startKey)
//}
//
//func (ht *HashTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
// return ht.trie.Prove(key, proofDb)
//}

View File

@@ -1713,18 +1713,18 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
// Write any contract code associated with the state object
if obj.code != nil && obj.dirtyCode {
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code)
switch d := s.db.(type) {
case *cachingVersaDB:
if d.debug != nil {
d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
}
case *cachingDB:
if d.debug != nil {
d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
}
default:
panic("caching db type error")
}
//switch d := s.db.(type) {
//case *cachingVersaDB:
// if d.debug != nil {
// d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
// }
//case *cachingDB:
// if d.debug != nil {
// d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
// }
//default:
// panic("caching db type error")
//}
obj.dirtyCode = false
if s.snap != nil {
panic("snapshot is not nil")

View File

@@ -191,33 +191,40 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp {
}
func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
// If we're in snap sync mode, return that directly
if cs.handler.snapSync.Load() {
block := cs.handler.chain.CurrentSnapBlock()
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
return downloader.SnapSync, td
}
// We are probably in full sync, but we might have rewound to before the
// snap sync pivot, check if we should re-enable snap sync.
head := cs.handler.chain.CurrentBlock()
if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil {
if head.Number.Uint64() < *pivot {
if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType {
log.Crit("Current rewound to before the fast sync pivot, can't enable pruneancient mode", "current block number", head.Number.Uint64(), "pivot", *pivot)
}
if cs.handler.chain.TrieDB().Scheme() != rawdb.VersionScheme {
// If we're in snap sync mode, return that directly
if cs.handler.snapSync.Load() {
block := cs.handler.chain.CurrentSnapBlock()
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
return downloader.SnapSync, td
}
}
// We are in a full sync, but the associated head state is missing. To complete
// the head state, forcefully rerun the snap sync. Note it doesn't mean the
// persistent state is corrupted, just mismatch with the head block.
if !cs.handler.chain.NoTries() && !cs.handler.chain.HasState(head.Root) {
block := cs.handler.chain.CurrentSnapBlock()
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
log.Info("Reenabled snap sync as chain is stateless")
return downloader.SnapSync, td
// We are probably in full sync, but we might have rewound to before the
// snap sync pivot, check if we should re-enable snap sync.
head = cs.handler.chain.CurrentBlock()
if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil {
if head.Number.Uint64() < *pivot {
if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType {
log.Crit("Current rewound to before the fast sync pivot, can't enable pruneancient mode", "current block number", head.Number.Uint64(), "pivot", *pivot)
}
block := cs.handler.chain.CurrentSnapBlock()
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
return downloader.SnapSync, td
}
}
// We are in a full sync, but the associated head state is missing. To complete
// the head state, forcefully rerun the snap sync. Note it doesn't mean the
// persistent state is corrupted, just mismatch with the head block.
if !cs.handler.chain.NoTries() && !cs.handler.chain.HasState(head.Root) {
block := cs.handler.chain.CurrentSnapBlock()
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
log.Info("Reenabled snap sync as chain is stateless")
return downloader.SnapSync, td
}
} else {
if !cs.handler.chain.HasState(head.Root) {
panic("version db not support snap sync")
}
}
// Nope, we're really full syncing
td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64())

View File

@@ -49,7 +49,8 @@ func (v *VersionDB) Scheme() string {
}
func (v *VersionDB) Initialized(genesisRoot common.Hash) bool {
return v.db.HasState(genesisRoot)
version, _ := v.db.LatestStoreDiskVersionInfo()
return version >= 0
}
func (v *VersionDB) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {