Merge pull request #24915 from karalabe/catalyst-custom-errors
core, eth, les, rpc: polish catalyst errors, add context
This commit is contained in:
commit
7aced8114f
@ -21,6 +21,39 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EngineAPIError is a standardized error message between consensus and execution
|
||||||
|
// clients, also containing any custom error message Geth might include.
|
||||||
|
type EngineAPIError struct {
|
||||||
|
code int
|
||||||
|
msg string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EngineAPIError) ErrorCode() int { return e.code }
|
||||||
|
func (e *EngineAPIError) Error() string { return e.msg }
|
||||||
|
func (e *EngineAPIError) ErrorData() interface{} {
|
||||||
|
if e.err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return struct {
|
||||||
|
Error string `json:"err"`
|
||||||
|
}{e.err.Error()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// With returns a copy of the error with a new embedded custom data field.
|
||||||
|
func (e *EngineAPIError) With(err error) *EngineAPIError {
|
||||||
|
return &EngineAPIError{
|
||||||
|
code: e.code,
|
||||||
|
msg: e.msg,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ rpc.Error = new(EngineAPIError)
|
||||||
|
_ rpc.DataError = new(EngineAPIError)
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// VALID is returned by the engine API in the following calls:
|
// VALID is returned by the engine API in the following calls:
|
||||||
// - newPayloadV1: if the payload was already known or was just validated and executed
|
// - newPayloadV1: if the payload was already known or was just validated and executed
|
||||||
@ -43,10 +76,10 @@ var (
|
|||||||
|
|
||||||
INVALIDBLOCKHASH = "INVALID_BLOCK_HASH"
|
INVALIDBLOCKHASH = "INVALID_BLOCK_HASH"
|
||||||
|
|
||||||
GenericServerError = rpc.CustomError{Code: -32000, ValidationError: "Server error"}
|
GenericServerError = &EngineAPIError{code: -32000, msg: "Server error"}
|
||||||
UnknownPayload = rpc.CustomError{Code: -38001, ValidationError: "Unknown payload"}
|
UnknownPayload = &EngineAPIError{code: -38001, msg: "Unknown payload"}
|
||||||
InvalidForkChoiceState = rpc.CustomError{Code: -38002, ValidationError: "Invalid forkchoice state"}
|
InvalidForkChoiceState = &EngineAPIError{code: -38002, msg: "Invalid forkchoice state"}
|
||||||
InvalidPayloadAttributes = rpc.CustomError{Code: -38003, ValidationError: "Invalid payload attributes"}
|
InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"}
|
||||||
|
|
||||||
STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil}
|
STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil}
|
||||||
STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil}
|
STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil}
|
||||||
|
@ -166,10 +166,10 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
|||||||
finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash)
|
finalBlock := api.eth.BlockChain().GetBlockByHash(update.FinalizedBlockHash)
|
||||||
if finalBlock == nil {
|
if finalBlock == nil {
|
||||||
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
||||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not available in database"))
|
||||||
} else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash {
|
} 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)
|
log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash)
|
||||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("final block not in canonical chain"))
|
||||||
}
|
}
|
||||||
// Set the finalized block
|
// Set the finalized block
|
||||||
api.eth.BlockChain().SetFinalized(finalBlock)
|
api.eth.BlockChain().SetFinalized(finalBlock)
|
||||||
@ -179,21 +179,19 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
|||||||
safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash)
|
safeBlock := api.eth.BlockChain().GetBlockByHash(update.SafeBlockHash)
|
||||||
if safeBlock == nil {
|
if safeBlock == nil {
|
||||||
log.Warn("Safe block not available in database")
|
log.Warn("Safe block not available in database")
|
||||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not available in database"))
|
||||||
}
|
}
|
||||||
if rawdb.ReadCanonicalHash(api.eth.ChainDb(), safeBlock.NumberU64()) != update.SafeBlockHash {
|
if rawdb.ReadCanonicalHash(api.eth.ChainDb(), safeBlock.NumberU64()) != update.SafeBlockHash {
|
||||||
log.Warn("Safe block not in canonical chain")
|
log.Warn("Safe block not in canonical chain")
|
||||||
return beacon.STATUS_INVALID, &beacon.InvalidForkChoiceState
|
return beacon.STATUS_INVALID, beacon.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
valid := func(id *beacon.PayloadID) beacon.ForkChoiceResponse {
|
valid := func(id *beacon.PayloadID) beacon.ForkChoiceResponse {
|
||||||
return beacon.ForkChoiceResponse{
|
return beacon.ForkChoiceResponse{
|
||||||
PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &update.HeadBlockHash},
|
PayloadStatus: beacon.PayloadStatusV1{Status: beacon.VALID, LatestValidHash: &update.HeadBlockHash},
|
||||||
PayloadID: id,
|
PayloadID: id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// might replace it arbitrarily many times in between.
|
// might replace it arbitrarily many times in between.
|
||||||
@ -202,14 +200,14 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
|
|||||||
empty, err := api.eth.Miner().GetSealingBlockSync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, true)
|
empty, err := api.eth.Miner().GetSealingBlockSync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create empty sealing payload", "err", err)
|
log.Error("Failed to create empty sealing payload", "err", err)
|
||||||
return valid(nil), &beacon.InvalidPayloadAttributes
|
return valid(nil), beacon.InvalidPayloadAttributes.With(err)
|
||||||
}
|
}
|
||||||
// Send a request to generate a full block in the background.
|
// Send a request to generate a full block in the background.
|
||||||
// The result can be obtained via the returned channel.
|
// The result can be obtained via the returned channel.
|
||||||
resCh, err := api.eth.Miner().GetSealingBlockAsync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, false)
|
resCh, err := api.eth.Miner().GetSealingBlockAsync(update.HeadBlockHash, payloadAttributes.Timestamp, payloadAttributes.SuggestedFeeRecipient, payloadAttributes.Random, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create async sealing payload", "err", err)
|
log.Error("Failed to create async sealing payload", "err", err)
|
||||||
return valid(nil), &beacon.InvalidPayloadAttributes
|
return valid(nil), beacon.InvalidPayloadAttributes.With(err)
|
||||||
}
|
}
|
||||||
id := computePayloadId(update.HeadBlockHash, payloadAttributes)
|
id := computePayloadId(update.HeadBlockHash, payloadAttributes)
|
||||||
api.localBlocks.put(id, &payload{empty: empty, result: resCh})
|
api.localBlocks.put(id, &payload{empty: empty, result: resCh})
|
||||||
@ -248,7 +246,7 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu
|
|||||||
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
|
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
|
||||||
data := api.localBlocks.get(payloadID)
|
data := api.localBlocks.get(payloadID)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, &beacon.UnknownPayload
|
return nil, beacon.UnknownPayload
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, pay
|
|||||||
|
|
||||||
// GetPayloadV1 returns a cached payload by id. It's not supported in les mode.
|
// GetPayloadV1 returns a cached payload by id. It's not supported in les mode.
|
||||||
func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) {
|
func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.ExecutableDataV1, error) {
|
||||||
return nil, &beacon.GenericServerError
|
return nil, beacon.GenericServerError.With(errors.New("not supported in light client mode"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
// ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
@ -157,7 +157,7 @@ func (api *ConsensusAPI) checkTerminalTotalDifficulty(head common.Hash) error {
|
|||||||
// make sure the parent has enough terminal total difficulty
|
// make sure the parent has enough terminal total difficulty
|
||||||
header := api.les.BlockChain().GetHeaderByHash(head)
|
header := api.les.BlockChain().GetHeaderByHash(head)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return &beacon.GenericServerError
|
return errors.New("unknown header")
|
||||||
}
|
}
|
||||||
td := api.les.BlockChain().GetTd(header.Hash(), header.Number.Uint64())
|
td := api.les.BlockChain().GetTd(header.Hash(), header.Number.Uint64())
|
||||||
if td != nil && td.Cmp(api.les.BlockChain().Config().TerminalTotalDifficulty) < 0 {
|
if td != nil && td.Cmp(api.les.BlockChain().Config().TerminalTotalDifficulty) < 0 {
|
||||||
@ -176,7 +176,7 @@ func (api *ConsensusAPI) setCanonical(newHead common.Hash) error {
|
|||||||
}
|
}
|
||||||
newHeadHeader := api.les.BlockChain().GetHeaderByHash(newHead)
|
newHeadHeader := api.les.BlockChain().GetHeaderByHash(newHead)
|
||||||
if newHeadHeader == nil {
|
if newHeadHeader == nil {
|
||||||
return &beacon.GenericServerError
|
return errors.New("unknown header")
|
||||||
}
|
}
|
||||||
if err := api.les.BlockChain().SetCanonical(newHeadHeader); err != nil {
|
if err := api.les.BlockChain().SetCanonical(newHeadHeader); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -54,7 +54,6 @@ var (
|
|||||||
_ Error = new(invalidRequestError)
|
_ Error = new(invalidRequestError)
|
||||||
_ Error = new(invalidMessageError)
|
_ Error = new(invalidMessageError)
|
||||||
_ Error = new(invalidParamsError)
|
_ Error = new(invalidParamsError)
|
||||||
_ Error = new(CustomError)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultErrorCode = -32000
|
const defaultErrorCode = -32000
|
||||||
@ -102,12 +101,3 @@ type invalidParamsError struct{ message string }
|
|||||||
func (e *invalidParamsError) ErrorCode() int { return -32602 }
|
func (e *invalidParamsError) ErrorCode() int { return -32602 }
|
||||||
|
|
||||||
func (e *invalidParamsError) Error() string { return e.message }
|
func (e *invalidParamsError) Error() string { return e.message }
|
||||||
|
|
||||||
type CustomError struct {
|
|
||||||
Code int
|
|
||||||
ValidationError string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *CustomError) ErrorCode() int { return e.Code }
|
|
||||||
|
|
||||||
func (e *CustomError) Error() string { return e.ValidationError }
|
|
||||||
|
Loading…
Reference in New Issue
Block a user