mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
solve potential fork boundary concurrency error
This commit is contained in:
parent
edbce93d07
commit
74b59cfa63
6 changed files with 35 additions and 30 deletions
|
|
@ -144,17 +144,20 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
return h
|
||||
}
|
||||
var (
|
||||
isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
|
||||
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762)
|
||||
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
||||
gaspool = new(core.GasPool)
|
||||
blockHash = common.Hash{0x13, 0x37}
|
||||
rejectedTxs []*rejectedTx
|
||||
includedTxs types.Transactions
|
||||
gasUsed = uint64(0)
|
||||
blobGasUsed = uint64(0)
|
||||
receipts = make(types.Receipts, 0)
|
||||
isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
|
||||
parentIsVerkle = pre.Env.Number > 0 && chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number-1)), pre.Env.ParentTimestamp)
|
||||
isForkBoundary = isEIP4762 && !parentIsVerkle
|
||||
statedb *state.StateDB
|
||||
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
|
||||
gaspool = new(core.GasPool)
|
||||
blockHash = common.Hash{0x13, 0x37}
|
||||
rejectedTxs []*rejectedTx
|
||||
includedTxs types.Transactions
|
||||
gasUsed = uint64(0)
|
||||
blobGasUsed = uint64(0)
|
||||
receipts = make(types.Receipts, 0)
|
||||
)
|
||||
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762 && !isForkBoundary, isForkBoundary)
|
||||
gaspool.AddGas(pre.Env.GasLimit)
|
||||
vmContext := vm.BlockContext{
|
||||
CanTransfer: core.CanTransfer,
|
||||
|
|
@ -222,6 +225,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
)
|
||||
core.ProcessParentBlockHash(prevHash, evm)
|
||||
}
|
||||
if isEIP4762 {
|
||||
core.InitializeBinaryTransitionRegistry(statedb)
|
||||
}
|
||||
for i := 0; txIt.Next(); i++ {
|
||||
tx, err := txIt.Tx()
|
||||
if err != nil {
|
||||
|
|
@ -377,7 +383,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
return statedb, execRs, body, nil
|
||||
}
|
||||
|
||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool) *state.StateDB {
|
||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool, forkBoundary bool) *state.StateDB {
|
||||
tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true, IsVerkle: isBintrie})
|
||||
sdb := state.NewDatabase(tdb, nil)
|
||||
|
||||
|
|
@ -406,6 +412,9 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool
|
|||
if isBintrie {
|
||||
return statedb
|
||||
}
|
||||
if forkBoundary {
|
||||
sdb.SetForkBoundary(root)
|
||||
}
|
||||
// For MPT mode, reopen the state with the committed root
|
||||
statedb, err = state.New(root, sdb)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -2085,7 +2085,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
|||
parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent != nil && !bc.chainConfig.IsVerkle(parent.Number, parent.Time) {
|
||||
bc.SetForkBoundary(parentRoot)
|
||||
defer bc.ClearForkBoundary()
|
||||
defer bc.ClearForkBoundary(parentRoot)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,8 +420,8 @@ func (bc *BlockChain) SetForkBoundary(root common.Hash) {
|
|||
bc.statedb.SetForkBoundary(root)
|
||||
}
|
||||
|
||||
func (bc *BlockChain) ClearForkBoundary() {
|
||||
bc.statedb.ClearForkBoundary()
|
||||
func (bc *BlockChain) ClearForkBoundary(root common.Hash) {
|
||||
bc.statedb.ClearForkBoundary(root)
|
||||
}
|
||||
|
||||
// HistoricState returns a historic state specified by the given root.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package state
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
|
|
@ -160,7 +160,7 @@ type CachingDB struct {
|
|||
// Transition-specific fields
|
||||
TransitionStatePerRoot *lru.Cache[common.Hash, *overlay.TransitionState]
|
||||
|
||||
forkBoundaryRoot atomic.Value // stores common.Hash; non-zero means fork boundary active for this root
|
||||
forkBoundaryRoots sync.Map // map[common.Hash]struct{}; set of roots at fork boundary
|
||||
}
|
||||
|
||||
// NewDatabase creates a state database with the provided data sources.
|
||||
|
|
@ -182,20 +182,16 @@ func NewDatabaseForTesting() *CachingDB {
|
|||
}
|
||||
|
||||
func (db *CachingDB) SetForkBoundary(root common.Hash) {
|
||||
db.forkBoundaryRoot.Store(root)
|
||||
db.forkBoundaryRoots.Store(root, struct{}{})
|
||||
}
|
||||
|
||||
func (db *CachingDB) ClearForkBoundary() {
|
||||
db.forkBoundaryRoot.Store(common.Hash{})
|
||||
func (db *CachingDB) ClearForkBoundary(root common.Hash) {
|
||||
db.forkBoundaryRoots.Delete(root)
|
||||
}
|
||||
|
||||
func (db *CachingDB) isForkBoundary(root common.Hash) bool {
|
||||
v := db.forkBoundaryRoot.Load()
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
stored, ok := v.(common.Hash)
|
||||
return ok && stored != (common.Hash{}) && stored == root
|
||||
_, ok := db.forkBoundaryRoots.Load(root)
|
||||
return ok
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func TestForkBoundaryOpenTrie(t *testing.T) {
|
|||
}
|
||||
|
||||
sdb.SetForkBoundary(root)
|
||||
defer sdb.ClearForkBoundary()
|
||||
defer sdb.ClearForkBoundary(root)
|
||||
|
||||
tr, err := sdb.OpenTrie(root)
|
||||
if err != nil {
|
||||
|
|
@ -80,7 +80,7 @@ func TestForkBoundaryStateReader(t *testing.T) {
|
|||
}
|
||||
|
||||
sdb.SetForkBoundary(root)
|
||||
defer sdb.ClearForkBoundary()
|
||||
defer sdb.ClearForkBoundary(root)
|
||||
|
||||
reader, err := sdb.StateReader(root)
|
||||
if err != nil {
|
||||
|
|
@ -121,7 +121,7 @@ func TestForkBoundaryWrite(t *testing.T) {
|
|||
}
|
||||
|
||||
sdb.SetForkBoundary(root)
|
||||
defer sdb.ClearForkBoundary()
|
||||
defer sdb.ClearForkBoundary(root)
|
||||
|
||||
tr, err := sdb.OpenTrie(root)
|
||||
if err != nil {
|
||||
|
|
@ -213,7 +213,7 @@ func TestForkBoundaryWrongRoot(t *testing.T) {
|
|||
|
||||
otherRoot := common.HexToHash("0xdeadbeef")
|
||||
sdb.SetForkBoundary(otherRoot)
|
||||
defer sdb.ClearForkBoundary()
|
||||
defer sdb.ClearForkBoundary(otherRoot)
|
||||
|
||||
tr, err := sdb.OpenTrie(root)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
|||
if miner.chainConfig.IsVerkle(header.Number, header.Time) &&
|
||||
!miner.chainConfig.IsVerkle(parent.Number, parent.Time) {
|
||||
miner.chain.SetForkBoundary(parent.Root)
|
||||
defer miner.chain.ClearForkBoundary()
|
||||
defer miner.chain.ClearForkBoundary(parent.Root)
|
||||
}
|
||||
// Could potentially happen if starting to mine in an odd state.
|
||||
// Note genParams.coinbase can be different with header.Coinbase
|
||||
|
|
|
|||
Loading…
Reference in a new issue