Compare commits

..

28 Commits

Author SHA1 Message Date
joeylichang
ffa6c04478 chore: reopen prefetcher 2024-09-30 15:22:22 +08:00
joeylichang
7bf93179b9 chore: delete write batch and change versa config 2024-09-30 15:11:05 +08:00
joeylichang
37b942eb2c fix: delete commit and commit num log 2024-09-29 14:54:43 +08:00
joeylichang
2fbd77d64c chore: change default config 2024-09-29 11:13:55 +08:00
joeylichang
46f6c75cc0 chore: change default config 2024-09-29 11:04:15 +08:00
joeylichang
7a0d393c0d chore: change storage writebatch to single update 2024-09-28 15:44:13 +08:00
joeylichang
ed573ee1a8 chore: change versa config' 2024-09-28 07:39:25 +08:00
joeylichang
6252589246 chore: delete prefetcher 2024-09-28 07:33:39 +08:00
joeylichang
5271bf9bdb feat: support versa write batch 2024-09-27 17:01:12 +08:00
joeylichang
2a6bb8720d fix: commit and calc num 2024-09-26 17:07:43 +08:00
joeylichang
53b585e7ab chore: add check for genesis 2024-09-26 16:55:15 +08:00
joeylichang
5018895927 chore: add commit and calc root num log 2024-09-26 16:25:32 +08:00
joeylichang
3dc1030979 chore: add state object commit panic check 2024-09-26 15:39:30 +08:00
will-2012
b8f5b6a135 Merge pull request #2709 from will-2012/update-versadb-config0
chore: update trivals
2024-09-14 16:43:17 +08:00
will@2012
4b17959733 chore: update trivals 2024-09-14 16:42:46 +08:00
will-2012
5bbfa69f35 Merge pull request #2708 from will-2012/update-versadb-config
chore: update versadb default config
2024-09-14 16:37:30 +08:00
will@2012
99678970e1 chore: update versadb default config 2024-09-14 16:34:57 +08:00
joeycli
6d082af0f3 feat: add prefetcher 2024-09-09 14:22:11 +08:00
joeycli
089845c5f3 chore: add statedb get metrices 2024-09-06 14:06:47 +08:00
joeycli
d7e873c28c fix: delete redundancy state close 2024-09-06 09:14:55 +08:00
joeycli
f646d4f1c0 feat: support version and root as key to state
fix: genesis version to -1

fix: copy with version

fix: change version type from uint64 to int64

fix: set genesis for rewind
2024-09-05 14:55:49 +08:00
joeycli
eaddc87def fix: check version and root when rewind
fix: rewind for genesis
2024-09-04 15:49:06 +08:00
joeycli
2c59e15b7a chore: add validate metrics 2024-09-04 10:21:33 +08:00
joeycli
a5e12fe178 feat: support rewind for versa db
fix: rewind ancient store
2024-09-02 17:35:32 +08:00
joeycli
4ed6b8e36f chore: add execute, verify and commit total metrics 2024-09-02 09:12:54 +08:00
joeycli
b76062c354 fix: rewind ancient store 2024-09-01 12:09:00 +08:00
joeycli
b298f4b6e6 chore: add mgasps metrics 2024-08-29 16:40:46 +08:00
joeycli
06366d743d chore: add pprof service 2024-08-29 12:15:39 +08:00
30 changed files with 276 additions and 103 deletions

View File

@@ -361,6 +361,8 @@ func geth(ctx *cli.Context) error {
defer stack.Close()
startNode(ctx, stack, backend, false)
// TODO:: debug code , will be deleted in the future
debug.StartPProf("127.0.0.1:7060", !ctx.IsSet("metrics.addr"))
stack.Wait()
return nil
}

View File

@@ -343,7 +343,7 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
continue
}
// If we're above the chain head, state availability is a must
if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
if !chain.HasBlockAndState(block.Hash(), block.Number().Int64()) {
return blocks[i:]
}
}

View File

@@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)
@@ -40,6 +41,12 @@ func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValida
}
}
var (
validateBloomTimer = metrics.NewRegisteredTimer("validate/bloom/time", nil)
validateReceiptTimer = metrics.NewRegisteredTimer("validate/receipt/time", nil)
validateRootTimer = metrics.NewRegisteredTimer("validate/root/time", nil)
)
// BlockValidator is responsible for validating block headers, uncles and
// processed state.
//
@@ -96,7 +103,7 @@ func ValidateListsInBody(block *types.Block) error {
// validated at this point.
func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Check whether the block is already imported.
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
if v.bc.HasBlockAndState(block.Hash(), block.Number().Int64()) {
return ErrKnownBlock
}
if v.bc.isCachedBadBlock(block) {
@@ -142,7 +149,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
return nil
},
func() error {
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
if !v.bc.HasBlockAndState(block.ParentHash(), block.Number().Int64()-1) {
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
return consensus.ErrUnknownAncestor
}
@@ -184,6 +191,10 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
// For valid blocks this should always validate to true.
validateFuns := []func() error{
func() error {
defer func(start time.Time) {
validateBloomTimer.UpdateSince(start)
}(time.Now())
rbloom := types.CreateBloom(receipts)
if rbloom != header.Bloom {
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
@@ -191,6 +202,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil
},
func() error {
defer func(start time.Time) {
validateReceiptTimer.UpdateSince(start)
}(time.Now())
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash {
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
@@ -209,6 +223,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
})
} else {
validateFuns = append(validateFuns, func() error {
defer func(start time.Time) {
validateRootTimer.UpdateSince(start)
}(time.Now())
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
}

View File

@@ -74,6 +74,7 @@ var (
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
@@ -95,6 +96,9 @@ var (
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
blockValidationTotalTimer = metrics.NewRegisteredTimer("chain/total/validation", nil)
blockExecutionTotalTimer = metrics.NewRegisteredTimer("chain/total/execution", nil)
blockWriteTotalTimer = metrics.NewRegisteredTimer("chain/total/write", nil)
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
@@ -342,6 +346,15 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// Open trie database with provided config
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
if triedb.Scheme() == rawdb.VersionScheme {
vdb := triedb.VersaDB()
ver, root := vdb.LatestStoreDiskVersionInfo()
if ver == -1 {
rawdb.WriteCanonicalHash(db, common.Hash{}, 0)
}
log.Info("version db latest version info", "version", ver, "root", root.String())
}
// Setup the genesis block, commit the provided genesis specification
// to database if the genesis block is not present yet, or load the
// stored one from database.
@@ -425,7 +438,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// if there is no available state, waiting for state sync.
head := bc.CurrentBlock()
if bc.triedb.Scheme() != rawdb.VersionScheme {
if !bc.HasState(head.Root) {
if !bc.HasState(head.Number.Int64(), 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
@@ -443,7 +456,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
if bc.triedb.Scheme() == rawdb.PathScheme && !bc.NoTries() {
recoverable, _ := bc.triedb.Recoverable(diskRoot)
if !bc.HasState(diskRoot) && !recoverable {
if !bc.HasState(0, diskRoot) && !recoverable {
diskRoot = bc.triedb.Head()
}
}
@@ -470,6 +483,43 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
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 bc.triedb.Scheme() != rawdb.VersionScheme {
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.BlockStore().Ancients()
@@ -732,25 +782,32 @@ func (bc *BlockChain) loadLastState() error {
headBlock = bc.GetBlockByHash(head)
versa := bc.triedb.VersaDB()
archiveVersion, _ := versa.LatestStoreDiskVersionInfo()
// empty chain
archiveVersion, archiveRoot := versa.LatestStoreDiskVersionInfo()
// first start
if archiveVersion == -1 {
archiveVersion = 0
archiveRoot = bc.genesisBlock.Root()
}
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)
log.Info("begin rewind versa db head", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
for {
if int64(headBlock.NumberU64()) == archiveVersion {
if int64(headBlock.NumberU64()) == archiveVersion && archiveRoot.Cmp(headBlock.Root()) == 0 {
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
} else if int64(headBlock.NumberU64()) == archiveVersion {
log.Crit("rewinding meet same number", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
} else if archiveRoot.Cmp(headBlock.Root()) == 0 {
log.Info("rewinding meet same root", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
}
log.Info("rewinding", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
headBlock = rawdb.ReadBlock(bc.db, headBlock.ParentHash(), headBlock.NumberU64()-1)
if headBlock == nil {
panic("versa db rewind head is nil")
@@ -941,7 +998,7 @@ func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash) (*typ
}
// If the associated state is not reachable, continue searching
// backwards until an available state is found.
if !bc.HasState(head.Root) {
if !bc.HasState(head.Number.Int64(), head.Root) {
// If the chain is gapped in the middle, return the genesis
// block as the new chain head.
parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1)
@@ -981,7 +1038,7 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
// noState represents if the target state requested for search
// is unavailable and impossible to be recovered.
noState = !bc.HasState(root) && !bc.stateRecoverable(root)
noState = !bc.HasState(head.Number.Int64(), root) && !bc.stateRecoverable(root)
start = time.Now() // Timestamp the rewinding is restarted
logged = time.Now() // Timestamp last progress log was printed
@@ -1002,13 +1059,13 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
// If the root threshold hasn't been crossed but the available
// state is reached, quickly determine if the target state is
// possible to be reached or not.
if !beyondRoot && noState && bc.HasState(head.Root) {
if !beyondRoot && noState && bc.HasState(head.Number.Int64(), head.Root) {
beyondRoot = true
log.Info("Disable the search for unattainable state", "root", root)
}
// Check if the associated state is available or recoverable if
// the requested root has already been crossed.
if beyondRoot && (bc.HasState(head.Root) || bc.stateRecoverable(head.Root)) {
if beyondRoot && (bc.HasState(head.Number.Int64(), head.Root) || bc.stateRecoverable(head.Root)) {
break
}
// If pivot block is reached, return the genesis block as the
@@ -1035,7 +1092,7 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
}
}
// Recover if the target state if it's not available yet.
if !bc.HasState(head.Root) {
if !bc.HasState(head.Number.Int64(), head.Root) {
if err := bc.triedb.Recover(head.Root); err != nil {
log.Crit("Failed to rollback state", "err", err)
}
@@ -1130,7 +1187,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// the pivot point. In this scenario, there is no possible recovery
// approach except for rerunning a snap sync. Do nothing here until the
// state syncer picks it up.
if !bc.HasState(newHeadBlock.Root) {
if !bc.HasState(newHeadBlock.Number.Int64(), newHeadBlock.Root) {
if newHeadBlock.Number.Uint64() != 0 {
log.Crit("Chain is stateless at a non-genesis block")
}
@@ -1242,7 +1299,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
return err
}
}
if !bc.NoTries() && !bc.HasState(root) {
if !bc.NoTries() && !bc.HasState(0, root) {
return fmt.Errorf("non existent state [%x..]", root[:4])
}
// If all checks out, manually set the head block.
@@ -2299,13 +2356,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
}
if bc.stateCache.Scheme() != rawdb.VersionScheme {
if block.NumberU64() == 2000001 {
log.Crit("exit.... path mode, 200w blocks")
}
}
bc.stateCache.SetVersion(int64(block.NumberU64()))
bc.stateCache.SetVersion(int64(block.NumberU64()) - 1)
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
if err != nil {
bc.stateCache.Release()
@@ -2317,18 +2368,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
//statedb.StartPrefetcher("chain")
interruptCh := make(chan struct{})
// For diff sync, it may fallback to full sync, so we still do prefetch
//if len(block.Transactions()) >= prefetchTxNumber {
// // do Prefetch in a separate goroutine to avoid blocking the critical path
//
// // 1.do state prefetch for snapshot cache
// throwaway := statedb.CopyDoPrefetch()
// go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
//
if len(block.Transactions()) >= prefetchTxNumber {
// do Prefetch in a separate goroutine to avoid blocking the critical path
//1.do state prefetch for snapshot cache
throwaway := statedb.CopyDoPrefetch()
go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
// // 2.do trie prefetch for MPT trie node cache
// // it is for the big state trie tree, prefetch based on transaction's From/To address.
// // trie prefetcher is thread safe now, ok to prefetch in a separate routine
// go throwaway.TriePrefetchInAdvance(block, signer)
//}
}
// Process block using the parent state as reference point
if bc.pipeCommit {
@@ -2344,6 +2395,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher()
return it.index, err
}
blockExecutionTotalTimer.UpdateSince(pstart)
ptime := time.Since(pstart)
// Validate the state using the default validator
@@ -2354,6 +2407,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher()
return it.index, err
}
blockValidationTotalTimer.UpdateSince(vstart)
vtime := time.Since(vstart)
proctime := time.Since(start) // processing + validation
@@ -2389,6 +2444,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
return it.index, err
}
bc.stateCache.Release()
blockWriteTotalTimer.UpdateSince(wstart)
bc.cacheReceipts(block.Hash(), receipts, block)
@@ -2568,7 +2624,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
numbers []uint64
)
parent := it.previous()
for parent != nil && !bc.HasState(parent.Root) {
for parent != nil && !bc.HasState(parent.Number.Int64(), parent.Root) {
if bc.stateRecoverable(parent.Root) {
if err := bc.triedb.Recover(parent.Root); err != nil {
return 0, err
@@ -2635,7 +2691,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
numbers []uint64
parent = block
)
for parent != nil && !bc.HasState(parent.Root()) {
for parent != nil && !bc.HasState(parent.Number().Int64(), parent.Root()) {
if bc.stateRecoverable(parent.Root()) {
if err := bc.triedb.Recover(parent.Root()); err != nil {
return common.Hash{}, err
@@ -2906,7 +2962,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
defer bc.chainmu.Unlock()
// Re-execute the reorged chain in case the head state is missing.
if !bc.HasState(head.Root()) {
if !bc.HasState(head.Number().Int64(), head.Root()) {
if latestValidHash, err := bc.recoverAncestors(head); err != nil {
return latestValidHash, err
}

View File

@@ -64,6 +64,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
}
mGasPsGauge.Update(int64(mgasps))
blockInsertMgaspsGauge.Update(int64(mgasps))
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)

View File

@@ -18,6 +18,7 @@ package core
import (
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -338,7 +339,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
}
// HasState checks if state trie is fully present in the database or not.
func (bc *BlockChain) HasState(hash common.Hash) bool {
func (bc *BlockChain) HasState(number int64, hash common.Hash) bool {
if bc.NoTries() {
return bc.snaps != nil && bc.snaps.Snapshot(hash) != nil
}
@@ -348,18 +349,24 @@ func (bc *BlockChain) HasState(hash common.Hash) bool {
return true
}
}
return bc.stateCache.HasState(hash)
return bc.stateCache.HasState(number, hash)
}
// HasBlockAndState checks if a block and associated state trie is fully present
// in the database or not, caching it if present.
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number int64) bool {
// Check first that the block itself is known
block := bc.GetBlock(hash, number)
var root common.Hash
if number < 0 {
root = types.EmptyRootHash
} else {
block := bc.GetBlock(hash, uint64(number))
if block == nil {
return false
}
return bc.HasState(block.Root())
root = block.Root()
}
return bc.HasState(number, root)
}
// stateRecoverable checks if the specified state is recoverable.
@@ -390,13 +397,19 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
// State returns a new mutable state based on the current HEAD block.
func (bc *BlockChain) State() (*state.StateDB, error) {
return bc.StateAt(bc.CurrentBlock().Root)
return bc.StateAt(bc.CurrentBlock().Number.Int64(), bc.CurrentBlock().Root)
}
// StateAt returns a new mutable state based on a particular point in time.
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
func (bc *BlockChain) StateAt(number int64, root common.Hash) (*state.StateDB, error) {
// new state db with no need commit mode
stateDb, err := state.New(root, state.NewDatabaseWithNodeDB(bc.db, bc.triedb, false), bc.snaps)
has := bc.HasState(number, root)
if !has {
return nil, fmt.Errorf(fmt.Sprintf("do not has state, verison: %d, root: %s", number, root.String()))
}
sdb := state.NewDatabaseWithNodeDB(bc.db, bc.triedb, false)
sdb.SetVersion(number)
stateDb, err := state.New(root, sdb, bc.snaps)
if err != nil {
return nil, err
}

View File

@@ -158,7 +158,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
triedbConfig.NoTries = false
}
cachingdb := state.NewDatabaseWithNodeDB(db, triedb, true)
cachingdb.SetVersion(0)
cachingdb.SetVersion(-1)
defer cachingdb.Release()
statedb, err := state.New(types.EmptyRootHash, cachingdb, nil)
if err != nil {
@@ -274,6 +274,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
log.Info("genesis block hash", "hash", block.Hash())
return genesis.Config, block.Hash(), nil
}
log.Info("init genesis", "stored root", stored.String())
// The genesis block is present(perhaps in ancient database) while the
// state database is not initialized yet. It can happen that the node
// is initialized with an external ancient store. Commit genesis state

View File

@@ -60,6 +60,7 @@ func (cv *cachingVersaDB) Copy() Database {
cp.triedb = cv.triedb
cp.versionDB = cv.versionDB
cp.codeDB = cv.codeDB
cp.version = cv.version
cp.mode = versa.S_RW // it is important
// TODO:: maybe add lock for cv.root
@@ -109,8 +110,8 @@ func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
return nil
}
func (cv *cachingVersaDB) HasState(root common.Hash) bool {
return cv.versionDB.HasState(root)
func (cv *cachingVersaDB) HasState(version int64, root common.Hash) bool {
return cv.versionDB.HasState(version, root)
}
func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
@@ -214,7 +215,7 @@ func (cv *cachingVersaDB) Flush() error {
}
func (cv *cachingVersaDB) SetVersion(version int64) {
cv.version = version - 1
cv.version = version
//cv.debug = NewDebugVersionState(cv.codeDB, cv.versionDB)
//cv.debug.Version = version
}
@@ -414,6 +415,10 @@ func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateA
return vt.db.Put(vt.handler, address.Bytes(), data)
}
func (vt *VersaTree) WriteBatch(values map[string][]byte) error {
return vt.db.WriteBatch(vt.handler, values)
}
func (vt *VersaTree) UpdateStorage(address common.Address, key, value []byte) error {
if vt.address.Cmp(address) != 0 {
panic(fmt.Sprintf("address mismatch in get storage, expect: %s, actul: %s", vt.address.String(), address.String()))

View File

@@ -87,7 +87,7 @@ type Database interface {
Copy() Database
// HasState returns the state data whether in the triedb.
HasState(root common.Hash) bool
HasState(version int64, root common.Hash) bool
// HasTreeExpired used for caching versa db, whether the state where the opened tree resides has been closed
HasTreeExpired(tr Trie) bool
@@ -143,6 +143,8 @@ type Trie interface {
// to be moved to the stateWriter interface when the latter is ready.
UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error
WriteBatch(values map[string][]byte) error
// Hash returns the root hash of the trie. It does not write to the database and
// can be used even if the trie doesn't have one.
Hash() common.Hash
@@ -402,7 +404,7 @@ func (db *cachingDB) Copy() Database {
return db
}
func (db *cachingDB) HasState(root common.Hash) bool {
func (db *cachingDB) HasState(_ int64, root common.Hash) bool {
_, err := db.OpenTrie(root)
return err == nil
}

View File

@@ -34,4 +34,7 @@ var (
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
accountIntermediateRootTimer = metrics.NewRegisteredTimer("state/account/intermediate/root/time", nil)
storageIntermediateRootTimer = metrics.NewRegisteredTimer("state/storage/intermediate/root/time", nil)
)

View File

@@ -235,6 +235,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
return common.Hash{}
}
// If no live objects are available, attempt to use snapshots
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetStorageTimer.UpdateSince(start)
stateDBGetStorageQPS.Mark(1)
}(time.Now())
var (
enc []byte
err error
@@ -390,6 +398,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
s.db.setError(err)
return nil, err
}
if len(s.pendingStorage) == 0 {
return s.trie, nil
}
// Insert all the pending storage updates into the trie
usedStorage := make([][]byte, 0, len(s.pendingStorage))
dirtyStorage := make(map[common.Hash][]byte)
@@ -405,11 +417,14 @@ func (s *stateObject) updateTrie() (Trie, error) {
}
dirtyStorage[key] = v
}
//storages := make(map[string][]byte)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for key, value := range dirtyStorage {
//TODO:: add version schema check
if len(value) == 0 {
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
s.db.setError(err)
@@ -421,6 +436,16 @@ func (s *stateObject) updateTrie() (Trie, error) {
}
s.db.StorageUpdated += 1
}
//if len(value) == 0 {
// storages[string(key[:])] = nil
//} else {
// v, _ := rlp.EncodeToBytes(value)
// storages[string(key[:])] = v
//}
//if err := tr.WriteBatch(storages); err != nil {
// s.db.setError(err)
//}
// Cache the items for preloading
usedStorage = append(usedStorage, common.CopyBytes(key[:]))
}
@@ -507,6 +532,11 @@ func (s *stateObject) updateRoot() {
// The returned set can be nil if nothing to commit. This function assumes all
// storage mutations have already been flushed into trie by updateRoot.
func (s *stateObject) commit() (*trienode.NodeSet, error) {
if s.IsContractAccount() && s.trie == nil && s.db.db.GetVersion() != 0 {
panic(fmt.Sprintf("not open contract account, owner: %s, r_version: %d, c_version: %d, root: %s",
s.address.String(), s.db.db.GetVersion(), s.version, s.Root().String()))
}
// Short circuit if trie is not even loaded, don't bother with committing anything
if s.trie == nil {
s.origin = s.data.Copy()

View File

@@ -54,6 +54,16 @@ type revision struct {
journalIndex int
}
var (
stateDBGetTimer = metrics.NewRegisteredTimer("statedb/get/time", nil)
stateDBGetQPS = metrics.NewRegisteredMeter("statedb/get/qps", nil)
stateDBGetAccountTimer = metrics.NewRegisteredTimer("statedb/account/get/time", nil)
stateDBGetAccountQPS = metrics.NewRegisteredMeter("statedb/account/get/qps", nil)
stateDBGetStorageTimer = metrics.NewRegisteredTimer("statedb/storage/get/time", nil)
stateDBGetStorageQPS = metrics.NewRegisteredMeter("statedb/storage/get/qps", nil)
)
// StateDB structs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
@@ -682,6 +692,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
if err := s.trie.UpdateAccount(addr, &obj.data); err != nil {
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
}
if obj.dirtyCode {
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
}
@@ -709,6 +720,7 @@ func (s *StateDB) deleteStateObject(obj *stateObject) {
}
// Delete the account from the trie
addr := obj.Address()
if err := s.trie.DeleteAccount(addr); err != nil {
s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err))
}
@@ -733,6 +745,14 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
if obj := s.stateObjects[addr]; obj != nil {
return obj
}
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetAccountTimer.UpdateSince(start)
stateDBGetAccountQPS.Mark(1)
}(time.Now())
// If no live objects are available, attempt to use snapshots
var data *types.StateAccount
if s.snap != nil {
@@ -1177,6 +1197,10 @@ func (s *StateDB) populateSnapStorage(obj *stateObject) bool {
}
func (s *StateDB) AccountsIntermediateRoot() {
defer func(start time.Time) {
storageIntermediateRootTimer.UpdateSince(start)
}(time.Now())
tasks := make(chan func())
finishCh := make(chan struct{})
defer close(finishCh)
@@ -1204,7 +1228,6 @@ func (s *StateDB) AccountsIntermediateRoot() {
wg.Add(1)
tasks <- func() {
obj.updateRoot()
// Cache the data until commit. Note, this update mechanism is not symmetric
// to the deletion, because whereas it is enough to track account updates
// at commit time, deletions need tracking at transaction boundary level to
@@ -1221,6 +1244,9 @@ func (s *StateDB) AccountsIntermediateRoot() {
}
func (s *StateDB) StateIntermediateRoot() common.Hash {
defer func(start time.Time) {
accountIntermediateRootTimer.UpdateSince(start)
}(time.Now())
// If there was a trie prefetcher operating, it gets aborted and irrevocably
// modified after we start retrieving tries. Remove it from the statedb after
// this round of use.
@@ -1654,9 +1680,9 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
if err := s.db.Flush(); err != nil {
return err
}
if err := s.db.Release(); err != nil {
return err
}
//if err := s.db.Release(); err != nil {
// return err
//}
s.originalRoot = root
if metrics.EnabledExpensive {
s.TrieDBCommits += time.Since(start)

View File

@@ -49,7 +49,6 @@ func NewStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse
// the transaction messages using the statedb, but any changes are discarded. The
// only goal is to pre-cache transaction signatures and state trie nodes.
func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, cfg *vm.Config, interruptCh <-chan struct{}) {
panic("prefetcher not support")
var (
header = block.Header()
signer = types.MakeSigner(p.config, header.Number, header.Time)

View File

@@ -366,9 +366,9 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
// Initialize the state with head block, or fallback to empty one in
// case the head state is not available (might occur when node is not
// fully synced).
state, err := p.chain.StateAt(head.Root)
state, err := p.chain.StateAt(head.Number.Int64(), head.Root)
if err != nil {
state, err = p.chain.StateAt(types.EmptyRootHash)
state, err = p.chain.StateAt(-1, types.EmptyRootHash)
}
if err != nil {
return err
@@ -793,7 +793,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
resettimeHist.Update(time.Since(start).Nanoseconds())
}(time.Now())
statedb, err := p.chain.StateAt(newHead.Root)
statedb, err := p.chain.StateAt(newHead.Number.Int64(), newHead.Root)
if err != nil {
log.Error("Failed to reset blobpool state", "err", err)
return

View File

@@ -40,5 +40,5 @@ type BlockChain interface {
GetBlock(hash common.Hash, number uint64) *types.Block
// StateAt returns a state database for a given root hash (generally the head).
StateAt(root common.Hash) (*state.StateDB, error)
StateAt(number int64, root common.Hash) (*state.StateDB, error)
}

View File

@@ -120,7 +120,7 @@ type BlockChain interface {
GetBlock(hash common.Hash, number uint64) *types.Block
// StateAt returns a state database for a given root hash (generally the head).
StateAt(root common.Hash) (*state.StateDB, error)
StateAt(number int64, root common.Hash) (*state.StateDB, error)
}
// Config are the configuration parameters of the transaction pool.
@@ -311,9 +311,9 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.A
// Initialize the state with head block, or fallback to empty one in
// case the head state is not available (might occur when node is not
// fully synced).
statedb, err := pool.chain.StateAt(head.Root)
statedb, err := pool.chain.StateAt(head.Number.Int64(), head.Root)
if err != nil {
statedb, err = pool.chain.StateAt(types.EmptyRootHash)
statedb, err = pool.chain.StateAt(-1, types.EmptyRootHash)
}
if err != nil {
return err
@@ -1492,7 +1492,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
if newHead == nil {
newHead = pool.chain.CurrentBlock() // Special case during testing
}
statedb, err := pool.chain.StateAt(newHead.Root)
statedb, err := pool.chain.StateAt(newHead.Number.Int64(), newHead.Root)
if err != nil {
log.Error("Failed to reset txpool state", "err", err)
return

View File

@@ -204,7 +204,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
if header == nil {
return nil, nil, errors.New("header not found")
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
stateDb, err := b.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
if err != nil {
return nil, nil, err
}
@@ -226,7 +226,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
return nil, nil, errors.New("hash is not currently canonical")
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
stateDb, err := b.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
if err != nil {
return nil, nil, err
}

View File

@@ -81,7 +81,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
if header == nil {
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
}
stateDb, err := api.eth.BlockChain().StateAt(header.Root)
stateDb, err := api.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
if err != nil {
return state.Dump{}, err
}
@@ -167,7 +167,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if header == nil {
return state.Dump{}, fmt.Errorf("block #%d not found", number)
}
stateDb, err = api.eth.BlockChain().StateAt(header.Root)
stateDb, err = api.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
if err != nil {
return state.Dump{}, err
}
@@ -177,7 +177,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if block == nil {
return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex())
}
stateDb, err = api.eth.BlockChain().StateAt(block.Root())
stateDb, err = api.eth.BlockChain().StateAt(block.Number().Int64(), block.Root())
if err != nil {
return state.Dump{}, err
}

View File

@@ -220,13 +220,13 @@ func newHandler(config *handlerConfig) (*handler, error) {
}
h.snapSync.Store(true)
log.Warn("Switch sync mode from full sync to snap sync", "reason", "snap sync incomplete")
} else if !h.chain.NoTries() && !h.chain.HasState(fullBlock.Root) {
} else if !h.chain.NoTries() && !h.chain.HasState(fullBlock.Number.Int64(), fullBlock.Root) {
h.snapSync.Store(true)
log.Warn("Switch sync mode from full sync to snap sync", "reason", "head state missing")
}
} else {
head := h.chain.CurrentBlock()
if head.Number.Uint64() > 0 && h.chain.HasState(head.Root) {
if head.Number.Uint64() > 0 && h.chain.HasState(head.Number.Int64(), head.Root) {
// Print warning log if database is not empty to run snap sync.
log.Warn("Switch sync mode from snap sync to full sync", "reason", "snap sync complete")
} else {

View File

@@ -55,7 +55,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
// The state is available in live database, create a reference
// on top to prevent garbage collection and return a release
// function to deref it.
if statedb, err = eth.blockchain.StateAt(block.Root()); err == nil {
if statedb, err = eth.blockchain.StateAt(block.Number().Int64(), block.Root()); err == nil {
eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{})
return statedb, func() {
eth.blockchain.TrieDB().Dereference(block.Root())
@@ -185,7 +185,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) {
// Check if the requested state is available in the live chain.
statedb, err := eth.blockchain.StateAt(block.Root())
statedb, err := eth.blockchain.StateAt(block.Number().Int64(), block.Root())
if err == nil {
return statedb, noopReleaser, nil
}

View File

@@ -17,6 +17,7 @@
package eth
import (
"fmt"
"math/big"
"time"
@@ -215,15 +216,15 @@ func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
// 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) {
if !cs.handler.chain.NoTries() && !cs.handler.chain.HasState(head.Number.Int64(), 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")
if !cs.handler.chain.HasState(head.Number.Int64(), head.Root) {
panic(fmt.Sprintf("version db not support snap sync, version: %d, root: %s", head.Number.Int64(), head.Root))
}
}
// Nope, we're really full syncing

3
go.mod
View File

@@ -42,7 +42,7 @@ require (
github.com/gorilla/websocket v1.5.1
github.com/graph-gophers/graphql-go v1.3.0
github.com/hashicorp/go-bexpr v0.1.10
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/hashicorp/golang-lru v1.0.2
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4
github.com/holiman/bloomfilter/v2 v2.0.3
github.com/holiman/uint256 v1.3.0
@@ -252,7 +252,6 @@ require (
github.com/spf13/afero v1.10.0 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/tidwall/gjson v1.10.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect

6
go.sum
View File

@@ -598,8 +598,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
@@ -1152,8 +1152,6 @@ github.com/tendermint/iavl v0.12.0 h1:xcaFAr+ycqCj7WN1RzL2EfcBioRDOHcU1oWcg83K02
github.com/tendermint/iavl v0.12.0/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM=
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo=
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo=
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=

View File

@@ -1367,11 +1367,11 @@ func (s *BlockChainAPI) needToReplay(ctx context.Context, block *types.Block, ac
if err != nil {
return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
}
parentState, err := s.b.Chain().StateAt(parent.Root())
parentState, err := s.b.Chain().StateAt(parent.Number().Int64(), parent.Root())
if err != nil {
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err)
}
currentState, err := s.b.Chain().StateAt(block.Root())
currentState, err := s.b.Chain().StateAt(parent.Number().Int64(), block.Root())
if err != nil {
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err)
}
@@ -1397,7 +1397,7 @@ func (s *BlockChainAPI) replay(ctx context.Context, block *types.Block, accounts
if err != nil {
return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
}
statedb, err := s.b.Chain().StateAt(parent.Root())
statedb, err := s.b.Chain().StateAt(parent.Number().Int64(), parent.Root())
if err != nil {
return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err)
}

View File

@@ -245,7 +245,7 @@ func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
if block == nil {
return nil, nil
}
stateDb, err := miner.worker.chain.StateAt(block.Root)
stateDb, err := miner.worker.chain.StateAt(block.Number.Int64(), block.Root)
if err != nil {
return nil, nil
}

View File

@@ -690,7 +690,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co
prevEnv *environment) (*environment, error) {
// Retrieve the parent state to execute on top and start a prefetcher for
// the miner to speed block sealing up a bit
state, err := w.chain.StateAt(parent.Root)
state, err := w.chain.StateAt(parent.Number.Int64(), parent.Root)
if err != nil {
return nil, err
}

View File

@@ -31,6 +31,11 @@ func NewEmptyTrie() *EmptyTrie {
return &EmptyTrie{}
}
func (t *EmptyTrie) WriteBatch(values map[string][]byte) error {
panic("EmptyTrie not support WriteBatch")
return nil
}
func (t *EmptyTrie) GetKey(shaKey []byte) []byte {
return nil
}

View File

@@ -73,6 +73,11 @@ func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
return &StateTrie{trie: *trie, db: db}, nil
}
func (t *StateTrie) WriteBatch(values map[string][]byte) error {
panic("StateTrie not support WriteBatch")
return nil
}
// MustGet returns the value for key stored in the trie.
// The value bytes must not be modified by the caller.
//

View File

@@ -69,6 +69,11 @@ func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCac
}, nil
}
func (t *VerkleTrie) WriteBatch(values map[string][]byte) error {
panic("VerkleTrie not support WriteBatch")
return nil
}
// GetKey returns the sha3 preimage of a hashed key that was previously used
// to store a value.
func (t *VerkleTrie) GetKey(key []byte) []byte {

View File

@@ -22,18 +22,22 @@ type VersionDB struct {
func New(config *Config) *VersionDB {
var (
cfg *versa.VersaDBConfig
//cfg *versa.VersaDBConfig
path = "./node/version_db" // TODO:: debug code
)
if config != nil {
path = config.Path
cfg = &versa.VersaDBConfig{
FlushInterval: config.FlushInterval,
MaxStatesInMem: config.MaxStatesInMem,
}
}
db, err := versa.NewVersaDB(path, cfg)
//if config != nil {
// path = config.Path
// cfg = &versa.VersaDBConfig{
// FlushInterval: 2000,
// MaxStatesInMem: 128,
// MemLowWaterMark: 10,
// MemHighWaterMark: 20,
// MemEvictInternal: 200,
// }
// _ = cfg
//}
db, err := versa.NewVersaDB(path, &versa.VersaDBConfig{})
if err != nil {
log.Crit("failed to new version db", "error", err)
}