forked from cerc-io/plugeth
eth/catalyst: update implementation to spec (#24802)
* eth/catalyst: return invalid payload attributes error * eth/catalyst: implement LVH as specified, add tests * eth/catalyst: return current block hash not header hash * eth/catalyst: fix test * eth/catalyst: bring error codes in line with spec
This commit is contained in:
+18
-11
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/beacon"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
@@ -165,10 +166,10 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
||||
finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash)
|
||||
if finalBlock == nil {
|
||||
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
||||
return beacon.STATUS_INVALID, errors.New("final block not available")
|
||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
||||
} else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash {
|
||||
log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash)
|
||||
return beacon.STATUS_INVALID, errors.New("final block not canonical")
|
||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
||||
}
|
||||
// Set the finalized block
|
||||
api.eth.BlockChain().SetFinalized(finalBlock)
|
||||
@@ -178,11 +179,11 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
||||
safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash)
|
||||
if safeBlock == nil {
|
||||
log.Warn("Safe block not available in database")
|
||||
return beacon.STATUS_INVALID, errors.New("safe head not available")
|
||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
||||
}
|
||||
if rawdb.ReadCanonicalHash(api.eth.ChainDb(), safeBlock.NumberU64()) != update.SafeBlockHash {
|
||||
log.Warn("Safe block not in canonical chain")
|
||||
return beacon.STATUS_INVALID, errors.New("safe head not canonical")
|
||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,13 +201,15 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
||||
// Create an empty block first which can be used as a fallback
|
||||
empty, err := api.eth.Miner().GetSealingBlockSync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, true)
|
||||
if err != nil {
|
||||
return valid(nil), err
|
||||
log.Error("Failed to create empty sealing payload", "err", err)
|
||||
return valid(nil), &beacon.InvalidPayloadAttributes
|
||||
}
|
||||
// Send a request to generate a full block in the background.
|
||||
// The result can be obtained via the returned channel.
|
||||
resCh, err := api.eth.Miner().GetSealingBlockAsync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, false)
|
||||
if err != nil {
|
||||
return valid(nil), err
|
||||
log.Error("Failed to create async sealing payload", "err", err)
|
||||
return valid(nil), &beacon.InvalidPayloadAttributes
|
||||
}
|
||||
id := computePayloadId(update.HeadBlockHash, payloadAttributes)
|
||||
api.localBlocks.put(id, &payload{empty: empty, result: resCh})
|
||||
@@ -303,7 +306,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa
|
||||
}
|
||||
if block.Time() <= parent.Time() {
|
||||
log.Warn("Invalid timestamp", "parent", block.Time(), "block", block.Time())
|
||||
return api.invalid(errors.New("invalid timestamp")), nil
|
||||
return api.invalid(errors.New("invalid timestamp"), parent), nil
|
||||
}
|
||||
if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||
api.remoteBlocks.put(block.Hash(), block.Header())
|
||||
@@ -313,7 +316,7 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa
|
||||
log.Trace("Inserting block without sethead", "hash", block.Hash(), "number", block.Number)
|
||||
if err := api.eth.BlockChain().InsertBlockWithoutSetHead(block); err != nil {
|
||||
log.Warn("NewPayloadV1: inserting block failed", "error", err)
|
||||
return api.invalid(err), nil
|
||||
return api.invalid(err, parent), nil
|
||||
}
|
||||
// We've accepted a valid payload from the beacon client. Mark the local
|
||||
// chain transitions to notify other subsystems (e.g. downloader) of the
|
||||
@@ -339,9 +342,13 @@ func computePayloadId(headBlockHash common.Hash, params *beacon.PayloadAttribute
|
||||
return out
|
||||
}
|
||||
|
||||
// invalid returns a response "INVALID" with the latest valid hash set to the current head.
|
||||
func (api *ConsensusAPI) invalid(err error) beacon.PayloadStatusV1 {
|
||||
currentHash := api.eth.BlockChain().CurrentHeader().Hash()
|
||||
// invalid returns a response "INVALID" with the latest valid hash supplied by latest or to the current head
|
||||
// if no latestValid block was provided.
|
||||
func (api *ConsensusAPI) invalid(err error, latestValid *types.Block) beacon.PayloadStatusV1 {
|
||||
currentHash := api.eth.BlockChain().CurrentBlock().Hash()
|
||||
if latestValid != nil {
|
||||
currentHash = latestValid.Hash()
|
||||
}
|
||||
errorMsg := err.Error()
|
||||
return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: ¤tHash, ValidationError: &errorMsg}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user