mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-28 08:37:22 +00:00
two-steps bootstrapping
This commit is contained in:
parent
9f89625a0d
commit
8cc4463bbd
5 changed files with 99 additions and 27 deletions
|
|
@ -32,6 +32,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/bintrie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
|
|
@ -370,8 +372,17 @@ func (bc *BlockChain) TxIndexDone() bool {
|
|||
}
|
||||
|
||||
// HasState checks if state trie is fully present in the database or not.
|
||||
// It avoids using OpenTrie which has transition-aware logic that may try
|
||||
// to open a binary tree before it exists. Instead, it directly attempts
|
||||
// to decode the root node as an MPT first, and if that fails, as a binary
|
||||
// trie.
|
||||
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||
_, err := bc.statedb.OpenTrie(hash)
|
||||
// Try to open as a Merkle Patricia Trie first.
|
||||
if _, err := trie.NewStateTrie(trie.StateTrieID(hash), bc.triedb); err == nil {
|
||||
return true
|
||||
}
|
||||
// Fall back to trying as a binary trie.
|
||||
_, err := bintrie.NewBinaryTrie(hash, bc.triedb)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ var (
|
|||
conversionProgressSlotKey = common.Hash{2} // slot 2: current slot pointer
|
||||
conversionProgressStorageProcessed = common.Hash{3} // slot 3: storage processed flag
|
||||
transitionEndedKey = common.Hash{4} // slot 4: non-zero if transition ended
|
||||
baseRootKey = common.Hash{5} // slot 5: MPT base root at transition start
|
||||
)
|
||||
|
||||
// isTransitionActive checks if the binary tree transition has been activated
|
||||
|
|
@ -232,12 +233,18 @@ func LoadTransitionState(reader StateReader, root common.Hash) *overlay.Transiti
|
|||
}
|
||||
storageProcessed := storageProcessedBytes[0] == 1
|
||||
|
||||
baseRoot, err := reader.Storage(params.BinaryTransitionRegistryAddress, baseRootKey)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &overlay.TransitionState{
|
||||
Started: started,
|
||||
Ended: ended,
|
||||
CurrentAccountAddress: ¤tAccount,
|
||||
CurrentSlotHash: currentSlotHash,
|
||||
StorageProcessed: storageProcessed,
|
||||
BaseRoot: baseRoot,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -307,30 +314,45 @@ func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithSta
|
|||
|
||||
// OpenTrie opens the main account trie at a specific root hash.
|
||||
func (db *CachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
||||
reader, err := db.triedb.StateReader(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flatReader := newFlatReader(reader)
|
||||
|
||||
ts := LoadTransitionState(flatReader, root)
|
||||
if isTransitionActive(flatReader) || db.triedb.IsVerkle() {
|
||||
bt, err := bintrie.NewBinaryTrie(root, db.triedb)
|
||||
// Only attempt transition-aware trie opening in path scheme, since
|
||||
// hashdb does not implement StateReader.
|
||||
if db.TrieDB().Scheme() == rawdb.PathScheme {
|
||||
reader, err := db.triedb.StateReader(root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open the overlay tree: %w", err)
|
||||
}
|
||||
if !ts.InTransition() {
|
||||
// Transition complete, use BinaryTrie only
|
||||
return bt, nil
|
||||
return nil, err
|
||||
}
|
||||
flatReader := newFlatReader(reader)
|
||||
|
||||
base, err := trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), db.triedb)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create base trie in OpenTrie: %w", err)
|
||||
ts := LoadTransitionState(flatReader, root)
|
||||
if isTransitionActive(flatReader) || db.triedb.IsVerkle() {
|
||||
fmt.Printf("Opening transition-aware trie for root %s with transition state: %+v\n", root, ts)
|
||||
|
||||
// special case of the tree bootsrap: the root will be that of the MPT, so in that
|
||||
// case, open an empty binary tree.
|
||||
var bt *bintrie.BinaryTrie
|
||||
if ts.BaseRoot == (common.Hash{}) {
|
||||
bt, err = bintrie.NewBinaryTrie(common.Hash{}, db.triedb)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not bootstrap the overlay tree: %w", err)
|
||||
}
|
||||
} else {
|
||||
bt, err = bintrie.NewBinaryTrie(root, db.triedb)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not open the overlay tree: %w", err)
|
||||
}
|
||||
}
|
||||
if !ts.InTransition() {
|
||||
// Transition complete, use BinaryTrie only
|
||||
return bt, nil
|
||||
}
|
||||
|
||||
base, err := trie.NewStateTrie(trie.StateTrieID(ts.BaseRoot), db.triedb)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create base trie in OpenTrie: %w", err)
|
||||
}
|
||||
return transitiontrie.NewTransitionTrie(base, bt, false), nil
|
||||
}
|
||||
return transitiontrie.NewTransitionTrie(base, bt, false), nil
|
||||
}
|
||||
|
||||
return trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,15 +87,28 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
context = NewEVMBlockContext(header, p.chain, nil)
|
||||
evm := vm.NewEVM(context, tracingStateDB, config, cfg)
|
||||
|
||||
if config.IsVerkle(header.Number, header.Time) {
|
||||
// Bootstrap part deux: initialize the base root in the registry,
|
||||
// as this is the first UBT block (which is the _second_ block of
|
||||
// the transition, after the bootstrapping block that initializes
|
||||
// the registry).
|
||||
parentHeader := p.chain.GetHeaderByHash(block.ParentHash())
|
||||
// Confusingly, the first IsVerkle block isn't "verkle"
|
||||
if config.IsVerkle(parentHeader.Number, parentHeader.Time) {
|
||||
// Store the parent's state root as the MPT base root for the
|
||||
// binary trie transition. Only written once (first verkle block),
|
||||
// before InitializeBinaryTransitionRegistry sets slot 0.
|
||||
if statedb.GetState(params.BinaryTransitionRegistryAddress, common.Hash{5}) == (common.Hash{}) {
|
||||
statedb.SetState(params.BinaryTransitionRegistryAddress, common.Hash{5}, parentHeader.Root)
|
||||
}
|
||||
}
|
||||
}
|
||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||
ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||
}
|
||||
if config.IsPrague(block.Number(), block.Time()) || config.IsVerkle(block.Number(), block.Time()) {
|
||||
ProcessParentBlockHash(block.ParentHash(), evm)
|
||||
}
|
||||
if config.IsVerkle(header.Number, header.Time) {
|
||||
InitializeBinaryTransitionRegistry(statedb)
|
||||
}
|
||||
|
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() {
|
||||
|
|
@ -129,6 +142,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, fmt.Errorf("failed to process consolidation queue: %w", err)
|
||||
}
|
||||
}
|
||||
if config.IsVerkle(header.Number, header.Time) {
|
||||
// Bootstrap part one: initialize the registry to mark the transition as started,
|
||||
// which has to be done at the end of the _previous_ block, so that the information
|
||||
// can bee made available inside the tree.
|
||||
parentHeader := p.chain.GetHeaderByHash(block.ParentHash())
|
||||
if !config.IsVerkle(parentHeader.Number, parentHeader.Time) {
|
||||
InitializeBinaryTransitionRegistry(statedb)
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body())
|
||||
|
|
|
|||
|
|
@ -31,5 +31,5 @@ func InitializeBinaryTransitionRegistry(statedb *state.StateDB) {
|
|||
}
|
||||
statedb.SetCode(params.BinaryTransitionRegistryAddress, []byte{1, 2, 3}, tracing.CodeChangeUnspecified)
|
||||
statedb.SetNonce(params.BinaryTransitionRegistryAddress, 1, tracing.NonceChangeUnspecified)
|
||||
statedb.SetState(params.BinaryTransitionRegistryAddress, common.Hash{}, common.Hash{1})
|
||||
statedb.SetState(params.BinaryTransitionRegistryAddress, common.Hash{}, common.Hash{1}) // slot 0: started
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,6 +167,15 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
return &newPayloadResult{err: err}
|
||||
}
|
||||
}
|
||||
if miner.chainConfig.IsVerkle(work.header.Number, work.header.Time) {
|
||||
// Bootstrap part one: initialize the registry to mark the transition as started,
|
||||
// which has to be done at the end of the _previous_ block, so that the information
|
||||
// can bee made available inside the tree.
|
||||
parentHeader := miner.chain.GetHeaderByHash(work.header.ParentHash) // XXX parent could be added to the environment in prepareWork to avoid this lookup
|
||||
if !miner.chainConfig.IsVerkle(parentHeader.Number, parentHeader.Time) {
|
||||
core.InitializeBinaryTransitionRegistry(work.state)
|
||||
}
|
||||
}
|
||||
if requests != nil {
|
||||
reqHash := types.CalcRequestsHash(requests)
|
||||
work.header.RequestsHash = &reqHash
|
||||
|
|
@ -260,15 +269,23 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
|||
log.Error("Failed to create sealing context", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
if miner.chainConfig.IsVerkle(header.Number, header.Time) {
|
||||
// Bootstrap part deux: initialize the base root in the registry,
|
||||
// as this is the first UBT block (which is the _second_ block of
|
||||
// the transition, after the bootstrapping block that initializes
|
||||
// the registry).
|
||||
if miner.chainConfig.IsVerkle(parent.Number, parent.Time) {
|
||||
if env.state.GetState(params.BinaryTransitionRegistryAddress, common.Hash{5}) == (common.Hash{}) {
|
||||
env.state.SetState(params.BinaryTransitionRegistryAddress, common.Hash{5}, parent.Root)
|
||||
}
|
||||
}
|
||||
}
|
||||
if header.ParentBeaconRoot != nil {
|
||||
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm)
|
||||
}
|
||||
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
||||
core.ProcessParentBlockHash(header.ParentHash, env.evm)
|
||||
}
|
||||
if miner.chainConfig.IsVerkle(header.Number, header.Time) {
|
||||
core.InitializeBinaryTransitionRegistry(env.state)
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue