forked from cerc-io/plugeth
core: eth: rpc: implement safe rpc block (#25165)
* core: eth: rpc: implement safe rpc block * core: fix setHead, panics
This commit is contained in:
parent
f543e6b065
commit
c6dcd018d2
@ -51,6 +51,7 @@ var (
|
|||||||
headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil)
|
headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil)
|
||||||
headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil)
|
headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil)
|
||||||
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
||||||
|
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
|
||||||
|
|
||||||
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
||||||
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
||||||
@ -191,6 +192,7 @@ type BlockChain struct {
|
|||||||
currentBlock atomic.Value // Current head of the block chain
|
currentBlock atomic.Value // Current head of the block chain
|
||||||
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
||||||
currentFinalizedBlock atomic.Value // Current finalized head
|
currentFinalizedBlock atomic.Value // Current finalized head
|
||||||
|
currentSafeBlock atomic.Value // Current safe head
|
||||||
|
|
||||||
stateCache state.Database // State database to reuse between imports (contains state cache)
|
stateCache state.Database // State database to reuse between imports (contains state cache)
|
||||||
bodyCache *lru.Cache // Cache for the most recent block bodies
|
bodyCache *lru.Cache // Cache for the most recent block bodies
|
||||||
@ -267,6 +269,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
|||||||
bc.currentBlock.Store(nilBlock)
|
bc.currentBlock.Store(nilBlock)
|
||||||
bc.currentFastBlock.Store(nilBlock)
|
bc.currentFastBlock.Store(nilBlock)
|
||||||
bc.currentFinalizedBlock.Store(nilBlock)
|
bc.currentFinalizedBlock.Store(nilBlock)
|
||||||
|
bc.currentSafeBlock.Store(nilBlock)
|
||||||
|
|
||||||
// Initialize the chain with ancient data if it isn't empty.
|
// Initialize the chain with ancient data if it isn't empty.
|
||||||
var txIndexBlock uint64
|
var txIndexBlock uint64
|
||||||
@ -464,11 +467,15 @@ func (bc *BlockChain) loadLastState() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the last known finalized block
|
// Restore the last known finalized block and safe block
|
||||||
|
// Note: the safe block is not stored on disk and it is set to the last
|
||||||
|
// known finalized block on startup
|
||||||
if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) {
|
if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) {
|
||||||
if block := bc.GetBlockByHash(head); block != nil {
|
if block := bc.GetBlockByHash(head); block != nil {
|
||||||
bc.currentFinalizedBlock.Store(block)
|
bc.currentFinalizedBlock.Store(block)
|
||||||
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
||||||
|
bc.currentSafeBlock.Store(block)
|
||||||
|
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Issue a status log for the user
|
// Issue a status log for the user
|
||||||
@ -504,8 +511,23 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
|||||||
// SetFinalized sets the finalized block.
|
// SetFinalized sets the finalized block.
|
||||||
func (bc *BlockChain) SetFinalized(block *types.Block) {
|
func (bc *BlockChain) SetFinalized(block *types.Block) {
|
||||||
bc.currentFinalizedBlock.Store(block)
|
bc.currentFinalizedBlock.Store(block)
|
||||||
|
if block != nil {
|
||||||
rawdb.WriteFinalizedBlockHash(bc.db, block.Hash())
|
rawdb.WriteFinalizedBlockHash(bc.db, block.Hash())
|
||||||
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
||||||
|
} else {
|
||||||
|
rawdb.WriteFinalizedBlockHash(bc.db, common.Hash{})
|
||||||
|
headFinalizedBlockGauge.Update(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSafe sets the safe block.
|
||||||
|
func (bc *BlockChain) SetSafe(block *types.Block) {
|
||||||
|
bc.currentSafeBlock.Store(block)
|
||||||
|
if block != nil {
|
||||||
|
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
||||||
|
} else {
|
||||||
|
headSafeBlockGauge.Update(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
|
||||||
@ -663,6 +685,16 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, root common.Hash, repair bo
|
|||||||
bc.txLookupCache.Purge()
|
bc.txLookupCache.Purge()
|
||||||
bc.futureBlocks.Purge()
|
bc.futureBlocks.Purge()
|
||||||
|
|
||||||
|
// Clear safe block, finalized block if needed
|
||||||
|
if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.NumberU64() {
|
||||||
|
log.Warn("SetHead invalidated safe block")
|
||||||
|
bc.SetSafe(nil)
|
||||||
|
}
|
||||||
|
if finalized := bc.CurrentFinalizedBlock(); finalized != nil && head < finalized.NumberU64() {
|
||||||
|
log.Error("SetHead invalidated finalized block")
|
||||||
|
bc.SetFinalized(nil)
|
||||||
|
}
|
||||||
|
|
||||||
return rootNumber, bc.loadLastState()
|
return rootNumber, bc.loadLastState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,12 @@ func (bc *BlockChain) CurrentFinalizedBlock() *types.Block {
|
|||||||
return bc.currentFinalizedBlock.Load().(*types.Block)
|
return bc.currentFinalizedBlock.Load().(*types.Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CurrentSafeBlock retrieves the current safe block of the canonical
|
||||||
|
// chain. The block is retrieved from the blockchain's internal cache.
|
||||||
|
func (bc *BlockChain) CurrentSafeBlock() *types.Block {
|
||||||
|
return bc.currentSafeBlock.Load().(*types.Block)
|
||||||
|
}
|
||||||
|
|
||||||
// HasHeader checks if a block header is present in the database or not, caching
|
// HasHeader checks if a block header is present in the database or not, caching
|
||||||
// it if present.
|
// it if present.
|
||||||
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
|
@ -272,6 +272,8 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
|||||||
block = api.eth.blockchain.CurrentBlock()
|
block = api.eth.blockchain.CurrentBlock()
|
||||||
} else if blockNr == rpc.FinalizedBlockNumber {
|
} else if blockNr == rpc.FinalizedBlockNumber {
|
||||||
block = api.eth.blockchain.CurrentFinalizedBlock()
|
block = api.eth.blockchain.CurrentFinalizedBlock()
|
||||||
|
} else if blockNr == rpc.SafeBlockNumber {
|
||||||
|
block = api.eth.blockchain.CurrentSafeBlock()
|
||||||
} else {
|
} else {
|
||||||
block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
||||||
}
|
}
|
||||||
@ -350,6 +352,8 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
|||||||
block = api.eth.blockchain.CurrentBlock()
|
block = api.eth.blockchain.CurrentBlock()
|
||||||
} else if number == rpc.FinalizedBlockNumber {
|
} else if number == rpc.FinalizedBlockNumber {
|
||||||
block = api.eth.blockchain.CurrentFinalizedBlock()
|
block = api.eth.blockchain.CurrentFinalizedBlock()
|
||||||
|
} else if number == rpc.SafeBlockNumber {
|
||||||
|
block = api.eth.blockchain.CurrentSafeBlock()
|
||||||
} else {
|
} else {
|
||||||
block = api.eth.blockchain.GetBlockByNumber(uint64(number))
|
block = api.eth.blockchain.GetBlockByNumber(uint64(number))
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,18 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
|
|||||||
return b.eth.blockchain.CurrentBlock().Header(), nil
|
return b.eth.blockchain.CurrentBlock().Header(), nil
|
||||||
}
|
}
|
||||||
if number == rpc.FinalizedBlockNumber {
|
if number == rpc.FinalizedBlockNumber {
|
||||||
return b.eth.blockchain.CurrentFinalizedBlock().Header(), nil
|
block := b.eth.blockchain.CurrentFinalizedBlock()
|
||||||
|
if block != nil {
|
||||||
|
return block.Header(), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("finalized block not found")
|
||||||
|
}
|
||||||
|
if number == rpc.SafeBlockNumber {
|
||||||
|
block := b.eth.blockchain.CurrentSafeBlock()
|
||||||
|
if block != nil {
|
||||||
|
return block.Header(), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("safe block not found")
|
||||||
}
|
}
|
||||||
return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil
|
return b.eth.blockchain.GetHeaderByNumber(uint64(number)), nil
|
||||||
}
|
}
|
||||||
@ -113,6 +124,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
|||||||
if number == rpc.FinalizedBlockNumber {
|
if number == rpc.FinalizedBlockNumber {
|
||||||
return b.eth.blockchain.CurrentFinalizedBlock(), nil
|
return b.eth.blockchain.CurrentFinalizedBlock(), nil
|
||||||
}
|
}
|
||||||
|
if number == rpc.SafeBlockNumber {
|
||||||
|
return b.eth.blockchain.CurrentSafeBlock(), nil
|
||||||
|
}
|
||||||
return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
|
return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +235,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
|||||||
log.Warn("Safe block not in canonical chain")
|
log.Warn("Safe block not in canonical chain")
|
||||||
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
|
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
|
||||||
}
|
}
|
||||||
|
// Set the safe block
|
||||||
|
api.eth.BlockChain().SetSafe(safeBlock)
|
||||||
}
|
}
|
||||||
// If payload generation was requested, create a new block to be potentially
|
// If payload generation was requested, create a new block to be potentially
|
||||||
// sealed by the beacon client. The payload will be requested later, and we
|
// sealed by the beacon client. The payload will be requested later, and we
|
||||||
|
@ -3696,7 +3696,7 @@ var outputBigNumberFormatter = function (number) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var isPredefinedBlockNumber = function (blockNumber) {
|
var isPredefinedBlockNumber = function (blockNumber) {
|
||||||
return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized';
|
return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest' || blockNumber === 'finalized' || blockNumber === 'safe';
|
||||||
};
|
};
|
||||||
|
|
||||||
var inputDefaultBlockNumberFormatter = function (blockNumber) {
|
var inputDefaultBlockNumberFormatter = function (blockNumber) {
|
||||||
|
10
rpc/types.go
10
rpc/types.go
@ -61,6 +61,7 @@ type jsonWriter interface {
|
|||||||
type BlockNumber int64
|
type BlockNumber int64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
SafeBlockNumber = BlockNumber(-4)
|
||||||
FinalizedBlockNumber = BlockNumber(-3)
|
FinalizedBlockNumber = BlockNumber(-3)
|
||||||
PendingBlockNumber = BlockNumber(-2)
|
PendingBlockNumber = BlockNumber(-2)
|
||||||
LatestBlockNumber = BlockNumber(-1)
|
LatestBlockNumber = BlockNumber(-1)
|
||||||
@ -92,6 +93,9 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
|||||||
case "finalized":
|
case "finalized":
|
||||||
*bn = FinalizedBlockNumber
|
*bn = FinalizedBlockNumber
|
||||||
return nil
|
return nil
|
||||||
|
case "safe":
|
||||||
|
*bn = SafeBlockNumber
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
blckNum, err := hexutil.DecodeUint64(input)
|
blckNum, err := hexutil.DecodeUint64(input)
|
||||||
@ -118,6 +122,8 @@ func (bn BlockNumber) MarshalText() ([]byte, error) {
|
|||||||
return []byte("pending"), nil
|
return []byte("pending"), nil
|
||||||
case FinalizedBlockNumber:
|
case FinalizedBlockNumber:
|
||||||
return []byte("finalized"), nil
|
return []byte("finalized"), nil
|
||||||
|
case SafeBlockNumber:
|
||||||
|
return []byte("safe"), nil
|
||||||
default:
|
default:
|
||||||
return hexutil.Uint64(bn).MarshalText()
|
return hexutil.Uint64(bn).MarshalText()
|
||||||
}
|
}
|
||||||
@ -168,6 +174,10 @@ func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
|
|||||||
bn := FinalizedBlockNumber
|
bn := FinalizedBlockNumber
|
||||||
bnh.BlockNumber = &bn
|
bnh.BlockNumber = &bn
|
||||||
return nil
|
return nil
|
||||||
|
case "safe":
|
||||||
|
bn := SafeBlockNumber
|
||||||
|
bnh.BlockNumber = &bn
|
||||||
|
return nil
|
||||||
default:
|
default:
|
||||||
if len(input) == 66 {
|
if len(input) == 66 {
|
||||||
hash := common.Hash{}
|
hash := common.Hash{}
|
||||||
|
Loading…
Reference in New Issue
Block a user