core, eth, miner, internal: improve StateAt for UBT compatibility

This commit is contained in:
Gary Rong 2026-04-16 11:13:31 +08:00
parent d84d2a68e2
commit 296edde6c5
19 changed files with 92 additions and 47 deletions

View file

@ -416,20 +416,42 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
// State returns a new mutable state based on the current HEAD block. // State returns a new mutable state based on the current HEAD block.
func (bc *BlockChain) State() (*state.StateDB, error) { func (bc *BlockChain) State() (*state.StateDB, error) {
return bc.StateAt(bc.CurrentBlock().Root) return bc.StateAt(bc.CurrentBlock())
} }
// StateAt returns a new mutable state based on a particular point in time. // 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(header *types.Header) (*state.StateDB, error) {
// TODO(rjl493456442) support ubt later if bc.chainConfig.IsUBT(header.Number, header.Time) {
return state.New(root, state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps)) return state.New(header.Root, state.NewUBTDatabase(bc.triedb, bc.codedb))
}
return state.New(header.Root, state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps))
} }
// HistoricState returns a historic state specified by the given root. // StateAtForkBoundary returns a new mutable state based on the parent state
// and the given header, handling the transition across the UBT fork.
func (bc *BlockChain) StateAtForkBoundary(parent *types.Header, header *types.Header) (*state.StateDB, error) {
// The parent is already in the UBT fork.
if bc.chainConfig.IsUBT(parent.Number, parent.Time) {
return state.New(parent.Root, state.NewUBTDatabase(bc.triedb, bc.codedb))
}
// The current block is the first block in the UBT fork
// (i.e., the parent is the last MPT block).
if bc.chainConfig.IsUBT(header.Number, header.Time) {
// TODO(gballet): register chain context if needed
return state.New(parent.Root, state.NewUBTDatabase(bc.triedb, bc.codedb))
}
// Both the parent and current block are in the MPT fork.
return state.New(parent.Root, state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps))
}
// HistoricState returns a historic state specified by the given header.
// Live states are not available and won't be served, please use `State` // Live states are not available and won't be served, please use `State`
// or `StateAt` instead. // or `StateAt` instead.
func (bc *BlockChain) HistoricState(root common.Hash) (*state.StateDB, error) { func (bc *BlockChain) HistoricState(header *types.Header) (*state.StateDB, error) {
return state.New(root, state.NewHistoricDatabase(bc.triedb, bc.codedb)) if bc.chainConfig.IsUBT(header.Number, header.Time) {
return nil, errors.New("historical state over ubt is not yet supported")
}
return state.New(header.Root, state.NewHistoricDatabase(bc.triedb, bc.codedb))
} }
// Config retrieves the chain's fork configuration. // Config retrieves the chain's fork configuration.

View file

@ -3890,7 +3890,7 @@ func TestTransientStorageReset(t *testing.T) {
t.Fatalf("failed to insert into chain: %v", err) t.Fatalf("failed to insert into chain: %v", err)
} }
// Check the storage // Check the storage
state, err := chain.StateAt(chain.CurrentHeader().Root) state, err := chain.StateAt(chain.CurrentHeader())
if err != nil { if err != nil {
t.Fatalf("Failed to load state %v", err) t.Fatalf("Failed to load state %v", err)
} }

View file

@ -441,9 +441,9 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserver txpool.Reser
// Initialize the state with head block, or fallback to empty one in // 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 // case the head state is not available (might occur when node is not
// fully synced). // fully synced).
state, err := p.chain.StateAt(head.Root) state, err := p.chain.StateAt(head)
if err != nil { if err != nil {
state, err = p.chain.StateAt(types.EmptyRootHash) state, err = p.chain.StateAt(p.chain.Genesis().Header())
} }
if err != nil { if err != nil {
return err return err
@ -894,7 +894,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
// Handle reorg buffer timeouts evicting old gapped transactions // Handle reorg buffer timeouts evicting old gapped transactions
p.evictGapped() p.evictGapped()
statedb, err := p.chain.StateAt(newHead.Root) statedb, err := p.chain.StateAt(newHead)
if err != nil { if err != nil {
log.Error("Failed to reset blobpool state", "err", err) log.Error("Failed to reset blobpool state", "err", err)
return return

View file

@ -45,6 +45,7 @@ import (
"github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/billy" "github.com/holiman/billy"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -180,10 +181,14 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return bc.blocks[number] return bc.blocks[number]
} }
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { func (bc *testBlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
return bc.statedb, nil return bc.statedb, nil
} }
func (bc *testBlockChain) Genesis() *types.Block {
return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil))
}
// reserver is a utility struct to sanity check that accounts are // reserver is a utility struct to sanity check that accounts are
// properly reserved by the blobpool (no duplicate reserves or unreserves). // properly reserved by the blobpool (no duplicate reserves or unreserves).
type reserver struct { type reserver struct {

View file

@ -32,6 +32,9 @@ type BlockChain interface {
// CurrentBlock returns the current head of the chain. // CurrentBlock returns the current head of the chain.
CurrentBlock() *types.Header CurrentBlock() *types.Header
// Genesis returns the genesis block of the chain.
Genesis() *types.Block
// CurrentFinalBlock returns the current block below which blobs should not // CurrentFinalBlock returns the current block below which blobs should not
// be maintained anymore for reorg purposes. // be maintained anymore for reorg purposes.
CurrentFinalBlock() *types.Header CurrentFinalBlock() *types.Header
@ -39,6 +42,6 @@ type BlockChain interface {
// GetBlock retrieves a specific block, used during pool resets. // GetBlock retrieves a specific block, used during pool resets.
GetBlock(hash common.Hash, number uint64) *types.Block GetBlock(hash common.Hash, number uint64) *types.Block
// StateAt returns a state database for a given root hash (generally the head). // StateAt returns a state database for a given chain header (generally the head).
StateAt(root common.Hash) (*state.StateDB, error) StateAt(header *types.Header) (*state.StateDB, error)
} }

View file

@ -129,11 +129,14 @@ type BlockChain interface {
// CurrentBlock returns the current head of the chain. // CurrentBlock returns the current head of the chain.
CurrentBlock() *types.Header CurrentBlock() *types.Header
// Genesis returns the genesis block of the chain.
Genesis() *types.Block
// GetBlock retrieves a specific block, used during pool resets. // GetBlock retrieves a specific block, used during pool resets.
GetBlock(hash common.Hash, number uint64) *types.Block GetBlock(hash common.Hash, number uint64) *types.Block
// StateAt returns a state database for a given root hash (generally the head). // StateAt returns a state database for a given chain header (generally the head).
StateAt(root common.Hash) (*state.StateDB, error) StateAt(header *types.Header) (*state.StateDB, error)
} }
// Config are the configuration parameters of the transaction pool. // Config are the configuration parameters of the transaction pool.
@ -317,9 +320,9 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserver txpool.
// Initialize the state with head block, or fallback to empty one in // 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 // case the head state is not available (might occur when node is not
// fully synced). // fully synced).
statedb, err := pool.chain.StateAt(head.Root) statedb, err := pool.chain.StateAt(head)
if err != nil { if err != nil {
statedb, err = pool.chain.StateAt(types.EmptyRootHash) statedb, err = pool.chain.StateAt(pool.chain.Genesis().Header())
} }
if err != nil { if err != nil {
return err return err
@ -1379,7 +1382,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
if newHead == nil { if newHead == nil {
newHead = pool.chain.CurrentBlock() // Special case during testing newHead = pool.chain.CurrentBlock() // Special case during testing
} }
statedb, err := pool.chain.StateAt(newHead.Root) statedb, err := pool.chain.StateAt(newHead)
if err != nil { if err != nil {
log.Error("Failed to reset txpool state", "err", err) log.Error("Failed to reset txpool state", "err", err)
return return

View file

@ -91,10 +91,14 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil))
} }
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { func (bc *testBlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
return bc.statedb, nil return bc.statedb, nil
} }
func (bc *testBlockChain) Genesis() *types.Block {
return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil))
}
func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return bc.chainHeadFeed.Subscribe(ch) return bc.chainHeadFeed.Subscribe(ch)
} }

View file

@ -102,7 +102,7 @@ func (env *testEnv) setGasTip(gasTip uint64) {
func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction { func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction {
if nonce == 0 { if nonce == 0 {
head := env.chain.CurrentHeader() head := env.chain.CurrentHeader()
state, _ := env.chain.StateAt(head.Root) state, _ := env.chain.StateAt(head)
nonce = state.GetNonce(address) nonce = state.GetNonce(address)
} }
if gasPrice == nil { if gasPrice == nil {
@ -114,7 +114,7 @@ func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction {
func (env *testEnv) makeTxs(n int) []*types.Transaction { func (env *testEnv) makeTxs(n int) []*types.Transaction {
head := env.chain.CurrentHeader() head := env.chain.CurrentHeader()
state, _ := env.chain.StateAt(head.Root) state, _ := env.chain.StateAt(head)
nonce := state.GetNonce(address) nonce := state.GetNonce(address)
var txs []*types.Transaction var txs []*types.Transaction

View file

@ -50,11 +50,14 @@ type BlockChain interface {
// CurrentBlock returns the current head of the chain. // CurrentBlock returns the current head of the chain.
CurrentBlock() *types.Header CurrentBlock() *types.Header
// Genesis returns the genesis block of the chain.
Genesis() *types.Block
// SubscribeChainHeadEvent subscribes to new blocks being added to the chain. // SubscribeChainHeadEvent subscribes to new blocks being added to the chain.
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
// StateAt returns a state database for a given root hash (generally the head). // StateAt returns a state database for a given chain header (generally the head).
StateAt(root common.Hash) (*state.StateDB, error) StateAt(header *types.Header) (*state.StateDB, error)
} }
// TxPool is an aggregator for various transaction specific pools, collectively // TxPool is an aggregator for various transaction specific pools, collectively
@ -87,9 +90,9 @@ func New(gasTip uint64, chain BlockChain, subpools []SubPool) (*TxPool, error) {
// Initialize the state with head block, or fallback to empty one in // 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 // case the head state is not available (might occur when node is not
// fully synced). // fully synced).
statedb, err := chain.StateAt(head.Root) statedb, err := chain.StateAt(head)
if err != nil { if err != nil {
statedb, err = chain.StateAt(types.EmptyRootHash) statedb, err = chain.StateAt(chain.Genesis().Header())
} }
if err != nil { if err != nil {
return nil, err return nil, err
@ -185,7 +188,7 @@ func (p *TxPool) loop(head *types.Header) {
case resetBusy <- struct{}{}: case resetBusy <- struct{}{}:
// Updates the statedb with the new chain head. The head state may be // Updates the statedb with the new chain head. The head state may be
// unavailable if the initial state sync has not yet completed. // unavailable if the initial state sync has not yet completed.
if statedb, err := p.chain.StateAt(newHead.Root); err != nil { if statedb, err := p.chain.StateAt(newHead); err != nil {
log.Error("Failed to reset txpool state", "err", err) log.Error("Failed to reset txpool state", "err", err)
} else { } else {
p.stateLock.Lock() p.stateLock.Lock()

View file

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

View file

@ -82,7 +82,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
if header == nil { if header == nil {
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr) 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)
if err != nil { if err != nil {
return state.Dump{}, err return state.Dump{}, err
} }
@ -167,7 +167,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if header == nil { if header == nil {
return state.Dump{}, fmt.Errorf("block #%d not found", number) 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)
if err != nil { if err != nil {
return state.Dump{}, err return state.Dump{}, err
} }
@ -177,7 +177,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if block == nil { if block == nil {
return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex()) 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.Header())
if err != nil { if err != nil {
return state.Dump{}, err return state.Dump{}, err
} }

View file

@ -299,7 +299,7 @@ func TestEth2NewBlock(t *testing.T) {
ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh) ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root()) statedb, _ := ethservice.BlockChain().StateAt(parent.Header())
nonce := statedb.GetNonce(testAddr) nonce := statedb.GetNonce(testAddr)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().Add([]*types.Transaction{tx}, true) ethservice.TxPool().Add([]*types.Transaction{tx}, true)
@ -478,7 +478,7 @@ func TestFullAPI(t *testing.T) {
) )
callback := func(parent *types.Header) { callback := func(parent *types.Header) {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root) statedb, _ := ethservice.BlockChain().StateAt(parent)
nonce := statedb.GetNonce(testAddr) nonce := statedb.GetNonce(testAddr)
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
ethservice.TxPool().Add([]*types.Transaction{tx}, false) ethservice.TxPool().Add([]*types.Transaction{tx}, false)
@ -604,7 +604,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
) )
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
statedb, _ := ethservice.BlockChain().StateAt(parent.Root) statedb, _ := ethservice.BlockChain().StateAt(parent)
tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{ tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{
Nonce: statedb.GetNonce(testAddr), Nonce: statedb.GetNonce(testAddr),
Value: new(big.Int), Value: new(big.Int),
@ -1263,7 +1263,7 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
// Each block, this callback will include two txs that generate body values like logs and requests. // Each block, this callback will include two txs that generate body values like logs and requests.
callback := func(parent *types.Header) { callback := func(parent *types.Header) {
var ( var (
statedb, _ = ethservice.BlockChain().StateAt(parent.Root) statedb, _ = ethservice.BlockChain().StateAt(parent)
// Create tx to trigger log generator. // Create tx to trigger log generator.
tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey) tx1, _ = types.SignTx(types.NewContractCreation(statedb.GetNonce(testAddr), new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
// Create tx to trigger deposit generator. // Create tx to trigger deposit generator.

View file

@ -104,7 +104,7 @@ func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.
func (b *testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { func (b *testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) {
if b.pending { if b.pending {
block := b.chain.GetBlockByNumber(testHead + 1) block := b.chain.GetBlockByNumber(testHead + 1)
state, _ := b.chain.StateAt(block.Root()) state, _ := b.chain.StateAt(block.Header())
return block, b.chain.GetReceiptsByHash(block.Hash()), state return block, b.chain.GetReceiptsByHash(block.Hash()), state
} }
return nil, nil, nil return nil, nil, nil

View file

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

View file

@ -152,7 +152,7 @@ func (b *testBackend) teardown() {
} }
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) { func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
statedb, err := b.chain.StateAt(block.Root()) statedb, err := b.chain.StateAt(block.Header())
if err != nil { if err != nil {
return nil, nil, errStateNotFound return nil, nil, errStateNotFound
} }

View file

@ -162,7 +162,7 @@ func setupTestBlockchain(t *testing.T, genesis *core.Genesis, tx *types.Transact
if genesisBlock == nil { if genesisBlock == nil {
t.Fatalf("failed to get genesis block") t.Fatalf("failed to get genesis block")
} }
statedb, err := blockchain.StateAt(genesisBlock.Root()) statedb, err := blockchain.StateAt(genesisBlock.Header())
if err != nil { if err != nil {
t.Fatalf("failed to get state: %v", err) t.Fatalf("failed to get state: %v", err)
} }

View file

@ -572,7 +572,7 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc
if header == nil { if header == nil {
return nil, nil, errors.New("header not found") return nil, nil, errors.New("header not found")
} }
stateDb, err := b.chain.StateAt(header.Root) stateDb, err := b.chain.StateAt(header)
return stateDb, header, err return stateDb, header, err
} }
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) { func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {

View file

@ -80,10 +80,14 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil)) return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil))
} }
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) { func (bc *testBlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
return bc.statedb, nil return bc.statedb, nil
} }
func (bc *testBlockChain) Genesis() *types.Block {
return types.NewBlock(bc.CurrentBlock(), nil, nil, trie.NewStackTrie(nil))
}
func (bc *testBlockChain) HasState(root common.Hash) bool { func (bc *testBlockChain) HasState(root common.Hash) bool {
return bc.root == root return bc.root == root
} }

View file

@ -324,7 +324,7 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams,
// makeEnv creates a new environment for the sealing block. // makeEnv creates a new environment for the sealing block.
func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, witness bool) (*environment, error) { func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, witness bool) (*environment, error) {
// Retrieve the parent state to execute on top. // Retrieve the parent state to execute on top.
state, err := miner.chain.StateAt(parent.Root) state, err := miner.chain.StateAtForkBoundary(parent, header)
if err != nil { if err != nil {
return nil, err return nil, err
} }