VC: blinded block publishing support (#4332)
* Add blind REST API declarations and implementations. * shortLog is still not stable. * Fix shortLog issues. * Enable disabled logging statements. * Address review comments. * Avoid templates suffering from double evaluation of their params * Address review comments. * Fix compilation issue. Co-authored-by: Zahary Karadjov <zahary@status.im>
This commit is contained in:
parent
c8083f2c32
commit
8fa6064b9a
|
@ -123,6 +123,7 @@ type
|
||||||
ListFeeRecipientResponse |
|
ListFeeRecipientResponse |
|
||||||
PrepareBeaconProposer |
|
PrepareBeaconProposer |
|
||||||
ProduceBlockResponseV2 |
|
ProduceBlockResponseV2 |
|
||||||
|
ProduceBlindedBlockResponse |
|
||||||
RestIndexedErrorMessage |
|
RestIndexedErrorMessage |
|
||||||
RestErrorMessage |
|
RestErrorMessage |
|
||||||
RestValidator |
|
RestValidator |
|
||||||
|
@ -886,29 +887,31 @@ template unrecognizedFieldWarning =
|
||||||
## ForkedBeaconBlock
|
## ForkedBeaconBlock
|
||||||
template prepareForkedBlockReading(
|
template prepareForkedBlockReading(
|
||||||
reader: var JsonReader[RestJson], value: untyped,
|
reader: var JsonReader[RestJson], value: untyped,
|
||||||
version: var Option[BeaconBlockFork], data: var Option[JsonString]) =
|
version: var Option[BeaconBlockFork],
|
||||||
|
data: var Option[JsonString],
|
||||||
|
blockTypeName: cstring) =
|
||||||
for fieldName {.inject.} in readObjectFields(reader):
|
for fieldName {.inject.} in readObjectFields(reader):
|
||||||
case fieldName
|
case fieldName
|
||||||
of "version":
|
of "version":
|
||||||
if version.isSome():
|
if version.isSome():
|
||||||
reader.raiseUnexpectedField("Multiple version fields found",
|
reader.raiseUnexpectedField("Multiple version fields found",
|
||||||
"ForkedBeaconBlock")
|
blockTypeName)
|
||||||
let vres = reader.readValue(string)
|
let vres = reader.readValue(string).toLowerAscii()
|
||||||
case vres
|
case vres
|
||||||
of "PHASE0", "phase0":
|
of "phase0":
|
||||||
version = some(BeaconBlockFork.Phase0)
|
version = some(BeaconBlockFork.Phase0)
|
||||||
of "ALTAIR", "altair":
|
of "altair":
|
||||||
version = some(BeaconBlockFork.Altair)
|
version = some(BeaconBlockFork.Altair)
|
||||||
of "BELLATRIX", "bellatrix":
|
of "bellatrix":
|
||||||
version = some(BeaconBlockFork.Bellatrix)
|
version = some(BeaconBlockFork.Bellatrix)
|
||||||
of "CAPELLA", "capella":
|
of "capella":
|
||||||
version = some(BeaconBlockFork.Bellatrix)
|
version = some(BeaconBlockFork.Bellatrix)
|
||||||
else:
|
else:
|
||||||
reader.raiseUnexpectedValue("Incorrect version field value")
|
reader.raiseUnexpectedValue("Incorrect version field value")
|
||||||
of "block", "block_header", "data":
|
of "block", "block_header", "data":
|
||||||
if data.isSome():
|
if data.isSome():
|
||||||
reader.raiseUnexpectedField("Multiple block or block_header fields found",
|
reader.raiseUnexpectedField("Multiple block or block_header fields found",
|
||||||
"ForkedBeaconBlock")
|
blockTypeName)
|
||||||
data = some(reader.readValue(JsonString))
|
data = some(reader.readValue(JsonString))
|
||||||
else:
|
else:
|
||||||
unrecognizedFieldWarning()
|
unrecognizedFieldWarning()
|
||||||
|
@ -925,7 +928,7 @@ proc readValue*[BlockType: ForkedBeaconBlock](
|
||||||
version: Option[BeaconBlockFork]
|
version: Option[BeaconBlockFork]
|
||||||
data: Option[JsonString]
|
data: Option[JsonString]
|
||||||
|
|
||||||
prepareForkedBlockReading(reader, value, version, data)
|
prepareForkedBlockReading(reader, value, version, data, "ForkedBeaconBlock")
|
||||||
|
|
||||||
case version.get():
|
case version.get():
|
||||||
of BeaconBlockFork.Phase0:
|
of BeaconBlockFork.Phase0:
|
||||||
|
@ -967,6 +970,57 @@ proc readValue*[BlockType: ForkedBeaconBlock](
|
||||||
of BeaconBlockFork.Capella:
|
of BeaconBlockFork.Capella:
|
||||||
reader.raiseUnexpectedValue($capellaImplementationMissing)
|
reader.raiseUnexpectedValue($capellaImplementationMissing)
|
||||||
|
|
||||||
|
proc readValue*[BlockType: ForkedBlindedBeaconBlock](
|
||||||
|
reader: var JsonReader[RestJson],
|
||||||
|
value: var BlockType
|
||||||
|
) {.raises: [IOError, SerializationError, Defect].} =
|
||||||
|
var
|
||||||
|
version: Option[BeaconBlockFork]
|
||||||
|
data: Option[JsonString]
|
||||||
|
|
||||||
|
prepareForkedBlockReading(reader, value, version, data,
|
||||||
|
"ForkedBlindedBeaconBlock")
|
||||||
|
|
||||||
|
case version.get():
|
||||||
|
of BeaconBlockFork.Phase0:
|
||||||
|
let res =
|
||||||
|
try:
|
||||||
|
RestJson.decode(string(data.get()),
|
||||||
|
phase0.BeaconBlock,
|
||||||
|
requireAllFields = true,
|
||||||
|
allowUnknownFields = true)
|
||||||
|
except SerializationError as exc:
|
||||||
|
reader.raiseUnexpectedValue("Incorrect phase0 block format, [" &
|
||||||
|
exc.formatMsg("BlindedBlock") & "]")
|
||||||
|
value = ForkedBlindedBeaconBlock(kind: BeaconBlockFork.Phase0,
|
||||||
|
phase0Data: res)
|
||||||
|
of BeaconBlockFork.Altair:
|
||||||
|
let res =
|
||||||
|
try:
|
||||||
|
RestJson.decode(string(data.get()),
|
||||||
|
altair.BeaconBlock,
|
||||||
|
requireAllFields = true,
|
||||||
|
allowUnknownFields = true)
|
||||||
|
except SerializationError as exc:
|
||||||
|
reader.raiseUnexpectedValue("Incorrect altair block format, [" &
|
||||||
|
exc.formatMsg("BlindedBlock") & "]")
|
||||||
|
value = ForkedBlindedBeaconBlock(kind: BeaconBlockFork.Altair,
|
||||||
|
altairData: res)
|
||||||
|
of BeaconBlockFork.Bellatrix:
|
||||||
|
let res =
|
||||||
|
try:
|
||||||
|
RestJson.decode(string(data.get()),
|
||||||
|
BlindedBeaconBlock,
|
||||||
|
requireAllFields = true,
|
||||||
|
allowUnknownFields = true)
|
||||||
|
except SerializationError as exc:
|
||||||
|
reader.raiseUnexpectedValue("Incorrect bellatrix block format, [" &
|
||||||
|
exc.formatMsg("BlindedBlock") & "]")
|
||||||
|
value = ForkedBlindedBeaconBlock(kind: BeaconBlockFork.Bellatrix,
|
||||||
|
bellatrixData: res)
|
||||||
|
of BeaconBlockFork.Capella:
|
||||||
|
reader.raiseUnexpectedValue($capellaImplementationMissing)
|
||||||
|
|
||||||
proc readValue*[BlockType: Web3SignerForkedBeaconBlock](
|
proc readValue*[BlockType: Web3SignerForkedBeaconBlock](
|
||||||
reader: var JsonReader[RestJson],
|
reader: var JsonReader[RestJson],
|
||||||
value: var BlockType) {.raises: [IOError, SerializationError, Defect].} =
|
value: var BlockType) {.raises: [IOError, SerializationError, Defect].} =
|
||||||
|
@ -974,7 +1028,8 @@ proc readValue*[BlockType: Web3SignerForkedBeaconBlock](
|
||||||
version: Option[BeaconBlockFork]
|
version: Option[BeaconBlockFork]
|
||||||
data: Option[JsonString]
|
data: Option[JsonString]
|
||||||
|
|
||||||
prepareForkedBlockReading(reader, value, version, data)
|
prepareForkedBlockReading(reader, value, version, data,
|
||||||
|
"Web3SignerForkedBeaconBlock")
|
||||||
|
|
||||||
case version.get():
|
case version.get():
|
||||||
of BeaconBlockFork.Phase0:
|
of BeaconBlockFork.Phase0:
|
||||||
|
|
|
@ -13,6 +13,7 @@ import
|
||||||
chronos, presto/client, chronicles,
|
chronos, presto/client, chronicles,
|
||||||
".."/".."/validators/slashing_protection_common,
|
".."/".."/validators/slashing_protection_common,
|
||||||
".."/datatypes/[phase0, altair, bellatrix],
|
".."/datatypes/[phase0, altair, bellatrix],
|
||||||
|
".."/mev/bellatrix_mev,
|
||||||
".."/[helpers, forks, keystore, eth2_ssz_serialization],
|
".."/[helpers, forks, keystore, eth2_ssz_serialization],
|
||||||
"."/[rest_types, rest_common, eth2_rest_serialization]
|
"."/[rest_types, rest_common, eth2_rest_serialization]
|
||||||
|
|
||||||
|
@ -135,6 +136,33 @@ proc publishSszBlock*(
|
||||||
extraHeaders = @[("eth-consensus-version", consensus)])
|
extraHeaders = @[("eth-consensus-version", consensus)])
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
proc publishBlindedBlock*(body: phase0.SignedBeaconBlock): RestPlainResponse {.
|
||||||
|
rest, endpoint: "/eth/v1/beacon/blinded_blocks",
|
||||||
|
meth: MethodPost.}
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
|
||||||
|
proc publishBlindedBlock*(body: altair.SignedBeaconBlock): RestPlainResponse {.
|
||||||
|
rest, endpoint: "/eth/v1/beacon/blinded_blocks",
|
||||||
|
meth: MethodPost.}
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
|
||||||
|
proc publishBlindedBlock*(body: SignedBlindedBeaconBlock): RestPlainResponse {.
|
||||||
|
rest, endpoint: "/eth/v1/beacon/blinded_blocks",
|
||||||
|
meth: MethodPost.}
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
|
||||||
|
proc publishSszBlindedBlock*(
|
||||||
|
client: RestClientRef,
|
||||||
|
blck: ForkySignedBeaconBlock
|
||||||
|
): Future[RestPlainResponse] {.async.} =
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
let
|
||||||
|
consensus = typeof(blck).toFork.toString()
|
||||||
|
resp = await client.publishBlindedBlock(
|
||||||
|
blck, restContentType = $OctetStreamMediaType,
|
||||||
|
extraHeaders = @[("eth-consensus-version", consensus)])
|
||||||
|
return resp
|
||||||
|
|
||||||
proc getBlockV2Plain*(block_id: BlockIdent): RestPlainResponse {.
|
proc getBlockV2Plain*(block_id: BlockIdent): RestPlainResponse {.
|
||||||
rest, endpoint: "/eth/v2/beacon/blocks/{block_id}",
|
rest, endpoint: "/eth/v2/beacon/blocks/{block_id}",
|
||||||
accept: preferSSZ,
|
accept: preferSSZ,
|
||||||
|
|
|
@ -604,6 +604,7 @@ type
|
||||||
ProduceAttestationDataResponse* = DataEnclosedObject[AttestationData]
|
ProduceAttestationDataResponse* = DataEnclosedObject[AttestationData]
|
||||||
ProduceBlockResponse* = DataEnclosedObject[phase0.BeaconBlock]
|
ProduceBlockResponse* = DataEnclosedObject[phase0.BeaconBlock]
|
||||||
ProduceBlockResponseV2* = ForkedBeaconBlock
|
ProduceBlockResponseV2* = ForkedBeaconBlock
|
||||||
|
ProduceBlindedBlockResponse* = ForkedBlindedBeaconBlock
|
||||||
ProduceSyncCommitteeContributionResponse* = DataEnclosedObject[SyncCommitteeContribution]
|
ProduceSyncCommitteeContributionResponse* = DataEnclosedObject[SyncCommitteeContribution]
|
||||||
SubmitBlindedBlockResponse* = DataEnclosedObject[bellatrix.ExecutionPayload]
|
SubmitBlindedBlockResponse* = DataEnclosedObject[bellatrix.ExecutionPayload]
|
||||||
GetValidatorsActivityResponse* = DataEnclosedObject[seq[RestActivityItem]]
|
GetValidatorsActivityResponse* = DataEnclosedObject[seq[RestActivityItem]]
|
||||||
|
|
|
@ -41,6 +41,13 @@ proc produceBlockV2*(slot: Slot, randao_reveal: ValidatorSig,
|
||||||
meth: MethodGet.}
|
meth: MethodGet.}
|
||||||
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlockV2
|
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlockV2
|
||||||
|
|
||||||
|
proc produceBlindedBlock*(slot: Slot, randao_reveal: ValidatorSig,
|
||||||
|
graffiti: GraffitiBytes
|
||||||
|
): RestResponse[ProduceBlindedBlockResponse] {.
|
||||||
|
rest, endpoint: "/eth/v1/validator/blinded_blocks/{slot}",
|
||||||
|
meth: MethodGet.}
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlindedBlock
|
||||||
|
|
||||||
proc produceAttestationData*(slot: Slot,
|
proc produceAttestationData*(slot: Slot,
|
||||||
committee_index: CommitteeIndex
|
committee_index: CommitteeIndex
|
||||||
): RestResponse[ProduceAttestationDataResponse] {.
|
): RestResponse[ProduceAttestationDataResponse] {.
|
||||||
|
|
|
@ -22,7 +22,7 @@ import
|
||||||
# it sequentially
|
# it sequentially
|
||||||
export
|
export
|
||||||
extras, block_id, phase0, altair, bellatrix, eth2_merkleization,
|
extras, block_id, phase0, altair, bellatrix, eth2_merkleization,
|
||||||
eth2_ssz_serialization, presets
|
eth2_ssz_serialization, presets, bellatrix_mev
|
||||||
|
|
||||||
# This file contains helpers for dealing with forks - we have two ways we can
|
# This file contains helpers for dealing with forks - we have two ways we can
|
||||||
# deal with forks:
|
# deal with forks:
|
||||||
|
@ -159,6 +159,18 @@ type
|
||||||
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
|
of BeaconBlockFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
|
||||||
of BeaconBlockFork.Capella: capellaData*: capella.SignedBeaconBlock
|
of BeaconBlockFork.Capella: capellaData*: capella.SignedBeaconBlock
|
||||||
|
|
||||||
|
ForkySignedBlindedBeaconBlock* =
|
||||||
|
phase0.SignedBeaconBlock |
|
||||||
|
altair.SignedBeaconBlock |
|
||||||
|
SignedBlindedBeaconBlock
|
||||||
|
|
||||||
|
ForkedSignedBlindedBeaconBlock* = object
|
||||||
|
case kind*: BeaconBlockFork
|
||||||
|
of BeaconBlockFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
|
||||||
|
of BeaconBlockFork.Altair: altairData*: altair.SignedBeaconBlock
|
||||||
|
of BeaconBlockFork.Bellatrix: bellatrixData*: SignedBlindedBeaconBlock
|
||||||
|
of BeaconBlockFork.Capella: capellaData*: SignedBlindedBeaconBlock
|
||||||
|
|
||||||
ForkySigVerifiedSignedBeaconBlock* =
|
ForkySigVerifiedSignedBeaconBlock* =
|
||||||
phase0.SigVerifiedSignedBeaconBlock |
|
phase0.SigVerifiedSignedBeaconBlock |
|
||||||
altair.SigVerifiedSignedBeaconBlock |
|
altair.SigVerifiedSignedBeaconBlock |
|
||||||
|
@ -265,8 +277,8 @@ template init*(T: type ForkedSignedBeaconBlock, blck: bellatrix.SignedBeaconBloc
|
||||||
template init*(T: type ForkedSignedBeaconBlock, blck: capella.SignedBeaconBlock): T =
|
template init*(T: type ForkedSignedBeaconBlock, blck: capella.SignedBeaconBlock): T =
|
||||||
T(kind: BeaconBlockFork.Capella, capellaData: blck)
|
T(kind: BeaconBlockFork.Capella, capellaData: blck)
|
||||||
|
|
||||||
template init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
|
func init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
|
||||||
blockRoot: Eth2Digest, signature: ValidatorSig): T =
|
blockRoot: Eth2Digest, signature: ValidatorSig): T =
|
||||||
case forked.kind
|
case forked.kind
|
||||||
of BeaconBlockFork.Phase0:
|
of BeaconBlockFork.Phase0:
|
||||||
T(kind: BeaconBlockFork.Phase0,
|
T(kind: BeaconBlockFork.Phase0,
|
||||||
|
@ -289,6 +301,29 @@ template init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
|
||||||
root: blockRoot,
|
root: blockRoot,
|
||||||
signature: signature))
|
signature: signature))
|
||||||
|
|
||||||
|
func init*(T: type ForkedSignedBlindedBeaconBlock,
|
||||||
|
forked: ForkedBlindedBeaconBlock, blockRoot: Eth2Digest,
|
||||||
|
signature: ValidatorSig): T =
|
||||||
|
case forked.kind
|
||||||
|
of BeaconBlockFork.Phase0:
|
||||||
|
T(kind: BeaconBlockFork.Phase0,
|
||||||
|
phase0Data: phase0.SignedBeaconBlock(message: forked.phase0Data,
|
||||||
|
root: blockRoot,
|
||||||
|
signature: signature))
|
||||||
|
of BeaconBlockFork.Altair:
|
||||||
|
T(kind: BeaconBlockFork.Altair,
|
||||||
|
altairData: altair.SignedBeaconBlock(message: forked.altairData,
|
||||||
|
root: blockRoot,
|
||||||
|
signature: signature))
|
||||||
|
of BeaconBlockFork.Bellatrix:
|
||||||
|
T(kind: BeaconBlockFork.Bellatrix,
|
||||||
|
bellatrixData: SignedBlindedBeaconBlock(message: forked.bellatrixData,
|
||||||
|
signature: signature))
|
||||||
|
of BeaconBlockFork.Capella:
|
||||||
|
T(kind: BeaconBlockFork.Capella,
|
||||||
|
capellaData: SignedBlindedBeaconBlock(message: forked.capellaData,
|
||||||
|
signature: signature))
|
||||||
|
|
||||||
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: phase0.MsgTrustedSignedBeaconBlock): T =
|
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: phase0.MsgTrustedSignedBeaconBlock): T =
|
||||||
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
|
||||||
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: altair.MsgTrustedSignedBeaconBlock): T =
|
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: altair.MsgTrustedSignedBeaconBlock): T =
|
||||||
|
@ -536,7 +571,8 @@ template asTrusted*(
|
||||||
template withBlck*(
|
template withBlck*(
|
||||||
x: ForkedBeaconBlock | Web3SignerForkedBeaconBlock |
|
x: ForkedBeaconBlock | Web3SignerForkedBeaconBlock |
|
||||||
ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock |
|
ForkedSignedBeaconBlock | ForkedMsgTrustedSignedBeaconBlock |
|
||||||
ForkedTrustedSignedBeaconBlock,
|
ForkedTrustedSignedBeaconBlock | ForkedBlindedBeaconBlock |
|
||||||
|
ForkedSignedBlindedBeaconBlock,
|
||||||
body: untyped): untyped =
|
body: untyped): untyped =
|
||||||
case x.kind
|
case x.kind
|
||||||
of BeaconBlockFork.Phase0:
|
of BeaconBlockFork.Phase0:
|
||||||
|
@ -576,7 +612,8 @@ template getForkedBlockField*(
|
||||||
of BeaconBlockFork.Capella: unsafeAddr x.capellaData.message.y)[]
|
of BeaconBlockFork.Capella: unsafeAddr x.capellaData.message.y)[]
|
||||||
|
|
||||||
template signature*(x: ForkedSignedBeaconBlock |
|
template signature*(x: ForkedSignedBeaconBlock |
|
||||||
ForkedMsgTrustedSignedBeaconBlock): ValidatorSig =
|
ForkedMsgTrustedSignedBeaconBlock |
|
||||||
|
ForkedSignedBlindedBeaconBlock): ValidatorSig =
|
||||||
withBlck(x): blck.signature
|
withBlck(x): blck.signature
|
||||||
|
|
||||||
template signature*(x: ForkedTrustedSignedBeaconBlock): TrustedSig =
|
template signature*(x: ForkedTrustedSignedBeaconBlock): TrustedSig =
|
||||||
|
@ -592,12 +629,13 @@ template slot*(x: ForkedSignedBeaconBlock |
|
||||||
ForkedTrustedSignedBeaconBlock): Slot =
|
ForkedTrustedSignedBeaconBlock): Slot =
|
||||||
withBlck(x): blck.message.slot
|
withBlck(x): blck.message.slot
|
||||||
|
|
||||||
template shortLog*(x: ForkedBeaconBlock): auto =
|
template shortLog*(x: ForkedBeaconBlock | ForkedBlindedBeaconBlock): auto =
|
||||||
withBlck(x): shortLog(blck)
|
withBlck(x): shortLog(blck)
|
||||||
|
|
||||||
template shortLog*(x: ForkedSignedBeaconBlock |
|
template shortLog*(x: ForkedSignedBeaconBlock |
|
||||||
ForkedMsgTrustedSignedBeaconBlock |
|
ForkedMsgTrustedSignedBeaconBlock |
|
||||||
ForkedTrustedSignedBeaconBlock): auto =
|
ForkedTrustedSignedBeaconBlock |
|
||||||
|
ForkedSignedBlindedBeaconBlock): auto =
|
||||||
withBlck(x): shortLog(blck)
|
withBlck(x): shortLog(blck)
|
||||||
|
|
||||||
chronicles.formatIt ForkedBeaconBlock: it.shortLog
|
chronicles.formatIt ForkedBeaconBlock: it.shortLog
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ".."/datatypes/[altair, bellatrix]
|
import ".."/datatypes/[altair, bellatrix]
|
||||||
|
from stew/byteutils import to0xHex
|
||||||
|
|
||||||
when (NimMajor, NimMinor) < (1, 4):
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
@ -76,6 +77,18 @@ func shortLog*(v: BlindedBeaconBlock): auto =
|
||||||
proposer_index: v.proposer_index,
|
proposer_index: v.proposer_index,
|
||||||
parent_root: shortLog(v.parent_root),
|
parent_root: shortLog(v.parent_root),
|
||||||
state_root: shortLog(v.state_root),
|
state_root: shortLog(v.state_root),
|
||||||
|
eth1data: v.body.eth1_data,
|
||||||
|
graffiti: $v.body.graffiti,
|
||||||
|
proposer_slashings_len: v.body.proposer_slashings.len(),
|
||||||
|
attester_slashings_len: v.body.attester_slashings.len(),
|
||||||
|
attestations_len: v.body.attestations.len(),
|
||||||
|
deposits_len: v.body.deposits.len(),
|
||||||
|
voluntary_exits_len: v.body.voluntary_exits.len(),
|
||||||
|
sync_committee_participants:
|
||||||
|
countOnes(v.body.sync_aggregate.sync_committee_bits),
|
||||||
|
block_number: v.body.execution_payload_header.block_number,
|
||||||
|
# TODO checksum hex? shortlog?
|
||||||
|
fee_recipient: to0xHex(v.body.execution_payload_header.fee_recipient.data),
|
||||||
)
|
)
|
||||||
|
|
||||||
func shortLog*(v: SignedBlindedBeaconBlock): auto =
|
func shortLog*(v: SignedBlindedBeaconBlock): auto =
|
||||||
|
|
|
@ -1772,6 +1772,200 @@ proc publishBlock*(
|
||||||
|
|
||||||
raise newException(ValidatorApiError, ErrorMessage)
|
raise newException(ValidatorApiError, ErrorMessage)
|
||||||
|
|
||||||
|
proc produceBlindedBlock*(
|
||||||
|
vc: ValidatorClientRef,
|
||||||
|
slot: Slot,
|
||||||
|
randao_reveal: ValidatorSig,
|
||||||
|
graffiti: GraffitiBytes,
|
||||||
|
strategy: ApiStrategyKind
|
||||||
|
): Future[ProduceBlindedBlockResponse] {.async.} =
|
||||||
|
logScope:
|
||||||
|
request = "produceBlindedBlock"
|
||||||
|
strategy = $strategy
|
||||||
|
|
||||||
|
const ErrorMessage = "Unable to retrieve block data"
|
||||||
|
|
||||||
|
case strategy
|
||||||
|
of ApiStrategyKind.First, ApiStrategyKind.Best:
|
||||||
|
let res = vc.firstSuccessParallel(
|
||||||
|
RestResponse[ProduceBlindedBlockResponse],
|
||||||
|
SlotDuration, {BeaconNodeRole.BlockProposalData},
|
||||||
|
produceBlindedBlock(it, slot, randao_reveal, graffiti)):
|
||||||
|
if apiResponse.isErr():
|
||||||
|
debug ErrorMessage, endpoint = node, error = apiResponse.error()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
else:
|
||||||
|
let response = apiResponse.get()
|
||||||
|
case response.status:
|
||||||
|
of 200:
|
||||||
|
trace ResponseSuccess, endpoint = node
|
||||||
|
RestBeaconNodeStatus.Online
|
||||||
|
of 400:
|
||||||
|
debug ResponseInvalidError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Incompatible
|
||||||
|
of 500:
|
||||||
|
debug ResponseInternalError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
of 503:
|
||||||
|
debug ResponseNoSyncError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.NotSynced
|
||||||
|
else:
|
||||||
|
debug ResponseUnexpectedError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
if res.isErr():
|
||||||
|
raise newException(ValidatorApiError, res.error())
|
||||||
|
return res.get().data
|
||||||
|
|
||||||
|
of ApiStrategyKind.Priority:
|
||||||
|
vc.firstSuccessSequential(
|
||||||
|
RestResponse[ProduceBlindedBlockResponse],
|
||||||
|
SlotDuration, {BeaconNodeRole.BlockProposalData},
|
||||||
|
produceBlindedBlock(it, slot, randao_reveal, graffiti)):
|
||||||
|
if apiResponse.isErr():
|
||||||
|
debug ErrorMessage, endpoint = node, error = apiResponse.error()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
else:
|
||||||
|
let response = apiResponse.get()
|
||||||
|
case response.status:
|
||||||
|
of 200:
|
||||||
|
trace ResponseSuccess, endpoint = node
|
||||||
|
return response.data
|
||||||
|
of 400:
|
||||||
|
debug ResponseInvalidError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Incompatible
|
||||||
|
of 500:
|
||||||
|
debug ResponseInternalError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
of 503:
|
||||||
|
debug ResponseNoSyncError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.NotSynced
|
||||||
|
else:
|
||||||
|
debug ResponseUnexpectedError, response_code = response.status,
|
||||||
|
endpoint = node
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
|
||||||
|
raise newException(ValidatorApiError, ErrorMessage)
|
||||||
|
|
||||||
|
proc publishBlindedBlock*(
|
||||||
|
vc: ValidatorClientRef,
|
||||||
|
data: ForkedSignedBlindedBeaconBlock,
|
||||||
|
strategy: ApiStrategyKind
|
||||||
|
): Future[bool] {.async.} =
|
||||||
|
logScope:
|
||||||
|
request = "publishBlindedBlock"
|
||||||
|
strategy = $strategy
|
||||||
|
|
||||||
|
const
|
||||||
|
BlockPublished = "Block was successfully published"
|
||||||
|
BlockBroadcasted = "Block not passed validation, but still published"
|
||||||
|
ErrorMessage = "Unable to publish block"
|
||||||
|
|
||||||
|
case strategy
|
||||||
|
of ApiStrategyKind.First, ApiStrategyKind.Best:
|
||||||
|
let res = block:
|
||||||
|
vc.firstSuccessParallel(RestPlainResponse, SlotDuration,
|
||||||
|
{BeaconNodeRole.BlockProposalPublish}):
|
||||||
|
case data.kind
|
||||||
|
of BeaconBlockFork.Phase0:
|
||||||
|
publishBlindedBlock(it, data.phase0Data)
|
||||||
|
of BeaconBlockFork.Altair:
|
||||||
|
publishBlindedBlock(it, data.altairData)
|
||||||
|
of BeaconBlockFork.Bellatrix:
|
||||||
|
publishBlindedBlock(it, data.bellatrixData)
|
||||||
|
of BeaconBlockFork.Capella:
|
||||||
|
raiseAssert $capellaImplementationMissing
|
||||||
|
do:
|
||||||
|
if apiResponse.isErr():
|
||||||
|
debug ErrorMessage, endpoint = node, error = apiResponse.error()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
else:
|
||||||
|
let response = apiResponse.get()
|
||||||
|
case response.status:
|
||||||
|
of 200:
|
||||||
|
trace BlockPublished, endpoint = node
|
||||||
|
RestBeaconNodeStatus.Online
|
||||||
|
of 202:
|
||||||
|
debug BlockBroadcasted, endpoint = node
|
||||||
|
RestBeaconNodeStatus.Online
|
||||||
|
of 400:
|
||||||
|
debug ResponseInvalidError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Incompatible
|
||||||
|
of 500:
|
||||||
|
debug ResponseInternalError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
of 503:
|
||||||
|
debug ResponseNoSyncError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.NotSynced
|
||||||
|
else:
|
||||||
|
debug ResponseUnexpectedError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
if res.isErr():
|
||||||
|
raise newException(ValidatorApiError, res.error())
|
||||||
|
return true
|
||||||
|
|
||||||
|
of ApiStrategyKind.Priority:
|
||||||
|
vc.firstSuccessSequential(RestPlainResponse, SlotDuration,
|
||||||
|
{BeaconNodeRole.BlockProposalPublish}):
|
||||||
|
case data.kind
|
||||||
|
of BeaconBlockFork.Phase0:
|
||||||
|
publishBlindedBlock(it, data.phase0Data)
|
||||||
|
of BeaconBlockFork.Altair:
|
||||||
|
publishBlindedBlock(it, data.altairData)
|
||||||
|
of BeaconBlockFork.Bellatrix:
|
||||||
|
publishBlindedBlock(it, data.bellatrixData)
|
||||||
|
of BeaconBlockFork.Capella:
|
||||||
|
raiseAssert $capellaImplementationMissing
|
||||||
|
do:
|
||||||
|
if apiResponse.isErr():
|
||||||
|
debug ErrorMessage, endpoint = node, error = apiResponse.error()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
else:
|
||||||
|
let response = apiResponse.get()
|
||||||
|
case response.status:
|
||||||
|
of 200:
|
||||||
|
trace BlockPublished, endpoint = node
|
||||||
|
return true
|
||||||
|
of 202:
|
||||||
|
debug BlockBroadcasted, endpoint = node
|
||||||
|
return true
|
||||||
|
of 400:
|
||||||
|
debug ResponseInvalidError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Incompatible
|
||||||
|
of 500:
|
||||||
|
debug ResponseInternalError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
of 503:
|
||||||
|
debug ResponseNoSyncError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.NotSynced
|
||||||
|
else:
|
||||||
|
debug ResponseUnexpectedError, response_code = response.status,
|
||||||
|
endpoint = node,
|
||||||
|
response_error = response.getErrorMessage()
|
||||||
|
RestBeaconNodeStatus.Offline
|
||||||
|
|
||||||
|
raise newException(ValidatorApiError, ErrorMessage)
|
||||||
|
|
||||||
proc prepareBeaconCommitteeSubnet*(
|
proc prepareBeaconCommitteeSubnet*(
|
||||||
vc: ValidatorClientRef,
|
vc: ValidatorClientRef,
|
||||||
data: seq[RestCommitteeSubscription],
|
data: seq[RestCommitteeSubscription],
|
||||||
|
|
|
@ -13,6 +13,82 @@ import
|
||||||
|
|
||||||
logScope: service = "block_service"
|
logScope: service = "block_service"
|
||||||
|
|
||||||
|
type
|
||||||
|
PreparedBeaconBlock = object
|
||||||
|
blockRoot*: Eth2Digest
|
||||||
|
data*: ForkedBeaconBlock
|
||||||
|
|
||||||
|
PreparedBlindedBeaconBlock = object
|
||||||
|
blockRoot*: Eth2Digest
|
||||||
|
data*: ForkedBlindedBeaconBlock
|
||||||
|
|
||||||
|
proc produceBlock(
|
||||||
|
vc: ValidatorClientRef,
|
||||||
|
currentSlot, slot: Slot,
|
||||||
|
randao_reveal: ValidatorSig,
|
||||||
|
graffiti: GraffitiBytes,
|
||||||
|
validator: AttachedValidator
|
||||||
|
): Future[Opt[PreparedBeaconBlock]] {.async.} =
|
||||||
|
logScope:
|
||||||
|
slot = slot
|
||||||
|
wall_slot = currentSlot
|
||||||
|
validator = shortLog(validator)
|
||||||
|
let
|
||||||
|
beaconBlock =
|
||||||
|
try:
|
||||||
|
await vc.produceBlockV2(slot, randao_reveal, graffiti,
|
||||||
|
ApiStrategyKind.Best)
|
||||||
|
except ValidatorApiError:
|
||||||
|
error "Unable to retrieve block data"
|
||||||
|
return Opt.none(PreparedBeaconBlock)
|
||||||
|
except CancelledError as exc:
|
||||||
|
error "Block data production has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while getting block data",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return Opt.none(PreparedBeaconBlock)
|
||||||
|
blockRoot = withBlck(beaconBlock): hash_tree_root(blck)
|
||||||
|
|
||||||
|
return Opt.some(PreparedBeaconBlock(blockRoot: blockRoot, data: beaconBlock))
|
||||||
|
|
||||||
|
proc produceBlindedBlock(
|
||||||
|
vc: ValidatorClientRef,
|
||||||
|
currentSlot, slot: Slot,
|
||||||
|
randao_reveal: ValidatorSig,
|
||||||
|
graffiti: GraffitiBytes,
|
||||||
|
validator: AttachedValidator
|
||||||
|
): Future[Opt[PreparedBlindedBeaconBlock]] {.async.} =
|
||||||
|
logScope:
|
||||||
|
slot = slot
|
||||||
|
wall_slot = currentSlot
|
||||||
|
validator = shortLog(validator)
|
||||||
|
let
|
||||||
|
beaconBlock =
|
||||||
|
try:
|
||||||
|
await vc.produceBlindedBlock(slot, randao_reveal, graffiti,
|
||||||
|
ApiStrategyKind.Best)
|
||||||
|
except ValidatorApiError:
|
||||||
|
error "Unable to retrieve blinded block data"
|
||||||
|
return Opt.none(PreparedBlindedBeaconBlock)
|
||||||
|
except CancelledError as exc:
|
||||||
|
error "Blinded block data production has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while getting blinded block data",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return Opt.none(PreparedBlindedBeaconBlock)
|
||||||
|
blockRoot = withBlck(beaconBlock): hash_tree_root(blck)
|
||||||
|
|
||||||
|
return Opt.some(
|
||||||
|
PreparedBlindedBeaconBlock(blockRoot: blockRoot, data: beaconBlock))
|
||||||
|
|
||||||
|
proc lazyWait[T](fut: Future[T]) {.async.} =
|
||||||
|
try:
|
||||||
|
discard await fut
|
||||||
|
except CatchableError:
|
||||||
|
discard
|
||||||
|
|
||||||
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
validator: AttachedValidator) {.async.} =
|
validator: AttachedValidator) {.async.} =
|
||||||
let
|
let
|
||||||
|
@ -25,123 +101,204 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
fork = vc.forkAtEpoch(slot.epoch)
|
fork = vc.forkAtEpoch(slot.epoch)
|
||||||
vindex = validator.index.get()
|
vindex = validator.index.get()
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
validator = shortLog(validator)
|
||||||
|
validator_index = vindex
|
||||||
|
slot = slot
|
||||||
|
wall_slot = currentSlot
|
||||||
|
|
||||||
if not(vc.doppelgangerCheck(validator)):
|
if not(vc.doppelgangerCheck(validator)):
|
||||||
info "Block has not been produced (doppelganger check still active)",
|
info "Block has not been produced (doppelganger check still active)"
|
||||||
slot = slot, validator = shortLog(validator),
|
|
||||||
validator_index = vindex
|
|
||||||
return
|
return
|
||||||
|
|
||||||
debug "Publishing block", validator = shortLog(validator),
|
debug "Publishing block", delay = vc.getDelay(slot.block_deadline()),
|
||||||
delay = vc.getDelay(slot.block_deadline()),
|
|
||||||
wall_slot = currentSlot,
|
|
||||||
genesis_root = genesisRoot,
|
genesis_root = genesisRoot,
|
||||||
graffiti = graffiti, fork = fork, slot = slot,
|
graffiti = graffiti, fork = fork
|
||||||
wall_slot = currentSlot
|
|
||||||
let randaoReveal =
|
let randaoReveal =
|
||||||
try:
|
try:
|
||||||
let res = await validator.getEpochSignature(fork, genesisRoot, slot.epoch)
|
let res = await validator.getEpochSignature(fork, genesisRoot, slot.epoch)
|
||||||
if res.isErr():
|
if res.isErr():
|
||||||
error "Unable to generate randao reveal usint remote signer",
|
error "Unable to generate randao reveal using remote signer",
|
||||||
validator = shortLog(validator), error_msg = res.error()
|
error_msg = res.error()
|
||||||
return
|
return
|
||||||
res.get()
|
res.get()
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
error "Randao reveal processing was interrupted"
|
error "Randao reveal production has been interrupted"
|
||||||
raise exc
|
raise exc
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
error "An unexpected error occurred while receiving randao data",
|
error "An unexpected error occurred while receiving randao data",
|
||||||
err_name = exc.name, err_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return
|
return
|
||||||
|
|
||||||
let beaconBlock =
|
var beaconBlocks =
|
||||||
try:
|
block:
|
||||||
await vc.produceBlockV2(slot, randaoReveal, graffiti,
|
let blindedBlockFut =
|
||||||
ApiStrategyKind.Best)
|
if vc.config.payloadBuilderEnable:
|
||||||
except ValidatorApiError:
|
vc.produceBlindedBlock(currentSlot, slot, randaoReveal, graffiti,
|
||||||
error "Unable to retrieve block data", slot = slot,
|
validator)
|
||||||
wall_slot = currentSlot, validator = shortLog(validator)
|
else:
|
||||||
return
|
nil
|
||||||
except CancelledError as exc:
|
let normalBlockFut = vc.produceBlock(currentSlot, slot, randaoReveal,
|
||||||
error "Producing block processing was interrupted"
|
graffiti, validator)
|
||||||
raise exc
|
let blindedBlock =
|
||||||
except CatchableError as exc:
|
if isNil(blindedBlockFut):
|
||||||
error "An unexpected error occurred while getting block data",
|
Opt.none(PreparedBlindedBeaconBlock)
|
||||||
err_name = exc.name, err_msg = exc.msg
|
else:
|
||||||
return
|
try:
|
||||||
|
await blindedBlockFut
|
||||||
|
except CancelledError as exc:
|
||||||
|
if not(normalBlockFut.finished()):
|
||||||
|
await normalBlockFut.cancelAndWait()
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
# This should not be happened, because all the exceptions handled.
|
||||||
|
Opt.none(PreparedBlindedBeaconBlock)
|
||||||
|
|
||||||
let blockRoot = withBlck(beaconBlock): hash_tree_root(blck)
|
let normalBlock =
|
||||||
# TODO: signingRoot is recomputed in getBlockSignature just after
|
if blindedBlock.isNone():
|
||||||
let signingRoot = compute_block_signing_root(fork, genesisRoot, slot,
|
try:
|
||||||
blockRoot)
|
await normalBlockFut
|
||||||
let notSlashable = vc.attachedValidators[]
|
except CancelledError as exc:
|
||||||
.slashingProtection
|
raise exc
|
||||||
.registerBlock(vindex, validator.pubkey, slot, signingRoot)
|
except CatchableError as exc:
|
||||||
|
# This should not be happened, because all the exceptions handled.
|
||||||
|
Opt.none(PreparedBeaconBlock)
|
||||||
|
else:
|
||||||
|
if not(normalBlockFut.finished()):
|
||||||
|
asyncSpawn lazyWait(normalBlockFut)
|
||||||
|
Opt.none(PreparedBeaconBlock)
|
||||||
|
|
||||||
if notSlashable.isOk():
|
if blindedBlock.isNone() and normalBlock.isNone():
|
||||||
let signature =
|
|
||||||
try:
|
|
||||||
let res = await validator.getBlockSignature(fork, genesisRoot,
|
|
||||||
slot, blockRoot,
|
|
||||||
beaconBlock)
|
|
||||||
if res.isErr():
|
|
||||||
error "Unable to sign block proposal using remote signer",
|
|
||||||
validator = shortLog(validator), error_msg = res.error()
|
|
||||||
return
|
|
||||||
res.get()
|
|
||||||
except CancelledError as exc:
|
|
||||||
debug "Block signature processing was interrupted"
|
|
||||||
raise exc
|
|
||||||
except CatchableError as exc:
|
|
||||||
error "An unexpected error occurred while signing block",
|
|
||||||
err_name = exc.name, err_msg = exc.msg
|
|
||||||
return
|
return
|
||||||
|
|
||||||
debug "Sending block",
|
(blindedBlock: blindedBlock, normalBlock: normalBlock)
|
||||||
blockRoot = shortLog(blockRoot), blck = shortLog(beaconBlock),
|
|
||||||
signature = shortLog(signature), validator = shortLog(validator)
|
|
||||||
|
|
||||||
let res =
|
if beaconBlocks.blindedBlock.isSome():
|
||||||
try:
|
let
|
||||||
let signedBlock = ForkedSignedBeaconBlock.init(beaconBlock, blockRoot,
|
preparedBlock = beaconBlocks.blindedBlock.get()
|
||||||
signature)
|
signingRoot = compute_block_signing_root(fork, genesisRoot, slot,
|
||||||
await vc.publishBlock(signedBlock, ApiStrategyKind.First)
|
preparedBlock.blockRoot)
|
||||||
except ValidatorApiError:
|
notSlashable = vc.attachedValidators[]
|
||||||
error "Unable to publish block",
|
.slashingProtection
|
||||||
blockRoot = shortLog(blockRoot),
|
.registerBlock(vindex, validator.pubkey, slot, signingRoot)
|
||||||
blck = shortLog(beaconBlock),
|
|
||||||
signature = shortLog(signature),
|
logScope:
|
||||||
validator = shortLog(validator),
|
blck = shortLog(preparedBlock.data)
|
||||||
validator_index = validator.index.get(),
|
block_root = shortLog(preparedBlock.blockRoot)
|
||||||
wall_slot = currentSlot
|
signing_root = shortLog(signingRoot)
|
||||||
return
|
|
||||||
except CancelledError as exc:
|
if notSlashable.isOk():
|
||||||
debug "Publishing block processing was interrupted"
|
let
|
||||||
raise exc
|
signature =
|
||||||
except CatchableError as exc:
|
try:
|
||||||
error "An unexpected error occurred while publishing block",
|
let res = await validator.getBlockSignature(fork, genesisRoot,
|
||||||
err_name = exc.name, err_msg = exc.msg
|
slot,
|
||||||
return
|
preparedBlock.blockRoot,
|
||||||
if res:
|
preparedBlock.data)
|
||||||
let delay = vc.getDelay(slot.block_deadline())
|
if res.isErr():
|
||||||
beacon_blocks_sent.inc()
|
error "Unable to sign blinded block proposal using remote signer",
|
||||||
beacon_blocks_sent_delay.observe(delay.toFloatSeconds())
|
error_msg = res.error()
|
||||||
notice "Block published", blockRoot = shortLog(blockRoot),
|
return
|
||||||
blck = shortLog(beaconBlock), signature = shortLog(signature),
|
res.get()
|
||||||
validator = shortLog(validator)
|
except CancelledError as exc:
|
||||||
|
debug "Blinded block signature process has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while signing blinded block",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
signature = shortLog(signature)
|
||||||
|
|
||||||
|
let
|
||||||
|
signedBlock = ForkedSignedBlindedBeaconBlock.init(preparedBlock.data,
|
||||||
|
preparedBlock.blockRoot, signature)
|
||||||
|
res =
|
||||||
|
try:
|
||||||
|
debug "Sending blinded block"
|
||||||
|
await vc.publishBlindedBlock(signedBlock, ApiStrategyKind.First)
|
||||||
|
except ValidatorApiError:
|
||||||
|
error "Unable to publish blinded block"
|
||||||
|
return
|
||||||
|
except CancelledError as exc:
|
||||||
|
debug "Blinded block publication has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while publishing blinded block",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return
|
||||||
|
|
||||||
|
if res:
|
||||||
|
let delay = vc.getDelay(slot.block_deadline())
|
||||||
|
beacon_blocks_sent.inc()
|
||||||
|
beacon_blocks_sent_delay.observe(delay.toFloatSeconds())
|
||||||
|
notice "Blinded block published", delay = delay
|
||||||
|
else:
|
||||||
|
warn "Blinded block was not accepted by beacon node"
|
||||||
else:
|
else:
|
||||||
warn "Block was not accepted by beacon node",
|
warn "Slashing protection activated for blinded block proposal"
|
||||||
blockRoot = shortLog(blockRoot),
|
|
||||||
blck = shortLog(beaconBlock),
|
|
||||||
signature = shortLog(signature),
|
|
||||||
validator = shortLog(validator),
|
|
||||||
wall_slot = currentSlot
|
|
||||||
else:
|
else:
|
||||||
warn "Slashing protection activated for block proposal",
|
let
|
||||||
blockRoot = shortLog(blockRoot), blck = shortLog(beaconBlock),
|
preparedBlock = beaconBlocks.normalBlock.get()
|
||||||
signingRoot = shortLog(signingRoot),
|
signingRoot = compute_block_signing_root(fork, genesisRoot, slot,
|
||||||
validator = shortLog(validator),
|
preparedBlock.blockRoot)
|
||||||
wall_slot = currentSlot,
|
notSlashable = vc.attachedValidators[]
|
||||||
existingProposal = notSlashable.error
|
.slashingProtection
|
||||||
|
.registerBlock(vindex, validator.pubkey, slot, signingRoot)
|
||||||
|
|
||||||
|
logScope:
|
||||||
|
blck = shortLog(preparedBlock.data)
|
||||||
|
block_root = shortLog(preparedBlock.blockRoot)
|
||||||
|
signing_root = shortLog(signingRoot)
|
||||||
|
|
||||||
|
if notSlashable.isOk():
|
||||||
|
let
|
||||||
|
signature =
|
||||||
|
try:
|
||||||
|
let res = await validator.getBlockSignature(fork,
|
||||||
|
genesisRoot, slot,
|
||||||
|
preparedBlock.blockRoot,
|
||||||
|
preparedBlock.data)
|
||||||
|
if res.isErr():
|
||||||
|
error "Unable to sign block proposal using remote signer",
|
||||||
|
error_msg = res.error()
|
||||||
|
return
|
||||||
|
res.get()
|
||||||
|
except CancelledError as exc:
|
||||||
|
debug "Block signature process has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while signing block",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return
|
||||||
|
signedBlock = ForkedSignedBeaconBlock.init(preparedBlock.data,
|
||||||
|
preparedBlock.blockRoot,
|
||||||
|
signature)
|
||||||
|
res =
|
||||||
|
try:
|
||||||
|
debug "Sending block"
|
||||||
|
await vc.publishBlock(signedBlock, ApiStrategyKind.First)
|
||||||
|
except ValidatorApiError:
|
||||||
|
error "Unable to publish block"
|
||||||
|
return
|
||||||
|
except CancelledError as exc:
|
||||||
|
debug "Block publication has been interrupted"
|
||||||
|
raise exc
|
||||||
|
except CatchableError as exc:
|
||||||
|
error "An unexpected error occurred while publishing block",
|
||||||
|
error_name = exc.name, error_msg = exc.msg
|
||||||
|
return
|
||||||
|
|
||||||
|
if res:
|
||||||
|
let delay = vc.getDelay(slot.block_deadline())
|
||||||
|
beacon_blocks_sent.inc()
|
||||||
|
beacon_blocks_sent_delay.observe(delay.toFloatSeconds())
|
||||||
|
notice "Block published", delay = delay
|
||||||
|
else:
|
||||||
|
warn "Block was not accepted by beacon node"
|
||||||
|
else:
|
||||||
|
warn "Slashing protection activated for block proposal"
|
||||||
|
|
||||||
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
||||||
proposerKey: ValidatorPubKey) {.async.} =
|
proposerKey: ValidatorPubKey) {.async.} =
|
||||||
|
@ -291,4 +448,3 @@ proc waitForBlockPublished*(vc: ValidatorClientRef, slot: Slot) {.async.} =
|
||||||
pending.add(future.cancelAndWait())
|
pending.add(future.cancelAndWait())
|
||||||
await allFutures(pending)
|
await allFutures(pending)
|
||||||
raise exc
|
raise exc
|
||||||
|
|
||||||
|
|
|
@ -326,7 +326,8 @@ proc signData(v: AttachedValidator,
|
||||||
proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||||
genesis_validators_root: Eth2Digest, slot: Slot,
|
genesis_validators_root: Eth2Digest, slot: Slot,
|
||||||
block_root: Eth2Digest,
|
block_root: Eth2Digest,
|
||||||
blck: ForkedBeaconBlock | BlindedBeaconBlock
|
blck: ForkedBeaconBlock | ForkedBlindedBeaconBlock |
|
||||||
|
BlindedBeaconBlock
|
||||||
): Future[SignatureResult] {.async.} =
|
): Future[SignatureResult] {.async.} =
|
||||||
return
|
return
|
||||||
case v.kind
|
case v.kind
|
||||||
|
@ -336,7 +337,29 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||||
fork, genesis_validators_root, slot, block_root,
|
fork, genesis_validators_root, slot, block_root,
|
||||||
v.data.privateKey).toValidatorSig())
|
v.data.privateKey).toValidatorSig())
|
||||||
of ValidatorKind.Remote:
|
of ValidatorKind.Remote:
|
||||||
when blck is BlindedBeaconBlock:
|
when blck is ForkedBlindedBeaconBlock:
|
||||||
|
let
|
||||||
|
web3SignerBlock =
|
||||||
|
case blck.kind
|
||||||
|
of BeaconBlockFork.Phase0:
|
||||||
|
Web3SignerForkedBeaconBlock(
|
||||||
|
kind: BeaconBlockFork.Phase0,
|
||||||
|
phase0Data: blck.phase0Data)
|
||||||
|
of BeaconBlockFork.Altair:
|
||||||
|
Web3SignerForkedBeaconBlock(
|
||||||
|
kind: BeaconBlockFork.Altair,
|
||||||
|
altairData: blck.altairData)
|
||||||
|
of BeaconBlockFork.Bellatrix:
|
||||||
|
Web3SignerForkedBeaconBlock(
|
||||||
|
kind: BeaconBlockFork.Bellatrix,
|
||||||
|
bellatrixData: blck.bellatrixData.toBeaconBlockHeader)
|
||||||
|
of BeaconBlockFork.Capella:
|
||||||
|
raiseAssert $capellaImplementationMissing
|
||||||
|
|
||||||
|
request = Web3SignerRequest.init(
|
||||||
|
fork, genesis_validators_root, web3SignerBlock)
|
||||||
|
await v.signData(request)
|
||||||
|
elif blck is BlindedBeaconBlock:
|
||||||
let request = Web3SignerRequest.init(
|
let request = Web3SignerRequest.init(
|
||||||
fork, genesis_validators_root,
|
fork, genesis_validators_root,
|
||||||
Web3SignerForkedBeaconBlock(
|
Web3SignerForkedBeaconBlock(
|
||||||
|
@ -519,4 +542,3 @@ proc getBuilderSignature*(v: AttachedValidator, fork: Fork,
|
||||||
let request = Web3SignerRequest.init(
|
let request = Web3SignerRequest.init(
|
||||||
fork, ZERO_HASH, validatorRegistration)
|
fork, ZERO_HASH, validatorRegistration)
|
||||||
await v.signData(request)
|
await v.signData(request)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue