nimbus-eth1/nimbus/beacon/api_handler/api_utils.nim

198 lines
5.7 KiB
Nim

# Nimbus
# Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.
import
std/[typetraits, strutils],
web3/execution_types,
json_rpc/errors,
nimcrypto/sha2,
stew/endians2,
results,
../../constants,
../../db/core_db,
../../utils/utils,
../../common/common,
../../core/chain,
../web3_eth_conv
{.push gcsafe, raises:[].}
proc update(ctx: var sha256, wd: WithdrawalV1) =
ctx.update(toBytesBE distinctBase wd.index)
ctx.update(toBytesBE distinctBase wd.validatorIndex)
ctx.update(distinctBase wd.address)
ctx.update(toBytesBE distinctBase wd.amount)
proc computePayloadId*(blockHash: common.Hash32,
params: PayloadAttributes): Bytes8 =
var dest: common.Hash32
var ctx: sha256
ctx.init()
ctx.update(blockHash.data)
ctx.update(toBytesBE distinctBase params.timestamp)
ctx.update(distinctBase params.prevRandao)
ctx.update(distinctBase params.suggestedFeeRecipient)
if params.withdrawals.isSome:
for wd in params.withdrawals.get:
ctx.update(wd)
if params.parentBeaconBlockRoot.isSome:
ctx.update(distinctBase params.parentBeaconBlockRoot.get)
ctx.finish dest.data
ctx.clear()
(distinctBase result)[0..7] = dest.data[0..7]
proc validateBlockHash*(header: common.Header,
wantHash: common.Hash32,
version: Version): Result[void, PayloadStatusV1]
{.gcsafe, raises: [ValueError].} =
let gotHash = header.blockHash
if wantHash != gotHash:
let status = if version == Version.V1:
PayloadExecutionStatus.invalid_block_hash
else:
PayloadExecutionStatus.invalid
let res = PayloadStatusV1(
status: status,
validationError: Opt.some("blockhash mismatch, want $1, got $2" % [
$wantHash, $gotHash])
)
return err(res)
return ok()
template toValidHash*(x: common.Hash32): Opt[Hash32] =
Opt.some(x)
proc simpleFCU*(status: PayloadStatusV1): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus: status)
proc simpleFCU*(status: PayloadExecutionStatus): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus: PayloadStatusV1(status: status))
proc simpleFCU*(status: PayloadExecutionStatus,
msg: string): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(
payloadStatus: PayloadStatusV1(
status: status,
validationError: Opt.some(msg)
)
)
proc invalidFCU*(
validationError: string,
hash = default(common.Hash32)): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus:
PayloadStatusV1(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(hash),
validationError: Opt.some validationError
)
)
proc validFCU*(id: Opt[Bytes8],
validHash: common.Hash32): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(
payloadStatus: PayloadStatusV1(
status: PayloadExecutionStatus.valid,
latestValidHash: toValidHash(validHash)
),
payloadId: id
)
proc invalidStatus*(validHash: common.Hash32, msg: string): PayloadStatusV1 =
PayloadStatusV1(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(validHash),
validationError: Opt.some(msg)
)
proc invalidStatus*(validHash = default(common.Hash32)): PayloadStatusV1 =
PayloadStatusV1(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(validHash)
)
proc acceptedStatus*(validHash: common.Hash32): PayloadStatusV1 =
PayloadStatusV1(
status: PayloadExecutionStatus.accepted,
latestValidHash: toValidHash(validHash)
)
proc acceptedStatus*(): PayloadStatusV1 =
PayloadStatusV1(
status: PayloadExecutionStatus.accepted
)
proc validStatus*(validHash: common.Hash32): PayloadStatusV1 =
PayloadStatusV1(
status: PayloadExecutionStatus.valid,
latestValidHash: toValidHash(validHash)
)
proc invalidParams*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiInvalidParams,
msg: msg
)
proc invalidForkChoiceState*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiInvalidForkchoiceState,
msg: msg
)
proc unknownPayload*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiUnknownPayload,
msg: msg
)
proc invalidAttr*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiInvalidPayloadAttributes,
msg: msg
)
proc unsupportedFork*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiUnsupportedFork,
msg: msg
)
proc tooLargeRequest*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiTooLargeRequest,
msg: msg
)
proc latestValidHash*(db: CoreDbRef,
parent: Header,
ttd: DifficultyInt): Hash32 =
if parent.isGenesis:
return default(Hash32)
let ptd = db.getScore(parent.parentHash).valueOr(0.u256)
if ptd >= ttd:
parent.blockHash
else:
# If the most recent valid ancestor is a PoW block,
# latestValidHash MUST be set to ZERO
default(Hash32)
proc invalidFCU*(validationError: string,
chain: ForkedChainRef,
header: Header): ForkchoiceUpdatedResponse =
let parent = chain.headerByHash(header.parentHash).valueOr:
return invalidFCU(validationError)
let blockHash =
latestValidHash(chain.db, parent, chain.com.ttd.get(high(UInt256)))
invalidFCU(validationError, blockHash)