diff --git a/core/blockchain.go b/core/blockchain.go index c53c65e68c..4242dcb335 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -244,12 +244,14 @@ type BlockChain struct { // Readers don't need to take it, they can just read the database. chainmu *syncx.ClosableMutex - currentBlock atomic.Pointer[types.Header] // Current head of the chain - currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync - currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block - currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block - currentUnsealedBlock *types.UnsealedBlock // Current unsealed block - unsealedBlockDbState *state.StateDB // StateDB for the current unsealed block + currentBlock atomic.Pointer[types.Header] // Current head of the chain + currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync + currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block + currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block + + currentUnsealedBlock *types.UnsealedBlock // Current unsealed block + unsealedBlockDbState *state.StateDB // StateDB for the current unsealed block + unsealedBlockLock sync.Mutex // Lock for the unsealedBlock bodyCache *lru.Cache[common.Hash, *types.Body] bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue] @@ -2551,3 +2553,8 @@ func (bc *BlockChain) SetTrieFlushInterval(interval time.Duration) { func (bc *BlockChain) GetTrieFlushInterval() time.Duration { return time.Duration(bc.flushInterval.Load()) } + +// UnsealedBlockLock returns a pointer to the unsealed block lock +func (bc *BlockChain) UnsealedBlockLock() *sync.Mutex { + return &bc.unsealedBlockLock +} diff --git a/eth/api_backend.go b/eth/api_backend.go index 023325625d..ce4954cefe 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -203,9 +203,16 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B // Latest state is the current open unselaed block if number == rpc.LatestBlockNumber { - stateDb := b.eth.BlockChain().CurrentUnsealedBlockState() - if stateDb != nil { - return stateDb, b.eth.BlockChain().CurrentUnsealedBlock().TempHeader(), nil + // if the lock is held, we can't access the unsealed block + if b.eth.BlockChain().UnsealedBlockLock().TryLock() { + defer b.eth.BlockChain().UnsealedBlockLock().Unlock() + + stateDb := b.eth.BlockChain().CurrentUnsealedBlockState() + if stateDb != nil { + return stateDb.Copy(), b.eth.BlockChain().CurrentUnsealedBlock().TempHeader(), nil + } + } else { + log.Warn("unsealed block lock is held, falling back to latest state") } } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index d930244e9f..a2f519e279 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -160,7 +160,6 @@ type ConsensusAPI struct { forkchoiceLock sync.Mutex // Lock for the forkChoiceUpdated method newPayloadLock sync.Mutex // Lock for the NewPayload method - unsealedBlockLock sync.Mutex // Lock for the unsealedBlock } // NewConsensusAPI creates a new consensus api for the given backend. @@ -1357,13 +1356,13 @@ func validateRequests(requests [][]byte) error { func (api *ConsensusAPI) NewFragV0(frag engine.SignedNewFrag) (string, error) { log.Info("new frag received", "forBlock", frag.Frag.BlockNumber, "current", api.eth.BlockChain().CurrentBlock().Number) - api.unsealedBlockLock.Lock() + api.eth.BlockChain().UnsealedBlockLock().Lock() res, err := api.newFragV0(frag) if err != nil { log.Error("failed to insert new frag, discarding unsealed block", "error", err) api.eth.BlockChain().ResetCurrentUnsealedBlock() } - api.unsealedBlockLock.Unlock() + api.eth.BlockChain().UnsealedBlockLock().Unlock() log.Info("new frag handled successfully") @@ -1445,13 +1444,13 @@ func (api *ConsensusAPI) SealFragV0(seal engine.SignedSeal) (string, error) { return engine.VALID, nil } - api.unsealedBlockLock.Lock() + api.eth.BlockChain().UnsealedBlockLock().Lock() res, err := api.sealFragV0(seal) if err != nil { log.Error("failed to seal block, discarding unsealed block", "error", err) api.eth.BlockChain().ResetCurrentUnsealedBlock() } - api.unsealedBlockLock.Unlock() + api.eth.BlockChain().UnsealedBlockLock().Unlock() return res, err } @@ -1521,14 +1520,14 @@ func (api *ConsensusAPI) ValidateSealFragV0(preSealedBlock *types.Block, seal en func (api *ConsensusAPI) EnvV0(env engine.SignedEnv) (string, error) { log.Info("env received", "forBlock", env.Env.Number, "current", api.eth.BlockChain().CurrentBlock().Number, "env", env.Env) - api.unsealedBlockLock.Lock() + api.eth.BlockChain().UnsealedBlockLock().Lock() res, err := api.envV0(env) if err != nil { log.Error("failed to open unsealed block, discarding unsealed block", "error", err) api.eth.BlockChain().ResetCurrentUnsealedBlock() log.Error("EnvV0 failed", "error", err) } - api.unsealedBlockLock.Unlock() + api.eth.BlockChain().UnsealedBlockLock().Unlock() log.Info("env handled successfully")