mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
core, eth, miner, internal: improve StateAt for UBT compatibility
This commit is contained in:
parent
d84d2a68e2
commit
296edde6c5
19 changed files with 92 additions and 47 deletions
|
|
@ -416,20 +416,42 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
|
|||
|
||||
// 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())
|
||||
}
|
||||
|
||||
// StateAt returns a new mutable state based on a particular point in time.
|
||||
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||
// TODO(rjl493456442) support ubt later
|
||||
return state.New(root, state.NewMPTDatabase(bc.triedb, bc.codedb).WithSnapshot(bc.snaps))
|
||||
func (bc *BlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
|
||||
if bc.chainConfig.IsUBT(header.Number, header.Time) {
|
||||
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`
|
||||
// or `StateAt` instead.
|
||||
func (bc *BlockChain) HistoricState(root common.Hash) (*state.StateDB, error) {
|
||||
return state.New(root, state.NewHistoricDatabase(bc.triedb, bc.codedb))
|
||||
func (bc *BlockChain) HistoricState(header *types.Header) (*state.StateDB, error) {
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -3890,7 +3890,7 @@ func TestTransientStorageReset(t *testing.T) {
|
|||
t.Fatalf("failed to insert into chain: %v", err)
|
||||
}
|
||||
// Check the storage
|
||||
state, err := chain.StateAt(chain.CurrentHeader().Root)
|
||||
state, err := chain.StateAt(chain.CurrentHeader())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to load state %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 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)
|
||||
if err != nil {
|
||||
state, err = p.chain.StateAt(types.EmptyRootHash)
|
||||
state, err = p.chain.StateAt(p.chain.Genesis().Header())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -894,7 +894,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
|||
// Handle reorg buffer timeouts evicting old gapped transactions
|
||||
p.evictGapped()
|
||||
|
||||
statedb, err := p.chain.StateAt(newHead.Root)
|
||||
statedb, err := p.chain.StateAt(newHead)
|
||||
if err != nil {
|
||||
log.Error("Failed to reset blobpool state", "err", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/holiman/billy"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
|
@ -180,10 +181,14 @@ func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block
|
|||
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
|
||||
}
|
||||
|
||||
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
|
||||
// properly reserved by the blobpool (no duplicate reserves or unreserves).
|
||||
type reserver struct {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ type BlockChain interface {
|
|||
// CurrentBlock returns the current head of the chain.
|
||||
CurrentBlock() *types.Header
|
||||
|
||||
// Genesis returns the genesis block of the chain.
|
||||
Genesis() *types.Block
|
||||
|
||||
// CurrentFinalBlock returns the current block below which blobs should not
|
||||
// be maintained anymore for reorg purposes.
|
||||
CurrentFinalBlock() *types.Header
|
||||
|
|
@ -39,6 +42,6 @@ type BlockChain interface {
|
|||
// GetBlock retrieves a specific block, used during pool resets.
|
||||
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 returns a state database for a given chain header (generally the head).
|
||||
StateAt(header *types.Header) (*state.StateDB, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,11 +129,14 @@ type BlockChain interface {
|
|||
// CurrentBlock returns the current head of the chain.
|
||||
CurrentBlock() *types.Header
|
||||
|
||||
// Genesis returns the genesis block of the chain.
|
||||
Genesis() *types.Block
|
||||
|
||||
// GetBlock retrieves a specific block, used during pool resets.
|
||||
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 returns a state database for a given chain header (generally the head).
|
||||
StateAt(header *types.Header) (*state.StateDB, error)
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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)
|
||||
if err != nil {
|
||||
statedb, err = pool.chain.StateAt(types.EmptyRootHash)
|
||||
statedb, err = pool.chain.StateAt(pool.chain.Genesis().Header())
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -1379,7 +1382,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)
|
||||
if err != nil {
|
||||
log.Error("Failed to reset txpool state", "err", err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
||||
func (bc *testBlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
|
||||
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 {
|
||||
return bc.chainHeadFeed.Subscribe(ch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ func (env *testEnv) setGasTip(gasTip uint64) {
|
|||
func (env *testEnv) makeTx(nonce uint64, gasPrice *big.Int) *types.Transaction {
|
||||
if nonce == 0 {
|
||||
head := env.chain.CurrentHeader()
|
||||
state, _ := env.chain.StateAt(head.Root)
|
||||
state, _ := env.chain.StateAt(head)
|
||||
nonce = state.GetNonce(address)
|
||||
}
|
||||
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 {
|
||||
head := env.chain.CurrentHeader()
|
||||
state, _ := env.chain.StateAt(head.Root)
|
||||
state, _ := env.chain.StateAt(head)
|
||||
nonce := state.GetNonce(address)
|
||||
|
||||
var txs []*types.Transaction
|
||||
|
|
|
|||
|
|
@ -50,11 +50,14 @@ type BlockChain interface {
|
|||
// CurrentBlock returns the current head of the chain.
|
||||
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(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||
|
||||
// StateAt returns a state database for a given root hash (generally the head).
|
||||
StateAt(root common.Hash) (*state.StateDB, error)
|
||||
// StateAt returns a state database for a given chain header (generally the head).
|
||||
StateAt(header *types.Header) (*state.StateDB, error)
|
||||
}
|
||||
|
||||
// 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
|
||||
// case the head state is not available (might occur when node is not
|
||||
// fully synced).
|
||||
statedb, err := chain.StateAt(head.Root)
|
||||
statedb, err := chain.StateAt(head)
|
||||
if err != nil {
|
||||
statedb, err = chain.StateAt(types.EmptyRootHash)
|
||||
statedb, err = chain.StateAt(chain.Genesis().Header())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -185,7 +188,7 @@ func (p *TxPool) loop(head *types.Header) {
|
|||
case resetBusy <- struct{}{}:
|
||||
// Updates the statedb with the new chain head. The head state may be
|
||||
// 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)
|
||||
} else {
|
||||
p.stateLock.Lock()
|
||||
|
|
|
|||
|
|
@ -236,9 +236,9 @@ 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)
|
||||
if err != nil {
|
||||
stateDb, err = b.eth.BlockChain().HistoricState(header.Root)
|
||||
stateDb, err = b.eth.BlockChain().HistoricState(header)
|
||||
if err != nil {
|
||||
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 {
|
||||
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 {
|
||||
stateDb, err = b.eth.BlockChain().HistoricState(header.Root)
|
||||
stateDb, err = b.eth.BlockChain().HistoricState(header)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,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)
|
||||
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)
|
||||
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.Header())
|
||||
if err != nil {
|
||||
return state.Dump{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ func TestEth2NewBlock(t *testing.T) {
|
|||
ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Header())
|
||||
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)
|
||||
ethservice.TxPool().Add([]*types.Transaction{tx}, true)
|
||||
|
|
@ -478,7 +478,7 @@ func TestFullAPI(t *testing.T) {
|
|||
)
|
||||
|
||||
callback := func(parent *types.Header) {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent)
|
||||
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)
|
||||
ethservice.TxPool().Add([]*types.Transaction{tx}, false)
|
||||
|
|
@ -604,7 +604,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
|||
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent)
|
||||
tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{
|
||||
Nonce: statedb.GetNonce(testAddr),
|
||||
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.
|
||||
callback := func(parent *types.Header) {
|
||||
var (
|
||||
statedb, _ = ethservice.BlockChain().StateAt(parent.Root)
|
||||
statedb, _ = ethservice.BlockChain().StateAt(parent)
|
||||
// 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)
|
||||
// Create tx to trigger deposit generator.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
if b.pending {
|
||||
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 nil, nil, nil
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// 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.Header()); err == nil {
|
||||
eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{})
|
||||
return statedb, func() {
|
||||
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) {
|
||||
// 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 {
|
||||
return statedb, noopReleaser, nil
|
||||
}
|
||||
statedb, err = eth.blockchain.HistoricState(block.Root())
|
||||
statedb, err = eth.blockchain.HistoricState(header)
|
||||
if err == nil {
|
||||
return statedb, noopReleaser, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
statedb, err := b.chain.StateAt(block.Root())
|
||||
statedb, err := b.chain.StateAt(block.Header())
|
||||
if err != nil {
|
||||
return nil, nil, errStateNotFound
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ func setupTestBlockchain(t *testing.T, genesis *core.Genesis, tx *types.Transact
|
|||
if genesisBlock == nil {
|
||||
t.Fatalf("failed to get genesis block")
|
||||
}
|
||||
statedb, err := blockchain.StateAt(genesisBlock.Root())
|
||||
statedb, err := blockchain.StateAt(genesisBlock.Header())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get state: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -572,7 +572,7 @@ func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.Bloc
|
|||
if header == nil {
|
||||
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
|
||||
}
|
||||
func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
||||
func (bc *testBlockChain) StateAt(header *types.Header) (*state.StateDB, error) {
|
||||
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 {
|
||||
return bc.root == root
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams,
|
|||
// 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) {
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue