Merge branch 'feat/eip-7495' into feat_eip-6493
This commit is contained in:
commit
d221cd5a6b
|
@ -431,20 +431,22 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
|
||||||
OK: 253/253 Fail: 0/253 Skip: 0/253
|
OK: 253/253 Fail: 0/253 Skip: 0/253
|
||||||
## EF - SSZ generic types
|
## EF - SSZ generic types
|
||||||
```diff
|
```diff
|
||||||
Testing basic_vector inputs - invalid Skip
|
Testing basic_vector inputs - invalid Skip
|
||||||
+ Testing basic_vector inputs - valid OK
|
+ Testing basic_vector inputs - valid OK
|
||||||
+ Testing bitlist inputs - invalid OK
|
+ Testing bitlist inputs - invalid OK
|
||||||
+ Testing bitlist inputs - valid OK
|
+ Testing bitlist inputs - valid OK
|
||||||
Testing bitvector inputs - invalid Skip
|
Testing bitvector inputs - invalid Skip
|
||||||
+ Testing bitvector inputs - valid OK
|
+ Testing bitvector inputs - valid OK
|
||||||
+ Testing boolean inputs - invalid OK
|
+ Testing boolean inputs - invalid OK
|
||||||
+ Testing boolean inputs - valid OK
|
+ Testing boolean inputs - valid OK
|
||||||
+ Testing containers inputs - invalid - skipping BitsStruct OK
|
+ Testing containers inputs - invalid - skipping BitsStruct OK
|
||||||
+ Testing containers inputs - valid - skipping BitsStruct OK
|
+ Testing containers inputs - valid - skipping BitsStruct OK
|
||||||
+ Testing uints inputs - invalid OK
|
+ Testing profiles inputs - valid OK
|
||||||
+ Testing uints inputs - valid OK
|
+ Testing stablecontainers inputs - valid OK
|
||||||
|
+ Testing uints inputs - invalid OK
|
||||||
|
+ Testing uints inputs - valid OK
|
||||||
```
|
```
|
||||||
OK: 10/12 Fail: 0/12 Skip: 2/12
|
OK: 12/14 Fail: 0/14 Skip: 2/14
|
||||||
## EIP-4881
|
## EIP-4881
|
||||||
```diff
|
```diff
|
||||||
+ deposit_cases OK
|
+ deposit_cases OK
|
||||||
|
@ -1030,4 +1032,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
|
||||||
OK: 9/9 Fail: 0/9 Skip: 0/9
|
OK: 9/9 Fail: 0/9 Skip: 0/9
|
||||||
|
|
||||||
---TOTAL---
|
---TOTAL---
|
||||||
OK: 686/691 Fail: 0/691 Skip: 5/691
|
OK: 689/694 Fail: 0/694 Skip: 5/694
|
||||||
|
|
|
@ -9,12 +9,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
chronicles,
|
chronicles,
|
||||||
../spec/datatypes/[phase0, altair, bellatrix],
|
|
||||||
../spec/forks
|
../spec/forks
|
||||||
|
|
||||||
from ../spec/datatypes/capella import SomeBeaconBlock, TrustedBeaconBlock
|
|
||||||
from ../spec/datatypes/deneb import SomeBeaconBlock, TrustedBeaconBlock
|
|
||||||
|
|
||||||
export chronicles, forks
|
export chronicles, forks
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -76,7 +72,7 @@ func init*(
|
||||||
deneb.SomeBeaconBlock | deneb.TrustedBeaconBlock |
|
deneb.SomeBeaconBlock | deneb.TrustedBeaconBlock |
|
||||||
electra.SomeBeaconBlock | electra.TrustedBeaconBlock): BlockRef =
|
electra.SomeBeaconBlock | electra.TrustedBeaconBlock): BlockRef =
|
||||||
BlockRef.init(
|
BlockRef.init(
|
||||||
root, Opt.some Eth2Digest(blck.body.execution_payload.block_hash),
|
root, Opt.some blck.body.execution_payload.block_hash,
|
||||||
executionValid =
|
executionValid =
|
||||||
executionValid or blck.body.execution_payload.block_hash == ZERO_HASH,
|
executionValid or blck.body.execution_payload.block_hash == ZERO_HASH,
|
||||||
blck.slot)
|
blck.slot)
|
||||||
|
|
|
@ -16,8 +16,7 @@ import
|
||||||
../spec/datatypes/base,
|
../spec/datatypes/base,
|
||||||
./block_pools_types, blockchain_dag
|
./block_pools_types, blockchain_dag
|
||||||
|
|
||||||
debugComment "probably just need Electra shortLog here"
|
from ../spec/datatypes/electra import shortLog
|
||||||
import ../spec/forks # prune this, it's for electra attestation logging
|
|
||||||
|
|
||||||
export
|
export
|
||||||
base, extras, block_pools_types, results
|
base, extras, block_pools_types, results
|
||||||
|
|
|
@ -273,7 +273,7 @@ proc main() {.async.} =
|
||||||
error "Failed to read an Eth1 private key from standard input"
|
error "Failed to read an Eth1 private key from standard input"
|
||||||
|
|
||||||
if privateKey.len > 0:
|
if privateKey.len > 0:
|
||||||
conf.privateKey = privateKey.string
|
conf.privateKey = privateKey
|
||||||
|
|
||||||
let web3 = await initWeb3(conf.web3Url, conf.privateKey)
|
let web3 = await initWeb3(conf.web3Url, conf.privateKey)
|
||||||
|
|
||||||
|
|
|
@ -366,8 +366,6 @@ proc updateGossipStatus*(
|
||||||
lightClient: LightClient, slot: Slot, dagIsBehind = default(Option[bool])) =
|
lightClient: LightClient, slot: Slot, dagIsBehind = default(Option[bool])) =
|
||||||
template cfg(): auto = lightClient.cfg
|
template cfg(): auto = lightClient.cfg
|
||||||
|
|
||||||
debugComment "when LC on electra works, add cfg.ELECTRA_FORK_EPOCH"
|
|
||||||
|
|
||||||
let
|
let
|
||||||
epoch = slot.epoch
|
epoch = slot.epoch
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,10 @@ type
|
||||||
|
|
||||||
func parseBootstrapAddress*(address: string):
|
func parseBootstrapAddress*(address: string):
|
||||||
Result[enr.Record, cstring] =
|
Result[enr.Record, cstring] =
|
||||||
let lowerCaseAddress = toLowerAscii(string address)
|
let lowerCaseAddress = toLowerAscii(address)
|
||||||
if lowerCaseAddress.startsWith("enr:"):
|
if lowerCaseAddress.startsWith("enr:"):
|
||||||
var enrRec: enr.Record
|
var enrRec: enr.Record
|
||||||
if enrRec.fromURI(string address):
|
if enrRec.fromURI(address):
|
||||||
return ok enrRec
|
return ok enrRec
|
||||||
return err "Invalid ENR bootstrap record"
|
return err "Invalid ENR bootstrap record"
|
||||||
elif lowerCaseAddress.startsWith("enode:"):
|
elif lowerCaseAddress.startsWith("enode:"):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -10,5 +10,4 @@
|
||||||
|
|
||||||
--styleCheck:usages
|
--styleCheck:usages
|
||||||
--styleCheck:hint
|
--styleCheck:hint
|
||||||
--hint[ConvFromXtoItselfNotNeeded]:off
|
|
||||||
--hint[Processing]:off
|
--hint[Processing]:off
|
||||||
|
|
|
@ -46,7 +46,7 @@ proc listRemoteValidators*(
|
||||||
if item.kind == ValidatorKind.Remote and item.data.remotes.len == 1:
|
if item.kind == ValidatorKind.Remote and item.data.remotes.len == 1:
|
||||||
validators.add RemoteKeystoreInfo(
|
validators.add RemoteKeystoreInfo(
|
||||||
pubkey: item.pubkey,
|
pubkey: item.pubkey,
|
||||||
url: HttpHostUri(item.data.remotes[0].url)
|
url: item.data.remotes[0].url
|
||||||
)
|
)
|
||||||
validators
|
validators
|
||||||
|
|
||||||
|
|
|
@ -688,8 +688,8 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
message = (await PayloadType.makeBeaconBlockForHeadAndSlot(
|
message = (await PayloadType.makeBeaconBlockForHeadAndSlot(
|
||||||
node, qrandao, proposer, qgraffiti, qhead, qslot)).valueOr:
|
node, qrandao, proposer, qgraffiti, qhead, qslot)).valueOr:
|
||||||
return RestApiResponse.jsonError(Http500, error)
|
return RestApiResponse.jsonError(Http500, error)
|
||||||
executionValue = Opt.some(UInt256(message.executionPayloadValue))
|
executionValue = Opt.some(message.executionPayloadValue)
|
||||||
consensusValue = Opt.some(UInt256(message.consensusBlockValue))
|
consensusValue = Opt.some(message.consensusBlockValue)
|
||||||
headers = consensusFork.getMaybeBlindedHeaders(
|
headers = consensusFork.getMaybeBlindedHeaders(
|
||||||
isBlinded = false, executionValue, consensusValue)
|
isBlinded = false, executionValue, consensusValue)
|
||||||
|
|
||||||
|
@ -914,7 +914,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
request.validator_index).pubkey
|
request.validator_index).pubkey
|
||||||
|
|
||||||
node.validatorMonitor[].addAutoMonitor(
|
node.validatorMonitor[].addAutoMonitor(
|
||||||
validator_pubkey, ValidatorIndex(request.validator_index))
|
validator_pubkey, request.validator_index)
|
||||||
|
|
||||||
RestApiResponse.jsonMsgResponse(BeaconCommitteeSubscriptionSuccess)
|
RestApiResponse.jsonMsgResponse(BeaconCommitteeSubscriptionSuccess)
|
||||||
|
|
||||||
|
@ -955,7 +955,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
validator_pubkey, item.until_epoch)
|
validator_pubkey, item.until_epoch)
|
||||||
|
|
||||||
node.validatorMonitor[].addAutoMonitor(
|
node.validatorMonitor[].addAutoMonitor(
|
||||||
validator_pubkey, ValidatorIndex(item.validator_index))
|
validator_pubkey, item.validator_index)
|
||||||
|
|
||||||
RestApiResponse.jsonMsgResponse(SyncCommitteeSubscriptionSuccess)
|
RestApiResponse.jsonMsgResponse(SyncCommitteeSubscriptionSuccess)
|
||||||
|
|
||||||
|
|
|
@ -289,7 +289,7 @@ func initiate_validator_exit*(
|
||||||
# Set validator exit epoch and withdrawable epoch
|
# Set validator exit epoch and withdrawable epoch
|
||||||
validator.exit_epoch = exit_queue_epoch
|
validator.exit_epoch = exit_queue_epoch
|
||||||
validator.withdrawable_epoch =
|
validator.withdrawable_epoch =
|
||||||
Epoch(validator.exit_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
|
validator.exit_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
if validator.withdrawable_epoch < validator.exit_epoch:
|
if validator.withdrawable_epoch < validator.exit_epoch:
|
||||||
return err("Invalid large withdrawable epoch")
|
return err("Invalid large withdrawable epoch")
|
||||||
state.validators.mitem(index) = validator
|
state.validators.mitem(index) = validator
|
||||||
|
|
|
@ -986,4 +986,3 @@ func ofLen*[T, N](ListType: type List[T, N], n: int): ListType =
|
||||||
raise newException(SszSizeMismatchError)
|
raise newException(SszSizeMismatchError)
|
||||||
|
|
||||||
template debugComment*(s: string) = discard
|
template debugComment*(s: string) = discard
|
||||||
template debugRaiseAssert*(s: string) = discard
|
|
||||||
|
|
|
@ -408,8 +408,7 @@ type
|
||||||
RestNimbusTimestamp2 |
|
RestNimbusTimestamp2 |
|
||||||
GetGraffitiResponse
|
GetGraffitiResponse
|
||||||
|
|
||||||
DecodeConsensysTypes* =
|
DecodeConsensysTypes* = ProduceBlindedBlockResponse
|
||||||
ProduceBlockResponseV2 | ProduceBlindedBlockResponse
|
|
||||||
|
|
||||||
RestVersioned*[T] = object
|
RestVersioned*[T] = object
|
||||||
data*: T
|
data*: T
|
||||||
|
@ -1443,8 +1442,7 @@ template prepareForkedBlockReading(blockType: typedesc,
|
||||||
if version.isNone():
|
if version.isNone():
|
||||||
reader.raiseUnexpectedValue("Incorrect version field value")
|
reader.raiseUnexpectedValue("Incorrect version field value")
|
||||||
of "data":
|
of "data":
|
||||||
when (blockType is ProduceBlockResponseV2) or
|
when (blockType is ForkedBlindedBeaconBlock) or
|
||||||
(blockType is ForkedBlindedBeaconBlock) or
|
|
||||||
(blockType is ProduceBlockResponseV3):
|
(blockType is ProduceBlockResponseV3):
|
||||||
if data.isSome():
|
if data.isSome():
|
||||||
reader.raiseUnexpectedField(
|
reader.raiseUnexpectedField(
|
||||||
|
@ -1492,92 +1490,6 @@ template prepareForkedBlockReading(blockType: typedesc,
|
||||||
if data.isNone():
|
if data.isNone():
|
||||||
reader.raiseUnexpectedValue("Field `data` is missing")
|
reader.raiseUnexpectedValue("Field `data` is missing")
|
||||||
|
|
||||||
proc readValue*[BlockType: ProduceBlockResponseV2](
|
|
||||||
reader: var JsonReader[RestJson],
|
|
||||||
value: var BlockType) {.raises: [IOError, SerializationError].} =
|
|
||||||
var
|
|
||||||
version: Opt[ConsensusFork]
|
|
||||||
data: Opt[JsonString]
|
|
||||||
blinded: Opt[bool]
|
|
||||||
payloadValue: Opt[Uint256]
|
|
||||||
blockValue: Opt[Uint256]
|
|
||||||
|
|
||||||
prepareForkedBlockReading(BlockType, reader, version, data, blinded,
|
|
||||||
payloadValue, blockValue)
|
|
||||||
|
|
||||||
case version.get():
|
|
||||||
of ConsensusFork.Phase0:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
phase0.BeaconBlock,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect phase0 block format")
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Phase0,
|
|
||||||
phase0Data: res)
|
|
||||||
of ConsensusFork.Altair:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
altair.BeaconBlock,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect altair block format")
|
|
||||||
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Altair,
|
|
||||||
altairData: res)
|
|
||||||
of ConsensusFork.Bellatrix:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
bellatrix.BeaconBlock,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect bellatrix block format")
|
|
||||||
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Bellatrix,
|
|
||||||
bellatrixData: res)
|
|
||||||
of ConsensusFork.Capella:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
capella.BeaconBlock,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect capella block format")
|
|
||||||
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Capella,
|
|
||||||
capellaData: res)
|
|
||||||
of ConsensusFork.Deneb:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
deneb.BlockContents,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect deneb block format")
|
|
||||||
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Deneb,
|
|
||||||
denebData: res)
|
|
||||||
of ConsensusFork.Electra:
|
|
||||||
let res =
|
|
||||||
try:
|
|
||||||
RestJson.decode(string(data.get()),
|
|
||||||
electra.BlockContents,
|
|
||||||
requireAllFields = true,
|
|
||||||
allowUnknownFields = true)
|
|
||||||
except SerializationError:
|
|
||||||
reader.raiseUnexpectedValue("Incorrect electra block format")
|
|
||||||
|
|
||||||
value = ProduceBlockResponseV2(kind: ConsensusFork.Electra,
|
|
||||||
electraData: res)
|
|
||||||
|
|
||||||
proc readValue*[BlockType: ForkedBlindedBeaconBlock](
|
proc readValue*[BlockType: ForkedBlindedBeaconBlock](
|
||||||
reader: var JsonReader[RestJson],
|
reader: var JsonReader[RestJson],
|
||||||
value: var BlockType
|
value: var BlockType
|
||||||
|
@ -3777,35 +3689,7 @@ proc decodeBytes*[T: DecodeConsensysTypes](
|
||||||
data = string.fromBytes(value)
|
data = string.fromBytes(value)
|
||||||
return err("Serialization error")
|
return err("Serialization error")
|
||||||
elif mediaType == OctetStreamMediaType:
|
elif mediaType == OctetStreamMediaType:
|
||||||
when t is ProduceBlockResponseV2:
|
when t is ProduceBlindedBlockResponse:
|
||||||
let fork = ConsensusFork.decodeString(consensusVersion).valueOr:
|
|
||||||
return err("Invalid or Unsupported consensus version")
|
|
||||||
case fork
|
|
||||||
of ConsensusFork.Electra:
|
|
||||||
let blckContents = ? readSszResBytes(electra.BlockContents, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Electra,
|
|
||||||
electraData: blckContents))
|
|
||||||
of ConsensusFork.Deneb:
|
|
||||||
let blckContents = ? readSszResBytes(deneb.BlockContents, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Deneb,
|
|
||||||
denebData: blckContents))
|
|
||||||
of ConsensusFork.Capella:
|
|
||||||
let blck = ? readSszResBytes(capella.BeaconBlock, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Capella,
|
|
||||||
capellaData: blck))
|
|
||||||
of ConsensusFork.Bellatrix:
|
|
||||||
let blck = ? readSszResBytes(bellatrix.BeaconBlock, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Bellatrix,
|
|
||||||
bellatrixData: blck))
|
|
||||||
of ConsensusFork.Altair:
|
|
||||||
let blck = ? readSszResBytes(altair.BeaconBlock, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Altair,
|
|
||||||
altairData: blck))
|
|
||||||
of ConsensusFork.Phase0:
|
|
||||||
let blck = ? readSszResBytes(phase0.BeaconBlock, value)
|
|
||||||
ok(ProduceBlockResponseV2(kind: ConsensusFork.Phase0,
|
|
||||||
phase0Data: blck))
|
|
||||||
elif t is ProduceBlindedBlockResponse:
|
|
||||||
let fork = ConsensusFork.decodeString(consensusVersion).valueOr:
|
let fork = ConsensusFork.decodeString(consensusVersion).valueOr:
|
||||||
return err("Invalid or Unsupported consensus version")
|
return err("Invalid or Unsupported consensus version")
|
||||||
case fork
|
case fork
|
||||||
|
|
|
@ -212,7 +212,7 @@ proc getLightClientBootstrap*(
|
||||||
let consensusForkRes = ConsensusFork.decodeString(
|
let consensusForkRes = ConsensusFork.decodeString(
|
||||||
resp.headers.getString("eth-consensus-version"))
|
resp.headers.getString("eth-consensus-version"))
|
||||||
if consensusForkRes.isErr:
|
if consensusForkRes.isErr:
|
||||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
raiseRestDecodingBytesError(consensusForkRes.error)
|
||||||
ForkedLightClientBootstrap.decodeHttpLightClientObject(
|
ForkedLightClientBootstrap.decodeHttpLightClientObject(
|
||||||
data, resp.contentType, consensusForkRes.get, cfg)
|
data, resp.contentType, consensusForkRes.get, cfg)
|
||||||
of 404:
|
of 404:
|
||||||
|
@ -294,7 +294,7 @@ proc getLightClientFinalityUpdate*(
|
||||||
let consensusForkRes = ConsensusFork.decodeString(
|
let consensusForkRes = ConsensusFork.decodeString(
|
||||||
resp.headers.getString("eth-consensus-version"))
|
resp.headers.getString("eth-consensus-version"))
|
||||||
if consensusForkRes.isErr:
|
if consensusForkRes.isErr:
|
||||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
raiseRestDecodingBytesError(consensusForkRes.error)
|
||||||
ForkedLightClientFinalityUpdate.decodeHttpLightClientObject(
|
ForkedLightClientFinalityUpdate.decodeHttpLightClientObject(
|
||||||
data, resp.contentType, consensusForkRes.get, cfg)
|
data, resp.contentType, consensusForkRes.get, cfg)
|
||||||
of 404:
|
of 404:
|
||||||
|
@ -336,7 +336,7 @@ proc getLightClientOptimisticUpdate*(
|
||||||
let consensusForkRes = ConsensusFork.decodeString(
|
let consensusForkRes = ConsensusFork.decodeString(
|
||||||
resp.headers.getString("eth-consensus-version"))
|
resp.headers.getString("eth-consensus-version"))
|
||||||
if consensusForkRes.isErr:
|
if consensusForkRes.isErr:
|
||||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
raiseRestDecodingBytesError(consensusForkRes.error)
|
||||||
ForkedLightClientOptimisticUpdate.decodeHttpLightClientObject(
|
ForkedLightClientOptimisticUpdate.decodeHttpLightClientObject(
|
||||||
data, resp.contentType, consensusForkRes.get, cfg)
|
data, resp.contentType, consensusForkRes.get, cfg)
|
||||||
of 404:
|
of 404:
|
||||||
|
|
|
@ -370,15 +370,6 @@ type
|
||||||
of ConsensusFork.Deneb: denebBody*: deneb.BeaconBlockBody
|
of ConsensusFork.Deneb: denebBody*: deneb.BeaconBlockBody
|
||||||
of ConsensusFork.Electra: electraBody*: electra.BeaconBlockBody
|
of ConsensusFork.Electra: electraBody*: electra.BeaconBlockBody
|
||||||
|
|
||||||
ProduceBlockResponseV2* = object
|
|
||||||
case kind*: ConsensusFork
|
|
||||||
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
|
|
||||||
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
|
|
||||||
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock
|
|
||||||
of ConsensusFork.Capella: capellaData*: capella.BeaconBlock
|
|
||||||
of ConsensusFork.Deneb: denebData*: deneb.BlockContents
|
|
||||||
of ConsensusFork.Electra: electraData*: electra.BlockContents
|
|
||||||
|
|
||||||
ProduceBlockResponseV3* = ForkedMaybeBlindedBeaconBlock
|
ProduceBlockResponseV3* = ForkedMaybeBlindedBeaconBlock
|
||||||
|
|
||||||
VCRuntimeConfig* = Table[string, string]
|
VCRuntimeConfig* = Table[string, string]
|
||||||
|
@ -1113,27 +1104,3 @@ func toValidatorIndex*(value: RestValidatorIndex): Result[ValidatorIndex,
|
||||||
err(ValidatorIndexError.TooHighValue)
|
err(ValidatorIndexError.TooHighValue)
|
||||||
else:
|
else:
|
||||||
doAssert(false, "ValidatorIndex type size is incorrect")
|
doAssert(false, "ValidatorIndex type size is incorrect")
|
||||||
|
|
||||||
template withBlck*(x: ProduceBlockResponseV2,
|
|
||||||
body: untyped): untyped =
|
|
||||||
case x.kind
|
|
||||||
of ConsensusFork.Phase0:
|
|
||||||
const consensusFork {.inject, used.} = ConsensusFork.Phase0
|
|
||||||
template blck: untyped {.inject.} = x.phase0Data
|
|
||||||
body
|
|
||||||
of ConsensusFork.Altair:
|
|
||||||
const consensusFork {.inject, used.} = ConsensusFork.Altair
|
|
||||||
template blck: untyped {.inject.} = x.altairData
|
|
||||||
body
|
|
||||||
of ConsensusFork.Bellatrix:
|
|
||||||
const consensusFork {.inject, used.} = ConsensusFork.Bellatrix
|
|
||||||
template blck: untyped {.inject.} = x.bellatrixData
|
|
||||||
body
|
|
||||||
of ConsensusFork.Capella:
|
|
||||||
const consensusFork {.inject, used.} = ConsensusFork.Capella
|
|
||||||
template blck: untyped {.inject.} = x.capellaData
|
|
||||||
body
|
|
||||||
of ConsensusFork.Deneb:
|
|
||||||
const consensusFork {.inject, used.} = ConsensusFork.Deneb
|
|
||||||
template blck: untyped {.inject.} = x.denebData.blck
|
|
||||||
body
|
|
||||||
|
|
|
@ -36,15 +36,6 @@ proc getSyncCommitteeDutiesPlain*(
|
||||||
meth: MethodPost.}
|
meth: MethodPost.}
|
||||||
## https://ethereum.github.io/beacon-APIs/#/Validator/getSyncCommitteeDuties
|
## https://ethereum.github.io/beacon-APIs/#/Validator/getSyncCommitteeDuties
|
||||||
|
|
||||||
proc produceBlockV2Plain*(
|
|
||||||
slot: Slot,
|
|
||||||
randao_reveal: ValidatorSig,
|
|
||||||
graffiti: GraffitiBytes
|
|
||||||
): RestPlainResponse {.
|
|
||||||
rest, endpoint: "/eth/v2/validator/blocks/{slot}",
|
|
||||||
accept: preferSSZ, meth: MethodGet.}
|
|
||||||
## https://ethereum.github.io/beacon-APIs/#/Validator/produceBlockV2
|
|
||||||
|
|
||||||
proc produceBlockV3Plain*(
|
proc produceBlockV3Plain*(
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
randao_reveal: ValidatorSig,
|
randao_reveal: ValidatorSig,
|
||||||
|
|
|
@ -291,7 +291,7 @@ template `$`*(x: WalletName): string =
|
||||||
# TODO: `burnMem` in nimcrypto could use distinctBase
|
# TODO: `burnMem` in nimcrypto could use distinctBase
|
||||||
# to make its usage less error-prone.
|
# to make its usage less error-prone.
|
||||||
template burnMem*(m: var (Mnemonic|string)) =
|
template burnMem*(m: var (Mnemonic|string)) =
|
||||||
ncrutils.burnMem(string m)
|
ncrutils.burnMem(distinctBase m)
|
||||||
|
|
||||||
template burnMem*(m: var KeySeed) =
|
template burnMem*(m: var KeySeed) =
|
||||||
ncrutils.burnMem(distinctBase m)
|
ncrutils.burnMem(distinctBase m)
|
||||||
|
@ -324,7 +324,7 @@ const
|
||||||
englishWordsDigest =
|
englishWordsDigest =
|
||||||
"AD90BF3BEB7B0EB7E5ACD74727DC0DA96E0A280A258354E7293FB7E211AC03DB".toDigest
|
"AD90BF3BEB7B0EB7E5ACD74727DC0DA96E0A280A258354E7293FB7E211AC03DB".toDigest
|
||||||
|
|
||||||
proc checkEnglishWords(): bool =
|
func checkEnglishWords(): bool =
|
||||||
if len(englishWords) != wordListLen:
|
if len(englishWords) != wordListLen:
|
||||||
false
|
false
|
||||||
else:
|
else:
|
||||||
|
@ -341,7 +341,7 @@ func validateKeyPath*(path: string): Result[KeyPath, cstring] =
|
||||||
var digitCount: int
|
var digitCount: int
|
||||||
var number: BiggestUInt
|
var number: BiggestUInt
|
||||||
try:
|
try:
|
||||||
for elem in path.string.split("/"):
|
for elem in path.split("/"):
|
||||||
# TODO: doesn't "m" have to be the first character and is it the only
|
# TODO: doesn't "m" have to be the first character and is it the only
|
||||||
# place where it is valid?
|
# place where it is valid?
|
||||||
if elem == "m":
|
if elem == "m":
|
||||||
|
@ -382,7 +382,7 @@ func isControlRune(r: Rune): bool =
|
||||||
let r = int r
|
let r = int r
|
||||||
(r >= 0 and r < 0x20) or (r >= 0x7F and r < 0xA0)
|
(r >= 0 and r < 0x20) or (r >= 0x7F and r < 0xA0)
|
||||||
|
|
||||||
proc init*(T: type KeystorePass, input: string): T =
|
func init*(T: type KeystorePass, input: string): T =
|
||||||
for rune in toNFKD(input):
|
for rune in toNFKD(input):
|
||||||
if not isControlRune(rune):
|
if not isControlRune(rune):
|
||||||
result.str.add rune
|
result.str.add rune
|
||||||
|
@ -395,7 +395,7 @@ func getSeed*(mnemonic: Mnemonic, password: KeystorePass): KeySeed =
|
||||||
template add(m: var Mnemonic, s: cstring) =
|
template add(m: var Mnemonic, s: cstring) =
|
||||||
m.string.add s
|
m.string.add s
|
||||||
|
|
||||||
proc generateMnemonic*(
|
func generateMnemonic*(
|
||||||
rng: var HmacDrbgContext,
|
rng: var HmacDrbgContext,
|
||||||
words: openArray[cstring] = englishWords,
|
words: openArray[cstring] = englishWords,
|
||||||
entropyParam: openArray[byte] = @[]): Mnemonic =
|
entropyParam: openArray[byte] = @[]): Mnemonic =
|
||||||
|
@ -429,12 +429,12 @@ proc generateMnemonic*(
|
||||||
result.add " "
|
result.add " "
|
||||||
result.add words[entropy.getBitsBE(firstBit..lastBit)]
|
result.add words[entropy.getBitsBE(firstBit..lastBit)]
|
||||||
|
|
||||||
proc cmpIgnoreCase(lhs: cstring, rhs: string): int =
|
func cmpIgnoreCase(lhs: cstring, rhs: string): int =
|
||||||
# TODO: This is a bit silly.
|
# TODO: This is a bit silly.
|
||||||
# Nim should have a `cmp` function for C strings.
|
# Nim should have a `cmp` function for C strings.
|
||||||
cmpIgnoreCase($lhs, rhs)
|
cmpIgnoreCase($lhs, rhs)
|
||||||
|
|
||||||
proc validateMnemonic*(inputWords: string,
|
func validateMnemonic*(inputWords: string,
|
||||||
outputMnemonic: var Mnemonic): bool =
|
outputMnemonic: var Mnemonic): bool =
|
||||||
## Accept a case-insensitive input string and returns `true`
|
## Accept a case-insensitive input string and returns `true`
|
||||||
## if it represents a valid mnenomic. The `outputMnemonic`
|
## if it represents a valid mnenomic. The `outputMnemonic`
|
||||||
|
@ -465,7 +465,7 @@ proc validateMnemonic*(inputWords: string,
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc deriveChildKey*(parentKey: ValidatorPrivKey,
|
func deriveChildKey*(parentKey: ValidatorPrivKey,
|
||||||
index: Natural): ValidatorPrivKey =
|
index: Natural): ValidatorPrivKey =
|
||||||
let success = derive_child_secretKey(SecretKey result,
|
let success = derive_child_secretKey(SecretKey result,
|
||||||
SecretKey parentKey,
|
SecretKey parentKey,
|
||||||
|
@ -475,7 +475,7 @@ proc deriveChildKey*(parentKey: ValidatorPrivKey,
|
||||||
# into asserts inside the function.
|
# into asserts inside the function.
|
||||||
doAssert success
|
doAssert success
|
||||||
|
|
||||||
proc deriveMasterKey*(seed: KeySeed): ValidatorPrivKey =
|
func deriveMasterKey*(seed: KeySeed): ValidatorPrivKey =
|
||||||
let success = derive_master_secretKey(SecretKey result,
|
let success = derive_master_secretKey(SecretKey result,
|
||||||
seq[byte] seed)
|
seq[byte] seed)
|
||||||
# TODO `derive_master_secretKey` is reporting pre-condition
|
# TODO `derive_master_secretKey` is reporting pre-condition
|
||||||
|
@ -483,17 +483,17 @@ proc deriveMasterKey*(seed: KeySeed): ValidatorPrivKey =
|
||||||
# into asserts inside the function.
|
# into asserts inside the function.
|
||||||
doAssert success
|
doAssert success
|
||||||
|
|
||||||
proc deriveMasterKey*(mnemonic: Mnemonic,
|
func deriveMasterKey*(mnemonic: Mnemonic,
|
||||||
password: KeystorePass): ValidatorPrivKey =
|
password: KeystorePass): ValidatorPrivKey =
|
||||||
deriveMasterKey(getSeed(mnemonic, password))
|
deriveMasterKey(getSeed(mnemonic, password))
|
||||||
|
|
||||||
proc deriveChildKey*(masterKey: ValidatorPrivKey,
|
func deriveChildKey*(masterKey: ValidatorPrivKey,
|
||||||
path: KeyPath): ValidatorPrivKey =
|
path: KeyPath): ValidatorPrivKey =
|
||||||
result = masterKey
|
result = masterKey
|
||||||
for idx in pathNodes(path):
|
for idx in pathNodes(path):
|
||||||
result = deriveChildKey(result, idx)
|
result = deriveChildKey(result, idx)
|
||||||
|
|
||||||
proc deriveChildKey*(masterKey: ValidatorPrivKey,
|
func deriveChildKey*(masterKey: ValidatorPrivKey,
|
||||||
path: openArray[Natural]): ValidatorPrivKey =
|
path: openArray[Natural]): ValidatorPrivKey =
|
||||||
result = masterKey
|
result = masterKey
|
||||||
for idx in path:
|
for idx in path:
|
||||||
|
@ -503,12 +503,12 @@ proc deriveChildKey*(masterKey: ValidatorPrivKey,
|
||||||
# if we fail we want to scrub secrets from memory
|
# if we fail we want to scrub secrets from memory
|
||||||
result = deriveChildKey(result, idx)
|
result = deriveChildKey(result, idx)
|
||||||
|
|
||||||
proc keyFromPath*(mnemonic: Mnemonic,
|
func keyFromPath*(mnemonic: Mnemonic,
|
||||||
password: KeystorePass,
|
password: KeystorePass,
|
||||||
path: KeyPath): ValidatorPrivKey =
|
path: KeyPath): ValidatorPrivKey =
|
||||||
deriveChildKey(deriveMasterKey(mnemonic, password), path)
|
deriveChildKey(deriveMasterKey(mnemonic, password), path)
|
||||||
|
|
||||||
proc shaChecksum(key, cipher: openArray[byte]): Sha256Digest =
|
func shaChecksum(key, cipher: openArray[byte]): Sha256Digest =
|
||||||
var ctx: sha256
|
var ctx: sha256
|
||||||
ctx.init()
|
ctx.init()
|
||||||
ctx.update(key)
|
ctx.update(key)
|
||||||
|
@ -681,7 +681,7 @@ proc readValue*(r: var JsonReader[DefaultFlavor], value: var Kdf)
|
||||||
readValueImpl(r, value)
|
readValueImpl(r, value)
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc readValue*(r: var JsonReader, value: var (Checksum|Cipher|Kdf)) =
|
func readValue*(r: var JsonReader, value: var (Checksum|Cipher|Kdf)) =
|
||||||
static: raiseAssert "Unknown flavor `JsonReader[" & $typeof(r).Flavor &
|
static: raiseAssert "Unknown flavor `JsonReader[" & $typeof(r).Flavor &
|
||||||
"]` for `readValue` of `" & $typeof(value) & "`"
|
"]` for `readValue` of `" & $typeof(value) & "`"
|
||||||
|
|
||||||
|
@ -951,7 +951,7 @@ func areValid(params: ScryptParams): bool =
|
||||||
params.p == scryptParams.p and
|
params.p == scryptParams.p and
|
||||||
params.salt.bytes.len > 0
|
params.salt.bytes.len > 0
|
||||||
|
|
||||||
proc decryptCryptoField*(crypto: Crypto, decKey: openArray[byte],
|
func decryptCryptoField*(crypto: Crypto, decKey: openArray[byte],
|
||||||
outSecret: var seq[byte]): DecryptionStatus =
|
outSecret: var seq[byte]): DecryptionStatus =
|
||||||
if crypto.cipher.message.bytes.len == 0:
|
if crypto.cipher.message.bytes.len == 0:
|
||||||
return DecryptionStatus.InvalidKeystore
|
return DecryptionStatus.InvalidKeystore
|
||||||
|
@ -977,7 +977,7 @@ proc decryptCryptoField*(crypto: Crypto, decKey: openArray[byte],
|
||||||
aesCipher.clear()
|
aesCipher.clear()
|
||||||
DecryptionStatus.Success
|
DecryptionStatus.Success
|
||||||
|
|
||||||
proc getDecryptionKey*(crypto: Crypto, password: KeystorePass,
|
func getDecryptionKey*(crypto: Crypto, password: KeystorePass,
|
||||||
decKey: var seq[byte]): DecryptionStatus =
|
decKey: var seq[byte]): DecryptionStatus =
|
||||||
let res =
|
let res =
|
||||||
case crypto.kdf.function
|
case crypto.kdf.function
|
||||||
|
@ -996,7 +996,7 @@ proc getDecryptionKey*(crypto: Crypto, password: KeystorePass,
|
||||||
decKey = res
|
decKey = res
|
||||||
DecryptionStatus.Success
|
DecryptionStatus.Success
|
||||||
|
|
||||||
proc decryptCryptoField*(crypto: Crypto,
|
func decryptCryptoField*(crypto: Crypto,
|
||||||
password: KeystorePass,
|
password: KeystorePass,
|
||||||
outSecret: var seq[byte]): DecryptionStatus =
|
outSecret: var seq[byte]): DecryptionStatus =
|
||||||
# https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
|
# https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
|
||||||
|
@ -1027,7 +1027,7 @@ template parseRemoteKeystore*(jsonContent: string): RemoteKeystore =
|
||||||
requireAllFields = false,
|
requireAllFields = false,
|
||||||
allowUnknownFields = true)
|
allowUnknownFields = true)
|
||||||
|
|
||||||
proc getSaltKey(keystore: Keystore, password: KeystorePass): KdfSaltKey =
|
func getSaltKey(keystore: Keystore, password: KeystorePass): KdfSaltKey =
|
||||||
let digest =
|
let digest =
|
||||||
case keystore.crypto.kdf.function
|
case keystore.crypto.kdf.function
|
||||||
of kdfPbkdf2:
|
of kdfPbkdf2:
|
||||||
|
@ -1050,8 +1050,8 @@ proc getSaltKey(keystore: Keystore, password: KeystorePass): KdfSaltKey =
|
||||||
h.update(toBytesLE(uint64(params.r)))
|
h.update(toBytesLE(uint64(params.r)))
|
||||||
KdfSaltKey(digest.data)
|
KdfSaltKey(digest.data)
|
||||||
|
|
||||||
proc `==`*(a, b: KdfSaltKey): bool {.borrow.}
|
func `==`*(a, b: KdfSaltKey): bool {.borrow.}
|
||||||
proc hash*(salt: KdfSaltKey): Hash {.borrow.}
|
func hash*(salt: KdfSaltKey): Hash {.borrow.}
|
||||||
|
|
||||||
{.push warning[ProveField]:off.}
|
{.push warning[ProveField]:off.}
|
||||||
func `==`*(a, b: Kdf): bool =
|
func `==`*(a, b: Kdf): bool =
|
||||||
|
@ -1089,7 +1089,7 @@ func init*(t: typedesc[KeystoreCacheRef],
|
||||||
expireTime: expireTime
|
expireTime: expireTime
|
||||||
)
|
)
|
||||||
|
|
||||||
proc clear*(cache: KeystoreCacheRef) =
|
func clear*(cache: KeystoreCacheRef) =
|
||||||
cache.table.clear()
|
cache.table.clear()
|
||||||
|
|
||||||
proc pruneExpiredKeys*(cache: KeystoreCacheRef) =
|
proc pruneExpiredKeys*(cache: KeystoreCacheRef) =
|
||||||
|
@ -1110,7 +1110,7 @@ proc init*(t: typedesc[KeystoreCacheItem], keystore: Keystore,
|
||||||
cipher: keystore.crypto.cipher, decryptionKey: @key,
|
cipher: keystore.crypto.cipher, decryptionKey: @key,
|
||||||
timestamp: Moment.now())
|
timestamp: Moment.now())
|
||||||
|
|
||||||
proc getCachedKey*(cache: KeystoreCacheRef,
|
func getCachedKey*(cache: KeystoreCacheRef,
|
||||||
keystore: Keystore, password: KeystorePass): Opt[seq[byte]] =
|
keystore: Keystore, password: KeystorePass): Opt[seq[byte]] =
|
||||||
if isNil(cache): return Opt.none(seq[byte])
|
if isNil(cache): return Opt.none(seq[byte])
|
||||||
let
|
let
|
||||||
|
@ -1132,7 +1132,7 @@ proc setCachedKey*(cache: KeystoreCacheRef, keystore: Keystore,
|
||||||
let saltKey = keystore.getSaltKey(password)
|
let saltKey = keystore.getSaltKey(password)
|
||||||
cache.table[saltKey] = KeystoreCacheItem.init(keystore, key)
|
cache.table[saltKey] = KeystoreCacheItem.init(keystore, key)
|
||||||
|
|
||||||
proc destroyCacheKey*(cache: KeystoreCacheRef,
|
func destroyCacheKey*(cache: KeystoreCacheRef,
|
||||||
keystore: Keystore, password: KeystorePass) =
|
keystore: Keystore, password: KeystorePass) =
|
||||||
if isNil(cache): return
|
if isNil(cache): return
|
||||||
let saltKey = keystore.getSaltKey(password)
|
let saltKey = keystore.getSaltKey(password)
|
||||||
|
@ -1206,7 +1206,7 @@ proc readValue*(reader: var JsonReader, value: var lcrypto.PublicKey) {.
|
||||||
# TODO: Can we provide better diagnostic?
|
# TODO: Can we provide better diagnostic?
|
||||||
raiseUnexpectedValue(reader, "Valid hex-encoded public key expected")
|
raiseUnexpectedValue(reader, "Valid hex-encoded public key expected")
|
||||||
|
|
||||||
proc decryptNetKeystore*(nkeystore: NetKeystore,
|
func decryptNetKeystore*(nkeystore: NetKeystore,
|
||||||
password: KeystorePass): KsResult[lcrypto.PrivateKey] =
|
password: KeystorePass): KsResult[lcrypto.PrivateKey] =
|
||||||
var secret: seq[byte]
|
var secret: seq[byte]
|
||||||
defer: burnMem(secret)
|
defer: burnMem(secret)
|
||||||
|
@ -1221,7 +1221,7 @@ proc decryptNetKeystore*(nkeystore: NetKeystore,
|
||||||
else:
|
else:
|
||||||
err $status
|
err $status
|
||||||
|
|
||||||
proc decryptNetKeystore*(nkeystore: JsonString,
|
func decryptNetKeystore*(nkeystore: JsonString,
|
||||||
password: KeystorePass): KsResult[lcrypto.PrivateKey] =
|
password: KeystorePass): KsResult[lcrypto.PrivateKey] =
|
||||||
try:
|
try:
|
||||||
let keystore = parseNetKeystore(string nkeystore)
|
let keystore = parseNetKeystore(string nkeystore)
|
||||||
|
@ -1229,10 +1229,10 @@ proc decryptNetKeystore*(nkeystore: JsonString,
|
||||||
except SerializationError as exc:
|
except SerializationError as exc:
|
||||||
return err(exc.formatMsg("<keystore>"))
|
return err(exc.formatMsg("<keystore>"))
|
||||||
|
|
||||||
proc generateKeystoreSalt*(rng: var HmacDrbgContext): seq[byte] =
|
func generateKeystoreSalt*(rng: var HmacDrbgContext): seq[byte] =
|
||||||
rng.generateBytes(keyLen)
|
rng.generateBytes(keyLen)
|
||||||
|
|
||||||
proc createCryptoField(kdfKind: KdfKind,
|
func createCryptoField(kdfKind: KdfKind,
|
||||||
rng: var HmacDrbgContext,
|
rng: var HmacDrbgContext,
|
||||||
secret: openArray[byte],
|
secret: openArray[byte],
|
||||||
password = KeystorePass.init "",
|
password = KeystorePass.init "",
|
||||||
|
@ -1339,7 +1339,7 @@ proc createKeystore*(kdfKind: KdfKind,
|
||||||
uuid: $uuid,
|
uuid: $uuid,
|
||||||
version: 4)
|
version: 4)
|
||||||
|
|
||||||
proc createRemoteKeystore*(pubKey: ValidatorPubKey, remoteUri: HttpHostUri,
|
func createRemoteKeystore*(pubKey: ValidatorPubKey, remoteUri: HttpHostUri,
|
||||||
version = 1'u64, description = "",
|
version = 1'u64, description = "",
|
||||||
remoteType = RemoteSignerType.Web3Signer,
|
remoteType = RemoteSignerType.Web3Signer,
|
||||||
flags: set[RemoteKeystoreFlag] = {}): RemoteKeystore =
|
flags: set[RemoteKeystoreFlag] = {}): RemoteKeystore =
|
||||||
|
@ -1387,10 +1387,10 @@ func makeWithdrawalCredentials*(k: ValidatorPubKey): Eth2Digest =
|
||||||
bytes
|
bytes
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/specs/phase0/deposit-contract.md#withdrawal-credentials
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/specs/phase0/deposit-contract.md#withdrawal-credentials
|
||||||
proc makeWithdrawalCredentials*(k: CookedPubKey): Eth2Digest =
|
func makeWithdrawalCredentials*(k: CookedPubKey): Eth2Digest =
|
||||||
makeWithdrawalCredentials(k.toPubKey())
|
makeWithdrawalCredentials(k.toPubKey())
|
||||||
|
|
||||||
proc prepareDeposit*(cfg: RuntimeConfig,
|
func prepareDeposit*(cfg: RuntimeConfig,
|
||||||
withdrawalPubKey: CookedPubKey,
|
withdrawalPubKey: CookedPubKey,
|
||||||
signingKey: ValidatorPrivKey, signingPubKey: CookedPubKey,
|
signingKey: ValidatorPrivKey, signingPubKey: CookedPubKey,
|
||||||
amount = MAX_EFFECTIVE_BALANCE.Gwei): DepositData =
|
amount = MAX_EFFECTIVE_BALANCE.Gwei): DepositData =
|
||||||
|
|
|
@ -507,43 +507,86 @@ proc process_bls_to_execution_change*(
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/94a0b6c581f2809aa8aca4ef7ee6fbb63f9d74e9/specs/electra/beacon-chain.md#new-process_execution_layer_exit
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.2/specs/electra/beacon-chain.md#new-process_execution_layer_withdrawal_request
|
||||||
func process_execution_layer_withdrawal_request(
|
func process_execution_layer_withdrawal_request*(
|
||||||
cfg: RuntimeConfig, state: var electra.BeaconState,
|
cfg: RuntimeConfig, state: var electra.BeaconState,
|
||||||
execution_layer_withdrawal_request: ExecutionLayerWithdrawalRequest,
|
execution_layer_withdrawal_request: ExecutionLayerWithdrawalRequest,
|
||||||
exit_queue_info: ExitQueueInfo, cache: var StateCache):
|
cache: var StateCache) =
|
||||||
Result[ExitQueueInfo, cstring] =
|
|
||||||
# Verify pubkey exists
|
|
||||||
let
|
let
|
||||||
pubkey_to_exit = execution_layer_withdrawal_request.validator_pubkey
|
amount = execution_layer_withdrawal_request.amount
|
||||||
validator_index = findValidatorIndex(state, pubkey_to_exit).valueOr:
|
is_full_exit_request = amount == static(FULL_EXIT_REQUEST_AMOUNT.Gwei)
|
||||||
return err("process_execution_layer_withdrawal_request: unknown index for validator pubkey")
|
|
||||||
validator = state.validators.item(validator_index)
|
# If partial withdrawal queue is full, only full exits are processed
|
||||||
|
if lenu64(state.pending_partial_withdrawals) ==
|
||||||
|
PENDING_PARTIAL_WITHDRAWALS_LIMIT and not is_full_exit_request:
|
||||||
|
return
|
||||||
|
|
||||||
|
let
|
||||||
|
request_pubkey = execution_layer_withdrawal_request.validator_pubkey
|
||||||
|
index = findValidatorIndex(state, request_pubkey).valueOr:
|
||||||
|
return
|
||||||
|
validator = state.validators.item(index)
|
||||||
|
|
||||||
# Verify withdrawal credentials
|
# Verify withdrawal credentials
|
||||||
let
|
let
|
||||||
is_execution_address = validator.has_eth1_withdrawal_credential
|
has_correct_credential = has_execution_withdrawal_credential(validator)
|
||||||
is_correct_source_address =
|
is_correct_source_address =
|
||||||
validator.withdrawal_credentials.data.toOpenArray(12, 31) ==
|
validator.withdrawal_credentials.data.toOpenArray(12, 31) ==
|
||||||
execution_layer_withdrawal_request.source_address.data
|
execution_layer_withdrawal_request.source_address.data
|
||||||
if not (is_execution_address and is_correct_source_address):
|
|
||||||
return err("process_execution_layer_withdrawal_request: not both execution address and correct source address")
|
if not (has_correct_credential and is_correct_source_address):
|
||||||
|
return
|
||||||
|
|
||||||
# Verify the validator is active
|
# Verify the validator is active
|
||||||
if not is_active_validator(validator, get_current_epoch(state)):
|
if not is_active_validator(validator, get_current_epoch(state)):
|
||||||
return err("process_execution_layer_withdrawal_request: not active validator")
|
return
|
||||||
|
|
||||||
# Verify exit has not been initiated
|
# Verify exit has not been initiated
|
||||||
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
||||||
return err("process_execution_layer_withdrawal_request: validator exit already initiated")
|
return
|
||||||
|
|
||||||
# Verify the validator has been active long enough
|
# Verify the validator has been active long enough
|
||||||
if get_current_epoch(state) < validator.activation_epoch + cfg.SHARD_COMMITTEE_PERIOD:
|
if get_current_epoch(state) <
|
||||||
return err("process_execution_layer_withdrawal_request: validator not active long enough")
|
validator.activation_epoch + cfg.SHARD_COMMITTEE_PERIOD:
|
||||||
|
return
|
||||||
|
|
||||||
# Initiate exit
|
let pending_balance_to_withdraw =
|
||||||
ok(? initiate_validator_exit(
|
get_pending_balance_to_withdraw(state, index)
|
||||||
cfg, state, validator_index, exit_queue_info, cache))
|
|
||||||
|
if is_full_exit_request:
|
||||||
|
# Only exit validator if it has no pending withdrawals in the queue
|
||||||
|
if pending_balance_to_withdraw == 0.Gwei:
|
||||||
|
if initiate_validator_exit(cfg, state, index, default(ExitQueueInfo),
|
||||||
|
cache).isErr():
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
let
|
||||||
|
has_sufficient_effective_balance =
|
||||||
|
validator.effective_balance >= static(MIN_ACTIVATION_BALANCE.Gwei)
|
||||||
|
has_excess_balance = state.balances.item(index) >
|
||||||
|
static(MIN_ACTIVATION_BALANCE.Gwei) + pending_balance_to_withdraw
|
||||||
|
|
||||||
|
# Only allow partial withdrawals with compounding withdrawal credentials
|
||||||
|
if has_compounding_withdrawal_credential(validator) and
|
||||||
|
has_sufficient_effective_balance and has_excess_balance:
|
||||||
|
let
|
||||||
|
to_withdraw = min(
|
||||||
|
state.balances.item(index) - static(MIN_ACTIVATION_BALANCE.Gwei) -
|
||||||
|
pending_balance_to_withdraw,
|
||||||
|
amount
|
||||||
|
)
|
||||||
|
exit_queue_epoch =
|
||||||
|
compute_exit_epoch_and_update_churn(cfg, state, to_withdraw, cache)
|
||||||
|
withdrawable_epoch =
|
||||||
|
exit_queue_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
|
||||||
|
|
||||||
|
# In theory can fail, but failing/early returning here is indistinguishable
|
||||||
|
discard state.pending_partial_withdrawals.add(PendingPartialWithdrawal(
|
||||||
|
index: index.uint64,
|
||||||
|
amount: to_withdraw,
|
||||||
|
withdrawable_epoch: withdrawable_epoch,
|
||||||
|
))
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#consolidations
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#consolidations
|
||||||
proc process_consolidation*(
|
proc process_consolidation*(
|
||||||
|
@ -703,8 +746,8 @@ proc process_operations(
|
||||||
# [New in Electra:EIP7002:EIP7251]
|
# [New in Electra:EIP7002:EIP7251]
|
||||||
when typeof(body).kind >= ConsensusFork.Electra:
|
when typeof(body).kind >= ConsensusFork.Electra:
|
||||||
for op in body.execution_payload.withdrawal_requests:
|
for op in body.execution_payload.withdrawal_requests:
|
||||||
discard ? process_execution_layer_withdrawal_request(
|
process_execution_layer_withdrawal_request(
|
||||||
cfg, state, op, default(ExitQueueInfo), cache)
|
cfg, state, op, cache)
|
||||||
for op in body.execution_payload.deposit_receipts:
|
for op in body.execution_payload.deposit_receipts:
|
||||||
debugComment "combine with previous bloom filter construction"
|
debugComment "combine with previous bloom filter construction"
|
||||||
let bloom_filter = constructBloomFilter(state.validators.asSeq)
|
let bloom_filter = constructBloomFilter(state.validators.asSeq)
|
||||||
|
@ -1035,87 +1078,6 @@ func process_withdrawals*(
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_execution_layer_withdrawal_request
|
|
||||||
func process_execution_layer_withdrawal_request*(
|
|
||||||
cfg: RuntimeConfig, state: var electra.BeaconState,
|
|
||||||
execution_layer_withdrawal_request: ExecutionLayerWithdrawalRequest,
|
|
||||||
cache: var StateCache) =
|
|
||||||
let
|
|
||||||
amount = execution_layer_withdrawal_request.amount
|
|
||||||
is_full_exit_request = amount == static(FULL_EXIT_REQUEST_AMOUNT.Gwei)
|
|
||||||
|
|
||||||
# If partial withdrawal queue is full, only full exits are processed
|
|
||||||
if lenu64(state.pending_partial_withdrawals) ==
|
|
||||||
PENDING_PARTIAL_WITHDRAWALS_LIMIT and not is_full_exit_request:
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
|
||||||
request_pubkey = execution_layer_withdrawal_request.validator_pubkey
|
|
||||||
index = findValidatorIndex(state, request_pubkey).valueOr:
|
|
||||||
return
|
|
||||||
validator = state.validators.item(index)
|
|
||||||
|
|
||||||
# Verify withdrawal credentials
|
|
||||||
let
|
|
||||||
has_correct_credential = has_execution_withdrawal_credential(validator)
|
|
||||||
is_correct_source_address =
|
|
||||||
validator.withdrawal_credentials.data.toOpenArray(12, 31) ==
|
|
||||||
execution_layer_withdrawal_request.source_address.data
|
|
||||||
|
|
||||||
if not (has_correct_credential and is_correct_source_address):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Verify the validator is active
|
|
||||||
if not is_active_validator(validator, get_current_epoch(state)):
|
|
||||||
return
|
|
||||||
|
|
||||||
# Verify exit has not been initiated
|
|
||||||
if validator.exit_epoch != FAR_FUTURE_EPOCH:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Verify the validator has been active long enough
|
|
||||||
if get_current_epoch(state) <
|
|
||||||
validator.activation_epoch + cfg.SHARD_COMMITTEE_PERIOD:
|
|
||||||
return
|
|
||||||
|
|
||||||
let pending_balance_to_withdraw =
|
|
||||||
get_pending_balance_to_withdraw(state, index)
|
|
||||||
|
|
||||||
if is_full_exit_request:
|
|
||||||
# Only exit validator if it has no pending withdrawals in the queue
|
|
||||||
if pending_balance_to_withdraw == 0.Gwei:
|
|
||||||
if initiate_validator_exit(cfg, state, index, default(ExitQueueInfo),
|
|
||||||
cache).isErr():
|
|
||||||
return
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
|
||||||
has_sufficient_effective_balance =
|
|
||||||
validator.effective_balance >= static(MIN_ACTIVATION_BALANCE.Gwei)
|
|
||||||
has_excess_balance = state.balances.item(index) >
|
|
||||||
static(MIN_ACTIVATION_BALANCE.Gwei) + pending_balance_to_withdraw
|
|
||||||
|
|
||||||
# Only allow partial withdrawals with compounding withdrawal credentials
|
|
||||||
if has_compounding_withdrawal_credential(validator) and
|
|
||||||
has_sufficient_effective_balance and has_excess_balance:
|
|
||||||
let
|
|
||||||
to_withdraw = min(
|
|
||||||
state.balances.item(index) - static(MIN_ACTIVATION_BALANCE.Gwei) -
|
|
||||||
pending_balance_to_withdraw,
|
|
||||||
amount
|
|
||||||
)
|
|
||||||
exit_queue_epoch =
|
|
||||||
compute_exit_epoch_and_update_churn(cfg, state, to_withdraw, cache)
|
|
||||||
withdrawable_epoch =
|
|
||||||
Epoch(exit_queue_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY)
|
|
||||||
|
|
||||||
# In theory can fail, but failing/early returning here is indistinguishable
|
|
||||||
discard state.pending_partial_withdrawals.add(PendingPartialWithdrawal(
|
|
||||||
index: index.uint64,
|
|
||||||
amount: to_withdraw,
|
|
||||||
withdrawable_epoch: withdrawable_epoch,
|
|
||||||
))
|
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#kzg_commitment_to_versioned_hash
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#kzg_commitment_to_versioned_hash
|
||||||
func kzg_commitment_to_versioned_hash*(
|
func kzg_commitment_to_versioned_hash*(
|
||||||
kzg_commitment: KzgCommitment): VersionedHash =
|
kzg_commitment: KzgCommitment): VersionedHash =
|
||||||
|
|
|
@ -1221,7 +1221,7 @@ func process_historical_summaries_update*(
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_balance_deposits
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_balance_deposits
|
||||||
func process_pending_balance_deposits*(
|
func process_pending_balance_deposits*(
|
||||||
cfg: RuntimeConfig, state: var electra.BeaconState,
|
cfg: RuntimeConfig, state: var electra.BeaconState,
|
||||||
cache: var StateCache) =
|
cache: var StateCache): Result[void, cstring] =
|
||||||
let
|
let
|
||||||
available_for_processing = state.deposit_balance_to_consume +
|
available_for_processing = state.deposit_balance_to_consume +
|
||||||
get_activation_exit_churn_limit(cfg, state, cache)
|
get_activation_exit_churn_limit(cfg, state, cache)
|
||||||
|
@ -1232,8 +1232,9 @@ func process_pending_balance_deposits*(
|
||||||
for deposit in state.pending_balance_deposits:
|
for deposit in state.pending_balance_deposits:
|
||||||
if processed_amount + deposit.amount > available_for_processing:
|
if processed_amount + deposit.amount > available_for_processing:
|
||||||
break
|
break
|
||||||
debugComment "do this validatorindex check properly (it truncates)"
|
let deposit_validator_index = ValidatorIndex.init(deposit.index).valueOr:
|
||||||
increase_balance(state, deposit.index.ValidatorIndex, deposit.amount)
|
return err("process_pending_balance_deposits: deposit index out of range")
|
||||||
|
increase_balance(state, deposit_validator_index, deposit.amount)
|
||||||
processed_amount += deposit.amount
|
processed_amount += deposit.amount
|
||||||
inc next_deposit_index
|
inc next_deposit_index
|
||||||
|
|
||||||
|
@ -1247,8 +1248,12 @@ func process_pending_balance_deposits*(
|
||||||
state.deposit_balance_to_consume =
|
state.deposit_balance_to_consume =
|
||||||
available_for_processing - processed_amount
|
available_for_processing - processed_amount
|
||||||
|
|
||||||
|
ok()
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_consolidations
|
# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_consolidations
|
||||||
func process_pending_consolidations*(cfg: RuntimeConfig, state: var electra.BeaconState) =
|
func process_pending_consolidations*(
|
||||||
|
cfg: RuntimeConfig, state: var electra.BeaconState):
|
||||||
|
Result[void, cstring] =
|
||||||
var next_pending_consolidation = 0
|
var next_pending_consolidation = 0
|
||||||
for pending_consolidation in state.pending_consolidations:
|
for pending_consolidation in state.pending_consolidations:
|
||||||
let source_validator =
|
let source_validator =
|
||||||
|
@ -1259,25 +1264,29 @@ func process_pending_consolidations*(cfg: RuntimeConfig, state: var electra.Beac
|
||||||
if source_validator.withdrawable_epoch > get_current_epoch(state):
|
if source_validator.withdrawable_epoch > get_current_epoch(state):
|
||||||
break
|
break
|
||||||
|
|
||||||
|
let
|
||||||
|
source_validator_index = ValidatorIndex.init(
|
||||||
|
pending_consolidation.source_index).valueOr:
|
||||||
|
return err("process_pending_consolidations: source index out of range")
|
||||||
|
target_validator_index = ValidatorIndex.init(
|
||||||
|
pending_consolidation.target_index).valueOr:
|
||||||
|
return err("process_pending_consolidations: target index out of range")
|
||||||
|
|
||||||
# Churn any target excess active balance of target and raise its max
|
# Churn any target excess active balance of target and raise its max
|
||||||
debugComment "truncating integer conversion"
|
switch_to_compounding_validator(state, target_validator_index)
|
||||||
switch_to_compounding_validator(
|
|
||||||
state, pending_consolidation.target_index.ValidatorIndex)
|
|
||||||
|
|
||||||
# Move active balance to target. Excess balance is withdrawable.
|
# Move active balance to target. Excess balance is withdrawable.
|
||||||
debugComment "Truncating"
|
let active_balance = get_active_balance(state, source_validator_index)
|
||||||
let active_balance = get_active_balance(
|
decrease_balance(state, source_validator_index, active_balance)
|
||||||
state, pending_consolidation.source_index.ValidatorIndex)
|
increase_balance(state, target_validator_index, active_balance)
|
||||||
decrease_balance(
|
|
||||||
state, pending_consolidation.source_index.ValidatorIndex, active_balance)
|
|
||||||
increase_balance(
|
|
||||||
state, pending_consolidation.target_index.ValidatorIndex, active_balance)
|
|
||||||
inc next_pending_consolidation
|
inc next_pending_consolidation
|
||||||
|
|
||||||
state.pending_consolidations =
|
state.pending_consolidations =
|
||||||
HashList[PendingConsolidation, Limit PENDING_CONSOLIDATIONS_LIMIT].init(
|
HashList[PendingConsolidation, Limit PENDING_CONSOLIDATIONS_LIMIT].init(
|
||||||
state.pending_consolidations.asSeq[next_pending_consolidation..^1])
|
state.pending_consolidations.asSeq[next_pending_consolidation..^1])
|
||||||
|
|
||||||
|
ok()
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#epoch-processing
|
# https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#epoch-processing
|
||||||
proc process_epoch*(
|
proc process_epoch*(
|
||||||
cfg: RuntimeConfig, state: var phase0.BeaconState, flags: UpdateFlags,
|
cfg: RuntimeConfig, state: var phase0.BeaconState, flags: UpdateFlags,
|
||||||
|
@ -1464,8 +1473,8 @@ proc process_epoch*(
|
||||||
process_slashings(state, info.balances.current_epoch)
|
process_slashings(state, info.balances.current_epoch)
|
||||||
|
|
||||||
process_eth1_data_reset(state)
|
process_eth1_data_reset(state)
|
||||||
process_pending_balance_deposits(cfg, state, cache) # [New in Electra:EIP7251]
|
? process_pending_balance_deposits(cfg, state, cache) # [New in Electra:EIP7251]
|
||||||
process_pending_consolidations(cfg, state) # [New in Electra:EIP7251]
|
? process_pending_consolidations(cfg, state) # [New in Electra:EIP7251]
|
||||||
process_effective_balance_updates(state) # [Modified in Electra:EIP7251]
|
process_effective_balance_updates(state) # [Modified in Electra:EIP7251]
|
||||||
process_slashings_reset(state)
|
process_slashings_reset(state)
|
||||||
process_randao_mixes_reset(state)
|
process_randao_mixes_reset(state)
|
||||||
|
|
|
@ -110,7 +110,7 @@ proc initQueue[A, B](man: SyncManager[A, B]) =
|
||||||
# there is present check `needsBackfill().
|
# there is present check `needsBackfill().
|
||||||
firstSlot
|
firstSlot
|
||||||
else:
|
else:
|
||||||
Slot(firstSlot - 1'u64)
|
firstSlot - 1'u64
|
||||||
man.queue = SyncQueue.init(A, man.direction, startSlot, lastSlot,
|
man.queue = SyncQueue.init(A, man.direction, startSlot, lastSlot,
|
||||||
man.chunkSize, man.getSafeSlot,
|
man.chunkSize, man.getSafeSlot,
|
||||||
man.blockVerifier, 1, man.ident)
|
man.blockVerifier, 1, man.ident)
|
||||||
|
|
|
@ -2022,97 +2022,6 @@ proc publishContributionAndProofs*(
|
||||||
raise (ref ValidatorApiError)(
|
raise (ref ValidatorApiError)(
|
||||||
msg: "Failed to publish sync committee contribution", data: failures)
|
msg: "Failed to publish sync committee contribution", data: failures)
|
||||||
|
|
||||||
proc produceBlockV2*(
|
|
||||||
vc: ValidatorClientRef,
|
|
||||||
slot: Slot,
|
|
||||||
randao_reveal: ValidatorSig,
|
|
||||||
graffiti: GraffitiBytes,
|
|
||||||
strategy: ApiStrategyKind
|
|
||||||
): Future[ProduceBlockResponseV2] {.async.} =
|
|
||||||
const
|
|
||||||
RequestName = "produceBlockV2"
|
|
||||||
|
|
||||||
var failures: seq[ApiNodeFailure]
|
|
||||||
|
|
||||||
case strategy
|
|
||||||
of ApiStrategyKind.First, ApiStrategyKind.Best:
|
|
||||||
let res = vc.firstSuccessParallel(
|
|
||||||
RestPlainResponse,
|
|
||||||
ProduceBlockResponseV2,
|
|
||||||
SlotDuration,
|
|
||||||
ViableNodeStatus,
|
|
||||||
{BeaconNodeRole.BlockProposalData},
|
|
||||||
produceBlockV2Plain(it, slot, randao_reveal, graffiti)):
|
|
||||||
if apiResponse.isErr():
|
|
||||||
handleCommunicationError()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err(apiResponse.error)
|
|
||||||
else:
|
|
||||||
let response = apiResponse.get()
|
|
||||||
case response.status:
|
|
||||||
of 200:
|
|
||||||
let
|
|
||||||
version = response.headers.getString("eth-consensus-version")
|
|
||||||
res = decodeBytes(ProduceBlockResponseV2, response.data,
|
|
||||||
response.contentType, version)
|
|
||||||
if res.isErr():
|
|
||||||
handleUnexpectedData()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err($res.error)
|
|
||||||
else:
|
|
||||||
ApiResponse[ProduceBlockResponseV2].ok(res.get())
|
|
||||||
of 400:
|
|
||||||
handle400()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err(ResponseInvalidError)
|
|
||||||
of 500:
|
|
||||||
handle500()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err(ResponseInternalError)
|
|
||||||
of 503:
|
|
||||||
handle503()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err(ResponseNoSyncError)
|
|
||||||
else:
|
|
||||||
handleUnexpectedCode()
|
|
||||||
ApiResponse[ProduceBlockResponseV2].err(ResponseUnexpectedError)
|
|
||||||
|
|
||||||
if res.isErr():
|
|
||||||
raise (ref ValidatorApiError)(msg: res.error, data: failures)
|
|
||||||
return res.get()
|
|
||||||
|
|
||||||
of ApiStrategyKind.Priority:
|
|
||||||
vc.firstSuccessSequential(
|
|
||||||
RestPlainResponse,
|
|
||||||
SlotDuration,
|
|
||||||
ViableNodeStatus,
|
|
||||||
{BeaconNodeRole.BlockProposalData},
|
|
||||||
produceBlockV2Plain(it, slot, randao_reveal, graffiti)):
|
|
||||||
if apiResponse.isErr():
|
|
||||||
handleCommunicationError()
|
|
||||||
false
|
|
||||||
else:
|
|
||||||
let response = apiResponse.get()
|
|
||||||
case response.status:
|
|
||||||
of 200:
|
|
||||||
let
|
|
||||||
version = response.headers.getString("eth-consensus-version")
|
|
||||||
res = decodeBytes(ProduceBlockResponseV2, response.data,
|
|
||||||
response.contentType, version)
|
|
||||||
if res.isOk(): return res.get()
|
|
||||||
handleUnexpectedData()
|
|
||||||
false
|
|
||||||
of 400:
|
|
||||||
handle400()
|
|
||||||
false
|
|
||||||
of 500:
|
|
||||||
handle500()
|
|
||||||
false
|
|
||||||
of 503:
|
|
||||||
handle503()
|
|
||||||
false
|
|
||||||
else:
|
|
||||||
handleUnexpectedCode()
|
|
||||||
false
|
|
||||||
|
|
||||||
raise (ref ValidatorApiError)(
|
|
||||||
msg: "Failed to produce block", data: failures)
|
|
||||||
|
|
||||||
proc produceBlockV3*(
|
proc produceBlockV3*(
|
||||||
vc: ValidatorClientRef,
|
vc: ValidatorClientRef,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
@ -2161,24 +2070,15 @@ proc produceBlockV3*(
|
||||||
ApiResponse[ProduceBlockResponseV3].ok(res.get())
|
ApiResponse[ProduceBlockResponseV3].ok(res.get())
|
||||||
of 400:
|
of 400:
|
||||||
handle400()
|
handle400()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
ApiResponse[ProduceBlockResponseV3].err(ResponseInvalidError)
|
|
||||||
of 404:
|
|
||||||
# TODO (cheatfate): Remove this handler when produceBlockV2 support
|
|
||||||
# will be dropped.
|
|
||||||
handle400()
|
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
ApiResponse[ProduceBlockResponseV3].err(ResponseInvalidError)
|
ApiResponse[ProduceBlockResponseV3].err(ResponseInvalidError)
|
||||||
of 500:
|
of 500:
|
||||||
handle500()
|
handle500()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
ApiResponse[ProduceBlockResponseV3].err(ResponseInternalError)
|
ApiResponse[ProduceBlockResponseV3].err(ResponseInternalError)
|
||||||
of 503:
|
of 503:
|
||||||
handle503()
|
handle503()
|
||||||
ApiResponse[ProduceBlockResponseV3].err(ResponseNoSyncError)
|
ApiResponse[ProduceBlockResponseV3].err(ResponseNoSyncError)
|
||||||
else:
|
else:
|
||||||
handleUnexpectedCode()
|
handleUnexpectedCode()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
ApiResponse[ProduceBlockResponseV3].err(ResponseUnexpectedError)
|
ApiResponse[ProduceBlockResponseV3].err(ResponseUnexpectedError)
|
||||||
|
|
||||||
if res.isErr():
|
if res.isErr():
|
||||||
|
@ -2216,24 +2116,15 @@ proc produceBlockV3*(
|
||||||
false
|
false
|
||||||
of 400:
|
of 400:
|
||||||
handle400()
|
handle400()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
false
|
|
||||||
of 404:
|
|
||||||
# TODO (cheatfate): Remove this handler when produceBlockV2 support
|
|
||||||
# will be dropped.
|
|
||||||
handle400()
|
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
false
|
false
|
||||||
of 500:
|
of 500:
|
||||||
handle500()
|
handle500()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
false
|
false
|
||||||
of 503:
|
of 503:
|
||||||
handle503()
|
handle503()
|
||||||
false
|
false
|
||||||
else:
|
else:
|
||||||
handleUnexpectedCode()
|
handleUnexpectedCode()
|
||||||
node.features.incl(RestBeaconNodeFeature.NoProduceBlockV3)
|
|
||||||
false
|
false
|
||||||
|
|
||||||
raise (ref ValidatorApiError)(
|
raise (ref ValidatorApiError)(
|
||||||
|
|
|
@ -49,114 +49,6 @@ func shortLog(v: ForkedMaybeBlindedBeaconBlock): auto =
|
||||||
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
||||||
proposerKey: ValidatorPubKey) {.async.}
|
proposerKey: ValidatorPubKey) {.async.}
|
||||||
|
|
||||||
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 = validatorLog(validator)
|
|
||||||
let
|
|
||||||
produceBlockResponse =
|
|
||||||
try:
|
|
||||||
await vc.produceBlockV2(slot, randao_reveal, graffiti,
|
|
||||||
ApiStrategyKind.Best)
|
|
||||||
except ValidatorApiError as exc:
|
|
||||||
warn "Unable to retrieve block data", reason = exc.getFailureReason()
|
|
||||||
return Opt.none(PreparedBeaconBlock)
|
|
||||||
except CancelledError as exc:
|
|
||||||
debug "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)
|
|
||||||
case produceBlockResponse.kind
|
|
||||||
of ConsensusFork.Phase0:
|
|
||||||
let blck = produceBlockResponse.phase0Data
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.none(deneb.KzgProofs),
|
|
||||||
blobsOpt: Opt.none(deneb.Blobs)))
|
|
||||||
of ConsensusFork.Altair:
|
|
||||||
let blck = produceBlockResponse.altairData
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.none(deneb.KzgProofs),
|
|
||||||
blobsOpt: Opt.none(deneb.Blobs)))
|
|
||||||
of ConsensusFork.Bellatrix:
|
|
||||||
let blck = produceBlockResponse.bellatrixData
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.none(deneb.KzgProofs),
|
|
||||||
blobsOpt: Opt.none(deneb.Blobs)))
|
|
||||||
of ConsensusFork.Capella:
|
|
||||||
let blck = produceBlockResponse.capellaData
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.none(deneb.KzgProofs),
|
|
||||||
blobsOpt: Opt.none(deneb.Blobs)))
|
|
||||||
of ConsensusFork.Deneb:
|
|
||||||
let
|
|
||||||
blck = produceBlockResponse.denebData.`block`
|
|
||||||
kzgProofs = produceBlockResponse.denebData.kzg_proofs
|
|
||||||
blobs = produceBlockResponse.denebData.blobs
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.some(kzgProofs),
|
|
||||||
blobsOpt: Opt.some(blobs)))
|
|
||||||
of ConsensusFork.Electra:
|
|
||||||
let
|
|
||||||
blck = produceBlockResponse.electraData.`block`
|
|
||||||
kzgProofs = produceBlockResponse.electraData.kzg_proofs
|
|
||||||
blobs = produceBlockResponse.electraData.blobs
|
|
||||||
return Opt.some(PreparedBeaconBlock(blockRoot: hash_tree_root(blck),
|
|
||||||
data: ForkedBeaconBlock.init(blck),
|
|
||||||
kzgProofsOpt: Opt.some(kzgProofs),
|
|
||||||
blobsOpt: Opt.some(blobs)))
|
|
||||||
|
|
||||||
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 = validatorLog(validator)
|
|
||||||
let
|
|
||||||
beaconBlock =
|
|
||||||
try:
|
|
||||||
await vc.produceBlindedBlock(slot, randao_reveal, graffiti,
|
|
||||||
ApiStrategyKind.Best)
|
|
||||||
except ValidatorApiError as exc:
|
|
||||||
warn "Unable to retrieve blinded block data", error_msg = exc.msg,
|
|
||||||
reason = exc.getFailureReason()
|
|
||||||
return Opt.none(PreparedBlindedBeaconBlock)
|
|
||||||
except CancelledError as exc:
|
|
||||||
debug "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(forkyBlck)
|
|
||||||
|
|
||||||
return Opt.some(
|
|
||||||
PreparedBlindedBeaconBlock(blockRoot: blockRoot, data: beaconBlock))
|
|
||||||
|
|
||||||
proc lazyWait[T](fut: Future[T]) {.async.} =
|
|
||||||
try:
|
|
||||||
discard await fut
|
|
||||||
except CatchableError:
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc prepareRandao(vc: ValidatorClientRef, slot: Slot,
|
proc prepareRandao(vc: ValidatorClientRef, slot: Slot,
|
||||||
proposerKey: ValidatorPubKey) {.async.} =
|
proposerKey: ValidatorPubKey) {.async.} =
|
||||||
if slot == GENESIS_SLOT:
|
if slot == GENESIS_SLOT:
|
||||||
|
@ -209,21 +101,9 @@ proc spawnProposalTask(vc: ValidatorClientRef,
|
||||||
duty: duty
|
duty: duty
|
||||||
)
|
)
|
||||||
|
|
||||||
proc isProduceBlockV3Supported(vc: ValidatorClientRef): bool =
|
|
||||||
let
|
|
||||||
# Both `statuses` and `roles` should be set to values which are used in
|
|
||||||
# api.produceBlockV3() call.
|
|
||||||
statuses = ViableNodeStatus
|
|
||||||
roles = {BeaconNodeRole.BlockProposalData}
|
|
||||||
|
|
||||||
for node in vc.filterNodes(statuses, roles):
|
|
||||||
if RestBeaconNodeFeature.NoProduceBlockV3 notin node.features:
|
|
||||||
return true
|
|
||||||
false
|
|
||||||
|
|
||||||
proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
fork: Fork, randaoReveal: ValidatorSig,
|
fork: Fork, randaoReveal: ValidatorSig,
|
||||||
validator: AttachedValidator): Future[bool] {.async.} =
|
validator: AttachedValidator) {.async.} =
|
||||||
let
|
let
|
||||||
genesisRoot = vc.beaconGenesis.genesis_validators_root
|
genesisRoot = vc.beaconGenesis.genesis_validators_root
|
||||||
graffiti =
|
graffiti =
|
||||||
|
@ -247,14 +127,14 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
ApiStrategyKind.Best)
|
ApiStrategyKind.Best)
|
||||||
except ValidatorApiError as exc:
|
except ValidatorApiError as exc:
|
||||||
warn "Unable to retrieve block data", reason = exc.getFailureReason()
|
warn "Unable to retrieve block data", reason = exc.getFailureReason()
|
||||||
return false
|
return
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
debug "Block data production has been interrupted"
|
debug "Block data production has been interrupted"
|
||||||
raise exc
|
raise exc
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
error "An unexpected error occurred while getting block data",
|
error "An unexpected error occurred while getting block data",
|
||||||
error_name = exc.name, error_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return false
|
return
|
||||||
|
|
||||||
withForkyMaybeBlindedBlck(maybeBlock):
|
withForkyMaybeBlindedBlck(maybeBlock):
|
||||||
when isBlinded:
|
when isBlinded:
|
||||||
|
@ -282,7 +162,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
|
|
||||||
if notSlashable.isErr():
|
if notSlashable.isErr():
|
||||||
warn "Slashing protection activated for blinded block proposal"
|
warn "Slashing protection activated for blinded block proposal"
|
||||||
return false
|
return
|
||||||
|
|
||||||
let signature =
|
let signature =
|
||||||
try:
|
try:
|
||||||
|
@ -292,7 +172,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
if res.isErr():
|
if res.isErr():
|
||||||
warn "Unable to sign blinded block proposal using remote signer",
|
warn "Unable to sign blinded block proposal using remote signer",
|
||||||
reason = res.error()
|
reason = res.error()
|
||||||
return false
|
return
|
||||||
res.get()
|
res.get()
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
debug "Blinded block signature process has been interrupted"
|
debug "Blinded block signature process has been interrupted"
|
||||||
|
@ -300,7 +180,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
error "An unexpected error occurred while signing blinded block",
|
error "An unexpected error occurred while signing blinded block",
|
||||||
error_name = exc.name, error_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return false
|
return
|
||||||
|
|
||||||
let
|
let
|
||||||
signedBlock =
|
signedBlock =
|
||||||
|
@ -313,7 +193,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
except ValidatorApiError as exc:
|
except ValidatorApiError as exc:
|
||||||
warn "Unable to publish blinded block",
|
warn "Unable to publish blinded block",
|
||||||
reason = exc.getFailureReason()
|
reason = exc.getFailureReason()
|
||||||
return false
|
return
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
debug "Blinded block publication has been interrupted"
|
debug "Blinded block publication has been interrupted"
|
||||||
raise exc
|
raise exc
|
||||||
|
@ -321,17 +201,15 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
error "An unexpected error occurred while publishing blinded " &
|
error "An unexpected error occurred while publishing blinded " &
|
||||||
"block",
|
"block",
|
||||||
error_name = exc.name, error_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return false
|
return
|
||||||
|
|
||||||
if res:
|
if res:
|
||||||
let delay = vc.getDelay(slot.block_deadline())
|
let delay = vc.getDelay(slot.block_deadline())
|
||||||
beacon_blocks_sent.inc()
|
beacon_blocks_sent.inc()
|
||||||
beacon_blocks_sent_delay.observe(delay.toFloatSeconds())
|
beacon_blocks_sent_delay.observe(delay.toFloatSeconds())
|
||||||
notice "Blinded block published", delay = delay
|
notice "Blinded block published", delay = delay
|
||||||
true
|
|
||||||
else:
|
else:
|
||||||
warn "Blinded block was not accepted by beacon node"
|
warn "Blinded block was not accepted by beacon node"
|
||||||
false
|
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
blockRoot = hash_tree_root(
|
blockRoot = hash_tree_root(
|
||||||
|
@ -367,7 +245,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
|
|
||||||
if notSlashable.isErr():
|
if notSlashable.isErr():
|
||||||
warn "Slashing protection activated for block proposal"
|
warn "Slashing protection activated for block proposal"
|
||||||
return false
|
return
|
||||||
|
|
||||||
let
|
let
|
||||||
signature =
|
signature =
|
||||||
|
@ -377,7 +255,7 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
if res.isErr():
|
if res.isErr():
|
||||||
warn "Unable to sign block proposal using remote signer",
|
warn "Unable to sign block proposal using remote signer",
|
||||||
reason = res.error()
|
reason = res.error()
|
||||||
return false
|
return
|
||||||
res.get()
|
res.get()
|
||||||
except CancelledError as exc:
|
except CancelledError as exc:
|
||||||
debug "Block signature process has been interrupted"
|
debug "Block signature process has been interrupted"
|
||||||
|
@ -385,240 +263,12 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
error "An unexpected error occurred while signing block",
|
error "An unexpected error occurred while signing block",
|
||||||
error_name = exc.name, error_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return false
|
return
|
||||||
|
|
||||||
signedBlockContents =
|
signedBlockContents =
|
||||||
RestPublishedSignedBlockContents.init(
|
RestPublishedSignedBlockContents.init(
|
||||||
forkyMaybeBlindedBlck, blockRoot, signature)
|
forkyMaybeBlindedBlck, blockRoot, signature)
|
||||||
|
|
||||||
res =
|
|
||||||
try:
|
|
||||||
debug "Sending block"
|
|
||||||
await vc.publishBlock(signedBlockContents, ApiStrategyKind.First)
|
|
||||||
except ValidatorApiError as exc:
|
|
||||||
warn "Unable to publish block", reason = exc.getFailureReason()
|
|
||||||
return false
|
|
||||||
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 false
|
|
||||||
|
|
||||||
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
|
|
||||||
true
|
|
||||||
else:
|
|
||||||
warn "Block was not accepted by beacon node"
|
|
||||||
false
|
|
||||||
|
|
||||||
proc publishBlockV2(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
|
||||||
fork: Fork, randaoReveal: ValidatorSig,
|
|
||||||
validator: AttachedValidator) {.async.} =
|
|
||||||
let
|
|
||||||
genesisRoot = vc.beaconGenesis.genesis_validators_root
|
|
||||||
graffiti = vc.getGraffitiBytes(validator)
|
|
||||||
vindex = validator.index.get()
|
|
||||||
|
|
||||||
logScope:
|
|
||||||
validator = validatorLog(validator)
|
|
||||||
validator_index = vindex
|
|
||||||
slot = slot
|
|
||||||
wall_slot = currentSlot
|
|
||||||
|
|
||||||
var beaconBlocks =
|
|
||||||
block:
|
|
||||||
let blindedBlockFut =
|
|
||||||
if vc.config.payloadBuilderEnable:
|
|
||||||
vc.produceBlindedBlock(currentSlot, slot, randaoReveal, graffiti,
|
|
||||||
validator)
|
|
||||||
else:
|
|
||||||
nil
|
|
||||||
let normalBlockFut = vc.produceBlock(currentSlot, slot, randaoReveal,
|
|
||||||
graffiti, validator)
|
|
||||||
let blindedBlock =
|
|
||||||
if isNil(blindedBlockFut):
|
|
||||||
Opt.none(PreparedBlindedBeaconBlock)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
await blindedBlockFut
|
|
||||||
except CancelledError as exc:
|
|
||||||
if not(normalBlockFut.finished()):
|
|
||||||
await normalBlockFut.cancelAndWait()
|
|
||||||
raise exc
|
|
||||||
except CatchableError:
|
|
||||||
# This should not happen, because all the exceptions are handled.
|
|
||||||
Opt.none(PreparedBlindedBeaconBlock)
|
|
||||||
|
|
||||||
let normalBlock =
|
|
||||||
if blindedBlock.isNone():
|
|
||||||
try:
|
|
||||||
await normalBlockFut
|
|
||||||
except CancelledError as exc:
|
|
||||||
raise exc
|
|
||||||
except CatchableError:
|
|
||||||
# This should not happen, because all the exceptions are handled.
|
|
||||||
Opt.none(PreparedBeaconBlock)
|
|
||||||
else:
|
|
||||||
if not(normalBlockFut.finished()):
|
|
||||||
asyncSpawn lazyWait(normalBlockFut)
|
|
||||||
Opt.none(PreparedBeaconBlock)
|
|
||||||
|
|
||||||
if blindedBlock.isNone() and normalBlock.isNone():
|
|
||||||
return
|
|
||||||
|
|
||||||
(blindedBlock: blindedBlock, normalBlock: normalBlock)
|
|
||||||
|
|
||||||
if beaconBlocks.blindedBlock.isSome():
|
|
||||||
let
|
|
||||||
preparedBlock = beaconBlocks.blindedBlock.get()
|
|
||||||
signingRoot = compute_block_signing_root(fork, genesisRoot, slot,
|
|
||||||
preparedBlock.blockRoot)
|
|
||||||
notSlashable = vc.attachedValidators[]
|
|
||||||
.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():
|
|
||||||
warn "Unable to sign blinded block proposal using remote signer",
|
|
||||||
reason = res.error()
|
|
||||||
return
|
|
||||||
res.get()
|
|
||||||
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 as exc:
|
|
||||||
warn "Unable to publish blinded block",
|
|
||||||
reason = exc.getFailureReason()
|
|
||||||
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:
|
|
||||||
warn "Slashing protection activated for blinded block proposal"
|
|
||||||
else:
|
|
||||||
let
|
|
||||||
preparedBlock = beaconBlocks.normalBlock.get()
|
|
||||||
signingRoot = compute_block_signing_root(fork, genesisRoot, slot,
|
|
||||||
preparedBlock.blockRoot)
|
|
||||||
notSlashable = vc.attachedValidators[]
|
|
||||||
.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():
|
|
||||||
warn "Unable to sign block proposal using remote signer",
|
|
||||||
reason = 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
|
|
||||||
|
|
||||||
signedBlockContents =
|
|
||||||
case preparedBlock.data.kind
|
|
||||||
of ConsensusFork.Phase0:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Phase0,
|
|
||||||
phase0Data: phase0.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.phase0Data,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature))
|
|
||||||
of ConsensusFork.Altair:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Altair,
|
|
||||||
altairData: altair.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.altairData,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature))
|
|
||||||
of ConsensusFork.Bellatrix:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Bellatrix,
|
|
||||||
bellatrixData: bellatrix.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.bellatrixData,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature))
|
|
||||||
of ConsensusFork.Capella:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Capella,
|
|
||||||
capellaData: capella.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.capellaData,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature))
|
|
||||||
of ConsensusFork.Deneb:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Deneb,
|
|
||||||
denebData: DenebSignedBlockContents(
|
|
||||||
signed_block: deneb.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.denebData,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature),
|
|
||||||
kzg_proofs: preparedBlock.kzgProofsOpt.get,
|
|
||||||
blobs: preparedBlock.blobsOpt.get))
|
|
||||||
of ConsensusFork.Electra:
|
|
||||||
RestPublishedSignedBlockContents(kind: ConsensusFork.Electra,
|
|
||||||
electraData: ElectraSignedBlockContents(
|
|
||||||
signed_block: electra.SignedBeaconBlock(
|
|
||||||
message: preparedBlock.data.electraData,
|
|
||||||
root: preparedBlock.blockRoot,
|
|
||||||
signature: signature),
|
|
||||||
kzg_proofs: preparedBlock.kzgProofsOpt.get,
|
|
||||||
blobs: preparedBlock.blobsOpt.get))
|
|
||||||
|
|
||||||
res =
|
res =
|
||||||
try:
|
try:
|
||||||
debug "Sending block"
|
debug "Sending block"
|
||||||
|
@ -641,8 +291,6 @@ proc publishBlockV2(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
notice "Block published", delay = delay
|
notice "Block published", delay = delay
|
||||||
else:
|
else:
|
||||||
warn "Block was not accepted by beacon node"
|
warn "Block was not accepted by beacon node"
|
||||||
else:
|
|
||||||
warn "Slashing protection activated for block proposal"
|
|
||||||
|
|
||||||
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
validator: AttachedValidator) {.async.} =
|
validator: AttachedValidator) {.async.} =
|
||||||
|
@ -677,18 +325,7 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||||
error_name = exc.name, error_msg = exc.msg
|
error_name = exc.name, error_msg = exc.msg
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO (cheatfate): This branch should be removed as soon as `produceBlockV2`
|
await vc.publishBlockV3(currentSlot, slot, fork, randaoReveal, validator)
|
||||||
# call will be fully deprecated.
|
|
||||||
if vc.isProduceBlockV3Supported():
|
|
||||||
# We call `V3` first, if call fails and `isProduceBlockV3Supported()`
|
|
||||||
# did not find any nodes which support `V3` we try to call `V2`.
|
|
||||||
let res =
|
|
||||||
await vc.publishBlockV3(currentSlot, slot, fork, randaoReveal, validator)
|
|
||||||
if not(res) and not(vc.isProduceBlockV3Supported()):
|
|
||||||
notice "Block production using V3 failed, trying V2"
|
|
||||||
await vc.publishBlockV2(currentSlot, slot, fork, randaoReveal, validator)
|
|
||||||
else:
|
|
||||||
await vc.publishBlockV2(currentSlot, slot, fork, randaoReveal, validator)
|
|
||||||
|
|
||||||
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
||||||
proposerKey: ValidatorPubKey) {.async.} =
|
proposerKey: ValidatorPubKey) {.async.} =
|
||||||
|
|
|
@ -117,7 +117,6 @@ type
|
||||||
|
|
||||||
RestBeaconNodeFeature* {.pure.} = enum
|
RestBeaconNodeFeature* {.pure.} = enum
|
||||||
NoNimbusExtensions, ## BN does not support Nimbus Extensions
|
NoNimbusExtensions, ## BN does not support Nimbus Extensions
|
||||||
NoProduceBlockV3 ## BN does not support produceBlockV3 call
|
|
||||||
|
|
||||||
TimeOffset* = object
|
TimeOffset* = object
|
||||||
value: int64
|
value: int64
|
||||||
|
@ -1512,7 +1511,7 @@ proc `+`*(slot: Slot, epochs: Epoch): Slot =
|
||||||
|
|
||||||
func finish_slot*(epoch: Epoch): Slot =
|
func finish_slot*(epoch: Epoch): Slot =
|
||||||
## Return the last slot of ``epoch``.
|
## Return the last slot of ``epoch``.
|
||||||
Slot((epoch + 1).start_slot() - 1)
|
(epoch + 1).start_slot() - 1
|
||||||
|
|
||||||
proc getGraffitiBytes*(vc: ValidatorClientRef,
|
proc getGraffitiBytes*(vc: ValidatorClientRef,
|
||||||
validator: AttachedValidator): GraffitiBytes =
|
validator: AttachedValidator): GraffitiBytes =
|
||||||
|
|
34
ncli/era.nim
34
ncli/era.nim
|
@ -92,41 +92,43 @@ proc appendRecord(f: IoHandle, index: Index): Result[int64, string] =
|
||||||
f.appendIndex(index.startSlot, index.offsets)
|
f.appendIndex(index.startSlot, index.offsets)
|
||||||
|
|
||||||
proc readIndex*(f: IoHandle): Result[Index, string] =
|
proc readIndex*(f: IoHandle): Result[Index, string] =
|
||||||
|
var
|
||||||
|
buf: seq[byte]
|
||||||
|
pos: int
|
||||||
|
|
||||||
let
|
let
|
||||||
startPos = ? f.getFilePos().mapErr(toString)
|
startPos = ? f.getFilePos().mapErr(toString)
|
||||||
fileSize = ? f.getFileSize().mapErr(toString)
|
fileSize = ? f.getFileSize().mapErr(toString)
|
||||||
header = ? f.readHeader()
|
header = ? f.readRecord(buf)
|
||||||
|
|
||||||
if header.typ != E2Index: return err("not an index")
|
if header.typ != E2Index: return err("not an index")
|
||||||
if header.len < 16: return err("index entry too small")
|
if buf.len < 16: return err("index entry too small")
|
||||||
if header.len mod 8 != 0: return err("index length invalid")
|
if buf.len mod 8 != 0: return err("index length invalid")
|
||||||
|
|
||||||
var buf: array[8, byte]
|
|
||||||
? f.readFileExact(buf)
|
|
||||||
let
|
let
|
||||||
slot = uint64.fromBytesLE(buf)
|
slot = uint64.fromBytesLE(buf.toOpenArray(pos, pos + 7))
|
||||||
count = header.len div 8 - 2
|
count = buf.len div 8 - 2
|
||||||
|
pos += 8
|
||||||
|
|
||||||
|
# technically not an error, but we'll throw this sanity check in here..
|
||||||
|
if slot > int32.high().uint64: return err("fishy slot")
|
||||||
|
|
||||||
var offsets = newSeqUninitialized[int64](count)
|
var offsets = newSeqUninitialized[int64](count)
|
||||||
for i in 0..<count:
|
for i in 0..<count:
|
||||||
? f.readFileExact(buf)
|
|
||||||
|
|
||||||
let
|
let
|
||||||
offset = uint64.fromBytesLE(buf)
|
offset = uint64.fromBytesLE(buf.toOpenArray(pos, pos + 7))
|
||||||
absolute =
|
absolute =
|
||||||
if offset == 0: 0'i64
|
if offset == 0: 0'i64
|
||||||
else:
|
else:
|
||||||
# Wrapping math is actually convenient here
|
# Wrapping math is actually convenient here
|
||||||
cast[int64](cast[uint64](startPos) + offset)
|
cast[int64](cast[uint64](startPos) + offset)
|
||||||
|
|
||||||
if absolute < 0 or absolute > fileSize: return err("Invalid offset")
|
if absolute < 0 or absolute > fileSize: return err("invalid offset")
|
||||||
offsets[i] = absolute
|
offsets[i] = absolute
|
||||||
|
pos += 8
|
||||||
|
|
||||||
? f.readFileExact(buf)
|
if uint64(count) != uint64.fromBytesLE(buf.toOpenArray(pos, pos + 7)):
|
||||||
if uint64(count) != uint64.fromBytesLE(buf): return err("invalid count")
|
return err("invalid count")
|
||||||
|
|
||||||
# technically not an error, but we'll throw this sanity check in here..
|
|
||||||
if slot > int32.high().uint64: return err("fishy slot")
|
|
||||||
|
|
||||||
ok(Index(startSlot: Slot(slot), offsets: offsets))
|
ok(Index(startSlot: Slot(slot), offsets: offsets))
|
||||||
|
|
||||||
|
|
|
@ -239,16 +239,19 @@ proc doSSZ(conf: NcliConf) =
|
||||||
of "bellatrix_signed_block": printit(bellatrix.SignedBeaconBlock)
|
of "bellatrix_signed_block": printit(bellatrix.SignedBeaconBlock)
|
||||||
of "capella_signed_block": printit(capella.SignedBeaconBlock)
|
of "capella_signed_block": printit(capella.SignedBeaconBlock)
|
||||||
of "deneb_signed_block": printit(deneb.SignedBeaconBlock)
|
of "deneb_signed_block": printit(deneb.SignedBeaconBlock)
|
||||||
|
of "electra_signed_block": printit(electra.SignedBeaconBlock)
|
||||||
of "phase0_block": printit(phase0.BeaconBlock)
|
of "phase0_block": printit(phase0.BeaconBlock)
|
||||||
of "altair_block": printit(altair.BeaconBlock)
|
of "altair_block": printit(altair.BeaconBlock)
|
||||||
of "bellatrix_block": printit(bellatrix.BeaconBlock)
|
of "bellatrix_block": printit(bellatrix.BeaconBlock)
|
||||||
of "capella_block": printit(capella.BeaconBlock)
|
of "capella_block": printit(capella.BeaconBlock)
|
||||||
of "deneb_block": printit(deneb.BeaconBlock)
|
of "deneb_block": printit(deneb.BeaconBlock)
|
||||||
|
of "electra_block": printit(electra.BeaconBlock)
|
||||||
of "phase0_block_body": printit(phase0.BeaconBlockBody)
|
of "phase0_block_body": printit(phase0.BeaconBlockBody)
|
||||||
of "altair_block_body": printit(altair.BeaconBlockBody)
|
of "altair_block_body": printit(altair.BeaconBlockBody)
|
||||||
of "bellatrix_block_body": printit(bellatrix.BeaconBlockBody)
|
of "bellatrix_block_body": printit(bellatrix.BeaconBlockBody)
|
||||||
of "capella_block_body": printit(capella.BeaconBlockBody)
|
of "capella_block_body": printit(capella.BeaconBlockBody)
|
||||||
of "deneb_block_body": printit(deneb.BeaconBlockBody)
|
of "deneb_block_body": printit(deneb.BeaconBlockBody)
|
||||||
|
of "electra_block_body": printit(electra.BeaconBlockBody)
|
||||||
of "block_header": printit(BeaconBlockHeader)
|
of "block_header": printit(BeaconBlockHeader)
|
||||||
of "deposit": printit(Deposit)
|
of "deposit": printit(Deposit)
|
||||||
of "deposit_data": printit(DepositData)
|
of "deposit_data": printit(DepositData)
|
||||||
|
@ -258,6 +261,7 @@ proc doSSZ(conf: NcliConf) =
|
||||||
of "bellatrix_state": printit(bellatrix.BeaconState)
|
of "bellatrix_state": printit(bellatrix.BeaconState)
|
||||||
of "capella_state": printit(capella.BeaconState)
|
of "capella_state": printit(capella.BeaconState)
|
||||||
of "deneb_state": printit(deneb.BeaconState)
|
of "deneb_state": printit(deneb.BeaconState)
|
||||||
|
of "electra_state": printit(electra.BeaconState)
|
||||||
of "proposer_slashing": printit(ProposerSlashing)
|
of "proposer_slashing": printit(ProposerSlashing)
|
||||||
of "voluntary_exit": printit(VoluntaryExit)
|
of "voluntary_exit": printit(VoluntaryExit)
|
||||||
|
|
||||||
|
|
|
@ -126,14 +126,13 @@ static:
|
||||||
"15227487_86601706.echop"]: # Wrong extension
|
"15227487_86601706.echop"]: # Wrong extension
|
||||||
doAssert not filename.matchFilenameAggregatedFiles
|
doAssert not filename.matchFilenameAggregatedFiles
|
||||||
|
|
||||||
proc getUnaggregatedFilesEpochRange*(
|
proc getUnaggregatedFilesEpochRange*(dir: string):
|
||||||
dir: string
|
tuple[firstEpoch, lastEpoch: Epoch] {.raises: [OSError, ValueError].} =
|
||||||
): tuple[firstEpoch, lastEpoch: Epoch] {.raises: [OSError, ValueError].} =
|
|
||||||
var smallestEpochFileName =
|
var smallestEpochFileName =
|
||||||
'9'.repeat(epochInfoFileNameDigitsCount) & epochFileNameExtension
|
'9'.repeat(epochInfoFileNameDigitsCount) & epochFileNameExtension
|
||||||
var largestEpochFileName =
|
var largestEpochFileName =
|
||||||
'0'.repeat(epochInfoFileNameDigitsCount) & epochFileNameExtension
|
'0'.repeat(epochInfoFileNameDigitsCount) & epochFileNameExtension
|
||||||
for (_, fn) in walkDir(dir.string, relative = true):
|
for (_, fn) in walkDir(dir, relative = true):
|
||||||
if fn.matchFilenameUnaggregatedFiles:
|
if fn.matchFilenameUnaggregatedFiles:
|
||||||
if fn < smallestEpochFileName:
|
if fn < smallestEpochFileName:
|
||||||
smallestEpochFileName = fn
|
smallestEpochFileName = fn
|
||||||
|
@ -151,7 +150,7 @@ proc getUnaggregatedFilesLastEpoch*(
|
||||||
proc getAggregatedFilesLastEpoch*(
|
proc getAggregatedFilesLastEpoch*(
|
||||||
dir: string): Epoch {.raises: [OSError, ValueError].}=
|
dir: string): Epoch {.raises: [OSError, ValueError].}=
|
||||||
var largestEpochInFileName = 0'u
|
var largestEpochInFileName = 0'u
|
||||||
for (_, fn) in walkDir(dir.string, relative = true):
|
for (_, fn) in walkDir(dir, relative = true):
|
||||||
if fn.matchFilenameAggregatedFiles:
|
if fn.matchFilenameAggregatedFiles:
|
||||||
let fileLastEpoch = parseUInt(
|
let fileLastEpoch = parseUInt(
|
||||||
fn[epochInfoFileNameDigitsCount + 1 .. 2 * epochInfoFileNameDigitsCount])
|
fn[epochInfoFileNameDigitsCount + 1 .. 2 * epochInfoFileNameDigitsCount])
|
||||||
|
|
|
@ -553,8 +553,8 @@ proc sendDeposits(deposits: seq[LaunchPadDeposit],
|
||||||
|
|
||||||
var web3 = await initWeb3(web3Url, privateKey)
|
var web3 = await initWeb3(web3Url, privateKey)
|
||||||
let gasPrice = int(await web3.provider.eth_gasPrice()) * 2
|
let gasPrice = int(await web3.provider.eth_gasPrice()) * 2
|
||||||
let depositContract = web3.contractSender(DepositContract,
|
let depositContract = web3.contractSender(
|
||||||
Eth1Address depositContractAddress)
|
DepositContract, depositContractAddress)
|
||||||
for i in 4200 ..< deposits.len:
|
for i in 4200 ..< deposits.len:
|
||||||
let dp = deposits[i] as DepositData
|
let dp = deposits[i] as DepositData
|
||||||
|
|
||||||
|
@ -656,7 +656,7 @@ when isMainModule:
|
||||||
error "Failed to read an Eth1 private key from standard input"
|
error "Failed to read an Eth1 private key from standard input"
|
||||||
|
|
||||||
if privateKey.len > 0:
|
if privateKey.len > 0:
|
||||||
conf.privateKey = privateKey.string
|
conf.privateKey = privateKey
|
||||||
|
|
||||||
case conf.cmd
|
case conf.cmd
|
||||||
of StartUpCommand.createTestnet:
|
of StartUpCommand.createTestnet:
|
||||||
|
|
|
@ -11,5 +11,4 @@
|
||||||
|
|
||||||
--styleCheck:usages
|
--styleCheck:usages
|
||||||
--styleCheck:error
|
--styleCheck:error
|
||||||
--hint[ConvFromXtoItselfNotNeeded]:off
|
|
||||||
--hint[Processing]:off
|
--hint[Processing]:off
|
||||||
|
|
|
@ -326,8 +326,7 @@ cli do(slots = SLOTS_PER_EPOCH * 7,
|
||||||
contribution: contribution,
|
contribution: contribution,
|
||||||
selection_proof: aggregator.selectionProof)
|
selection_proof: aggregator.selectionProof)
|
||||||
|
|
||||||
validatorPrivKey =
|
validatorPrivKey = MockPrivKeys[aggregator.validatorIdx]
|
||||||
MockPrivKeys[aggregator.validatorIdx.ValidatorIndex]
|
|
||||||
|
|
||||||
signedContributionAndProof = SignedContributionAndProof(
|
signedContributionAndProof = SignedContributionAndProof(
|
||||||
message: contributionAndProof,
|
message: contributionAndProof,
|
||||||
|
|
|
@ -11,5 +11,4 @@
|
||||||
|
|
||||||
--styleCheck:usages
|
--styleCheck:usages
|
||||||
--styleCheck:error
|
--styleCheck:error
|
||||||
--hint[ConvFromXtoItselfNotNeeded]:off
|
|
||||||
--hint[Processing]:off
|
--hint[Processing]:off
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
import
|
import
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
chronicles,
|
chronicles,
|
||||||
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
|
../../../beacon_chain/spec/[presets, state_transition_epoch],
|
||||||
../../../beacon_chain/spec/datatypes/altair,
|
../../../beacon_chain/spec/datatypes/altair,
|
||||||
# Test utilities
|
# Test utilities
|
||||||
../../testutil,
|
../../testutil,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
|
../../../beacon_chain/spec/[presets, state_transition_epoch],
|
||||||
../../../beacon_chain/spec/datatypes/[altair, bellatrix],
|
../../../beacon_chain/spec/datatypes/[altair, bellatrix],
|
||||||
# Test utilities
|
# Test utilities
|
||||||
../../testutil,
|
../../testutil,
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
# 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.
|
||||||
|
|
||||||
|
{.push raises: [].}
|
||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
# Status internals
|
# Status internals
|
||||||
chronicles,
|
chronicles,
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
|
../../../beacon_chain/spec/[presets, state_transition_epoch],
|
||||||
../../../beacon_chain/spec/datatypes/[altair, capella],
|
../../../beacon_chain/spec/datatypes/[altair, capella],
|
||||||
# Test utilities
|
# Test utilities
|
||||||
../../testutil,
|
../../testutil,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import
|
||||||
# Status internals
|
# Status internals
|
||||||
chronicles,
|
chronicles,
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
|
../../../beacon_chain/spec/[presets, state_transition_epoch],
|
||||||
../../../beacon_chain/spec/datatypes/[altair, deneb],
|
../../../beacon_chain/spec/datatypes/[altair, deneb],
|
||||||
# Test utilities
|
# Test utilities
|
||||||
../../testutil,
|
../../testutil,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import
|
||||||
# Status internals
|
# Status internals
|
||||||
chronicles,
|
chronicles,
|
||||||
# Beacon chain internals
|
# Beacon chain internals
|
||||||
../../../beacon_chain/spec/[beaconstate, presets, state_transition_epoch],
|
../../../beacon_chain/spec/[presets, state_transition_epoch],
|
||||||
../../../beacon_chain/spec/datatypes/[altair, electra],
|
../../../beacon_chain/spec/datatypes/[altair, electra],
|
||||||
# Test utilities
|
# Test utilities
|
||||||
../../testutil,
|
../../testutil,
|
||||||
|
@ -146,13 +146,11 @@ runSuite(ParticipationFlagDir, "Participation flag updates"):
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
runSuite(PendingBalanceDepositsDir, "Pending balance deposits"):
|
runSuite(PendingBalanceDepositsDir, "Pending balance deposits"):
|
||||||
process_pending_balance_deposits(cfg, state, cache)
|
process_pending_balance_deposits(cfg, state, cache)
|
||||||
Result[void, cstring].ok()
|
|
||||||
|
|
||||||
# Pending consolidations
|
# Pending consolidations
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
runSuite(PendingConsolidationsDir, "Pending consolidations"):
|
runSuite(PendingConsolidationsDir, "Pending consolidations"):
|
||||||
process_pending_consolidations(cfg, state)
|
process_pending_consolidations(cfg, state)
|
||||||
Result[void, cstring].ok()
|
|
||||||
|
|
||||||
# Sync committee updates
|
# Sync committee updates
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
|
|
|
@ -80,6 +80,132 @@ type
|
||||||
D: BitList[6]
|
D: BitList[6]
|
||||||
E: BitArray[8]
|
E: BitArray[8]
|
||||||
|
|
||||||
|
# https://github.com/wemeetagain/consensus-specs/blob/eip-7495/tests/generators/ssz_generic/ssz_stablecontainer.py
|
||||||
|
SingleFieldTestStableStruct {.sszStableContainer: 4.} = object
|
||||||
|
A: Opt[byte]
|
||||||
|
|
||||||
|
SmallTestStableStruct {.sszStableContainer: 4.} = object
|
||||||
|
A: Opt[uint16]
|
||||||
|
B: Opt[uint16]
|
||||||
|
|
||||||
|
FixedTestStableStruct {.sszStableContainer: 4.} = object
|
||||||
|
A: Opt[uint8]
|
||||||
|
B: Opt[uint64]
|
||||||
|
C: Opt[uint32]
|
||||||
|
|
||||||
|
VarTestStableStruct {.sszStableContainer: 4.} = object
|
||||||
|
A: Opt[uint16]
|
||||||
|
B: Opt[List[uint16, 1024]]
|
||||||
|
C: Opt[uint8]
|
||||||
|
|
||||||
|
ComplexTestStableStruct {.sszStableContainer: 8.} = object
|
||||||
|
A: Opt[uint16]
|
||||||
|
B: Opt[List[uint16, 128]]
|
||||||
|
C: Opt[uint8]
|
||||||
|
D: Opt[List[byte, 256]]
|
||||||
|
E: Opt[VarTestStableStruct]
|
||||||
|
F: Opt[array[4, FixedTestStableStruct]]
|
||||||
|
G: Opt[array[2, VarTestStableStruct]]
|
||||||
|
|
||||||
|
BitsStableStruct {.sszStableContainer: 8.} = object
|
||||||
|
A: Opt[BitList[5]]
|
||||||
|
B: Opt[BitArray[2]]
|
||||||
|
C: Opt[BitArray[1]]
|
||||||
|
D: Opt[BitList[6]]
|
||||||
|
E: Opt[BitArray[8]]
|
||||||
|
|
||||||
|
# https://github.com/wemeetagain/consensus-specs/blob/eip-7495/tests/generators/ssz_generic/ssz_profile.py
|
||||||
|
SingleFieldTestProfile {.sszProfile: SingleFieldTestStableStruct.} = object
|
||||||
|
A: byte
|
||||||
|
|
||||||
|
SmallTestProfile1 {.sszProfile: SmallTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
B: uint16
|
||||||
|
|
||||||
|
SmallTestProfile2 {.sszProfile: SmallTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
|
||||||
|
SmallTestProfile3 {.sszProfile: SmallTestStableStruct.} = object
|
||||||
|
B: uint16
|
||||||
|
|
||||||
|
FixedTestProfile1 {.sszProfile: FixedTestStableStruct.} = object
|
||||||
|
A: uint8
|
||||||
|
B: uint64
|
||||||
|
C: uint32
|
||||||
|
|
||||||
|
FixedTestProfile2 {.sszProfile: FixedTestStableStruct.} = object
|
||||||
|
A: uint8
|
||||||
|
B: uint64
|
||||||
|
|
||||||
|
FixedTestProfile3 {.sszProfile: FixedTestStableStruct.} = object
|
||||||
|
A: uint8
|
||||||
|
C: uint32
|
||||||
|
|
||||||
|
FixedTestProfile4 {.sszProfile: FixedTestStableStruct.} = object
|
||||||
|
C: uint32
|
||||||
|
|
||||||
|
VarTestProfile1 {.sszProfile: VarTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
B: List[uint16, 1024]
|
||||||
|
C: uint8
|
||||||
|
|
||||||
|
VarTestProfile2 {.sszProfile: VarTestStableStruct.} = object
|
||||||
|
B: List[uint16, 1024]
|
||||||
|
C: uint8
|
||||||
|
|
||||||
|
VarTestProfile3 {.sszProfile: VarTestStableStruct.} = object
|
||||||
|
B: List[uint16, 1024]
|
||||||
|
|
||||||
|
ComplexTestProfile1 {.sszProfile: ComplexTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
B: List[uint16, 128]
|
||||||
|
C: uint8
|
||||||
|
D: List[byte, 256]
|
||||||
|
E: VarTestStableStruct
|
||||||
|
F: array[4, FixedTestStableStruct]
|
||||||
|
G: array[2, VarTestStableStruct]
|
||||||
|
|
||||||
|
ComplexTestProfile2 {.sszProfile: ComplexTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
B: List[uint16, 128]
|
||||||
|
C: uint8
|
||||||
|
D: List[byte, 256]
|
||||||
|
E: VarTestStableStruct
|
||||||
|
|
||||||
|
ComplexTestProfile3 {.sszProfile: ComplexTestStableStruct.} = object
|
||||||
|
A: uint16
|
||||||
|
C: uint8
|
||||||
|
E: VarTestStableStruct
|
||||||
|
G: array[2, VarTestStableStruct]
|
||||||
|
|
||||||
|
ComplexTestProfile4 {.sszProfile: ComplexTestStableStruct.} = object
|
||||||
|
B: List[uint16, 128]
|
||||||
|
D: List[byte, 256]
|
||||||
|
F: array[4, FixedTestStableStruct]
|
||||||
|
|
||||||
|
ComplexTestProfile5 {.sszProfile: ComplexTestStableStruct.} = object
|
||||||
|
E: VarTestStableStruct
|
||||||
|
F: array[4, FixedTestStableStruct]
|
||||||
|
G: array[2, VarTestStableStruct]
|
||||||
|
|
||||||
|
BitsProfile1 {.sszProfile: BitsStableStruct.} = object
|
||||||
|
A: BitList[5]
|
||||||
|
B: BitArray[2]
|
||||||
|
C: BitArray[1]
|
||||||
|
D: BitList[6]
|
||||||
|
E: BitArray[8]
|
||||||
|
|
||||||
|
BitsProfile2 {.sszProfile: BitsStableStruct.} = object
|
||||||
|
A: BitList[5]
|
||||||
|
B: BitArray[2]
|
||||||
|
C: BitArray[1]
|
||||||
|
D: BitList[6]
|
||||||
|
|
||||||
|
BitsProfile3 {.sszProfile: BitsStableStruct.} = object
|
||||||
|
A: BitList[5]
|
||||||
|
D: BitList[6]
|
||||||
|
E: BitArray[8]
|
||||||
|
|
||||||
# Type specific checks
|
# Type specific checks
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -285,6 +411,71 @@ proc sszCheck(
|
||||||
of "BitsStruct": checkBasic(BitsStruct, dir, expectedHash)
|
of "BitsStruct": checkBasic(BitsStruct, dir, expectedHash)
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "unknown container in test: " & sszSubType)
|
raise newException(ValueError, "unknown container in test: " & sszSubType)
|
||||||
|
of "profiles":
|
||||||
|
var name: string
|
||||||
|
let wasMatched = scanf(sszSubType, "$+_", name)
|
||||||
|
doAssert wasMatched
|
||||||
|
case name
|
||||||
|
of "BitsProfile1":
|
||||||
|
checkBasic(BitsProfile1, dir, expectedHash)
|
||||||
|
of "BitsProfile2":
|
||||||
|
checkBasic(BitsProfile2, dir, expectedHash)
|
||||||
|
of "BitsProfile3":
|
||||||
|
checkBasic(BitsProfile3, dir, expectedHash)
|
||||||
|
of "ComplexTestProfile1":
|
||||||
|
checkBasic(ComplexTestProfile1, dir, expectedHash)
|
||||||
|
of "ComplexTestProfile2":
|
||||||
|
checkBasic(ComplexTestProfile2, dir, expectedHash)
|
||||||
|
of "ComplexTestProfile3":
|
||||||
|
checkBasic(ComplexTestProfile3, dir, expectedHash)
|
||||||
|
of "ComplexTestProfile4":
|
||||||
|
checkBasic(ComplexTestProfile4, dir, expectedHash)
|
||||||
|
of "ComplexTestProfile5":
|
||||||
|
checkBasic(ComplexTestProfile5, dir, expectedHash)
|
||||||
|
of "FixedTestProfile1":
|
||||||
|
checkBasic(FixedTestProfile1, dir, expectedHash)
|
||||||
|
of "FixedTestProfile2":
|
||||||
|
checkBasic(FixedTestProfile2, dir, expectedHash)
|
||||||
|
of "FixedTestProfile3":
|
||||||
|
checkBasic(FixedTestProfile3, dir, expectedHash)
|
||||||
|
of "FixedTestProfile4":
|
||||||
|
checkBasic(FixedTestProfile4, dir, expectedHash)
|
||||||
|
of "SingleFieldTestProfile":
|
||||||
|
checkBasic(SingleFieldTestProfile, dir, expectedHash)
|
||||||
|
of "SmallTestProfile1":
|
||||||
|
checkBasic(SmallTestProfile1, dir, expectedHash)
|
||||||
|
of "SmallTestProfile2":
|
||||||
|
checkBasic(SmallTestProfile2, dir, expectedHash)
|
||||||
|
of "SmallTestProfile3":
|
||||||
|
checkBasic(SmallTestProfile3, dir, expectedHash)
|
||||||
|
of "VarTestProfile1":
|
||||||
|
checkBasic(VarTestProfile1, dir, expectedHash)
|
||||||
|
of "VarTestProfile2":
|
||||||
|
checkBasic(VarTestProfile2, dir, expectedHash)
|
||||||
|
of "VarTestProfile3":
|
||||||
|
checkBasic(VarTestProfile3, dir, expectedHash)
|
||||||
|
else:
|
||||||
|
raise newException(ValueError, "unknown profile in test: " & sszSubType)
|
||||||
|
of "stablecontainers":
|
||||||
|
var name: string
|
||||||
|
let wasMatched = scanf(sszSubType, "$+_", name)
|
||||||
|
doAssert wasMatched
|
||||||
|
case name
|
||||||
|
of "BitsStableStruct":
|
||||||
|
checkBasic(BitsStableStruct, dir, expectedHash)
|
||||||
|
of "ComplexTestStableStruct":
|
||||||
|
checkBasic(ComplexTestStableStruct, dir, expectedHash)
|
||||||
|
of "FixedTestStableStruct":
|
||||||
|
checkBasic(FixedTestStableStruct, dir, expectedHash)
|
||||||
|
of "SingleFieldTestStableStruct":
|
||||||
|
checkBasic(SingleFieldTestStableStruct, dir, expectedHash)
|
||||||
|
of "SmallTestStableStruct":
|
||||||
|
checkBasic(SmallTestStableStruct, dir, expectedHash)
|
||||||
|
of "VarTestStableStruct":
|
||||||
|
checkBasic(VarTestStableStruct, dir, expectedHash)
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"unknown stablecontainer in test: " & sszSubType)
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "unknown ssz type in test: " & sszType)
|
raise newException(ValueError, "unknown ssz type in test: " & sszType)
|
||||||
|
|
||||||
|
@ -306,26 +497,27 @@ suite "EF - SSZ generic types":
|
||||||
of "containers":
|
of "containers":
|
||||||
skipped = " - skipping BitsStruct"
|
skipped = " - skipping BitsStruct"
|
||||||
|
|
||||||
test &"Testing {sszType:12} inputs - valid" & skipped:
|
test &"Testing {sszType:16} inputs - valid" & skipped:
|
||||||
let path = SSZDir/sszType/"valid"
|
let path = SSZDir/sszType/"valid"
|
||||||
for pathKind, sszSubType in walkDir(
|
for pathKind, sszSubType in walkDir(
|
||||||
path, relative = true, checkDir = true):
|
path, relative = true, checkDir = true):
|
||||||
if pathKind != pcDir: continue
|
if pathKind != pcDir: continue
|
||||||
sszCheck(path, sszType, sszSubType)
|
sszCheck(path, sszType, sszSubType)
|
||||||
|
|
||||||
test &"Testing {sszType:12} inputs - invalid" & skipped:
|
template invalidPath: untyped = SSZDir/sszType/"invalid"
|
||||||
let path = SSZDir/sszType/"invalid"
|
if os_ops.dirExists(invalidPath):
|
||||||
for pathKind, sszSubType in walkDir(
|
test &"Testing {sszType:16} inputs - invalid" & skipped:
|
||||||
path, relative = true, checkDir = true):
|
for pathKind, sszSubType in walkDir(
|
||||||
if pathKind != pcDir: continue
|
invalidPath, relative = true, checkDir = true):
|
||||||
try:
|
if pathKind != pcDir: continue
|
||||||
sszCheck(path, sszType, sszSubType)
|
try:
|
||||||
except SszError, UnconsumedInput:
|
sszCheck(invalidPath, sszType, sszSubType)
|
||||||
discard
|
except SszError, UnconsumedInput:
|
||||||
except TestSizeError as err:
|
discard
|
||||||
echo err.msg
|
except TestSizeError as err:
|
||||||
skip()
|
echo err.msg
|
||||||
except:
|
skip()
|
||||||
checkpoint getStackTrace(getCurrentException())
|
except:
|
||||||
checkpoint getCurrentExceptionMsg()
|
checkpoint getStackTrace(getCurrentException())
|
||||||
check false
|
checkpoint getCurrentExceptionMsg()
|
||||||
|
check false
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2019-2023 Status Research & Development GmbH
|
# Copyright (c) 2019-2024 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -11,5 +11,4 @@
|
||||||
|
|
||||||
--styleCheck:usages
|
--styleCheck:usages
|
||||||
--styleCheck:hint
|
--styleCheck:hint
|
||||||
--hint[ConvFromXtoItselfNotNeeded]:off
|
|
||||||
--hint[Processing]:off
|
--hint[Processing]:off
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
{.used.}
|
||||||
|
|
||||||
import unittest2, results, chronos, stint
|
import unittest2, results, chronos, stint
|
||||||
import ../beacon_chain/validators/beacon_validators,
|
import ../beacon_chain/validators/beacon_validators,
|
||||||
|
|
|
@ -1336,8 +1336,7 @@ suite "State history":
|
||||||
res = process_slots(cfg, dag.headState, 5.Slot, cache, info, flags = {})
|
res = process_slots(cfg, dag.headState, 5.Slot, cache, info, flags = {})
|
||||||
check res.isOk
|
check res.isOk
|
||||||
for i in 0.Slot .. 5.Slot:
|
for i in 0.Slot .. 5.Slot:
|
||||||
check state.getBlockIdAtSlot(i) ==
|
check state.getBlockIdAtSlot(i) == Opt.some BlockSlotId.init(gen, i)
|
||||||
Opt.some BlockSlotId.init(gen, i.Slot)
|
|
||||||
check state.getBlockIdAtSlot(6.Slot).isNone
|
check state.getBlockIdAtSlot(6.Slot).isNone
|
||||||
|
|
||||||
# Fill 5 slots
|
# Fill 5 slots
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
# 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.
|
||||||
|
|
||||||
{.push raises: [].}
|
{.push raises: [].}
|
||||||
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/algorithm,
|
unittest2, chronicles, results, stew/[byteutils, io2],
|
||||||
unittest2, chronicles, stew/[results, byteutils, io2],
|
|
||||||
chronos/asyncproc,
|
chronos/asyncproc,
|
||||||
chronos/unittest2/asynctests,
|
chronos/unittest2/asynctests,
|
||||||
../beacon_chain/spec/[signatures, crypto],
|
../beacon_chain/spec/[signatures, crypto],
|
||||||
|
@ -19,8 +19,6 @@ import
|
||||||
|
|
||||||
from std/os import getEnv, osErrorMsg
|
from std/os import getEnv, osErrorMsg
|
||||||
|
|
||||||
{.used.}
|
|
||||||
|
|
||||||
const
|
const
|
||||||
TestDirectoryName = "test-signing-node"
|
TestDirectoryName = "test-signing-node"
|
||||||
TestDirectoryNameVerifyingWeb3Signer = "test-signing-node-verifying-web3signer"
|
TestDirectoryNameVerifyingWeb3Signer = "test-signing-node-verifying-web3signer"
|
||||||
|
@ -63,8 +61,8 @@ const
|
||||||
|
|
||||||
AgAttestation = "{\"data\":{\"aggregation_bits\":\"0x01\",\"signature\":\"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505\",\"data\":{\"slot\":\"1\",\"index\":\"1\",\"beacon_block_root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\",\"source\":{\"epoch\":\"1\",\"root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\"},\"target\":{\"epoch\":\"1\",\"root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\"}}}}"
|
AgAttestation = "{\"data\":{\"aggregation_bits\":\"0x01\",\"signature\":\"0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505\",\"data\":{\"slot\":\"1\",\"index\":\"1\",\"beacon_block_root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\",\"source\":{\"epoch\":\"1\",\"root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\"},\"target\":{\"epoch\":\"1\",\"root\":\"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2\"}}}}"
|
||||||
|
|
||||||
CapellaBlock = "{\"version\":\"capella\",\"data\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[]},\"bls_to_execution_changes\":[]}}}"
|
CapellaBlock = "{\"message\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[]},\"bls_to_execution_changes\":[]}},\"signature\":\"$2\"}"
|
||||||
DenebBlockContents = "{\"version\":\"deneb\",\"data\":{\"block\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[],\"blob_gas_used\":\"2316131761\",\"excess_blob_gas\":\"231613172261\"},\"bls_to_execution_changes\":[],\"blob_kzg_commitments\":[]}},\"kzg_proofs\":[],\"blobs\":[]}}"
|
DenebBlockContents = "{\"signed_block\":{\"message\":{\"slot\":\"5297696\",\"proposer_index\":\"153094\",\"parent_root\":\"0xe6106533af9be918120ead7440a8006c7f123cc3cb7daf1f11d951864abea014\",\"state_root\":\"0xf86196d34500ca25d1f4e7431d4d52f6f85540bcaf97dd0d2ad9ecdb3eebcdf0\",\"body\":{\"randao_reveal\":\"0xa7efee3d5ddceb60810b23e3b5d39734696418f41dfd13a0851c7be7a72acbdceaa61e1db27513801917d72519d1c1040ccfed829faf06abe06d9964949554bf4369134b66de715ea49eb4fecf3e2b7e646f1764a1993e31e53dbc6557929c12\",\"eth1_data\":{\"deposit_root\":\"0x8ec87d7219a3c873fff3bfe206b4f923d1b471ce4ff9d6d6ecc162ef07825e14\",\"deposit_count\":\"259476\",\"block_hash\":\"0x877b6f8332c7397251ff3f0c5cecec105ff7d4cb78251b47f91fd15a86a565ab\"},\"graffiti\":\"\",\"proposer_slashings\":[],\"attester_slashings\":[],\"attestations\":[],\"deposits\":[],\"voluntary_exits\":[],\"sync_aggregate\":{\"sync_committee_bits\":\"0x733dfda7f5ffde5ade73367fcbf7fffeef7fe43777ffdffab9dbad6f7eed5fff9bfec4affdefbfaddf35bf5efbff9ffff9dfd7dbf97fbfcdfaddfeffbf95f75f\",\"sync_committee_signature\":\"0x81fdf76e797f81b0116a1c1ae5200b613c8041115223cd89e8bd5477aab13de6097a9ebf42b130c59527bbb4c96811b809353a17c717549f82d4bd336068ef0b99b1feebd4d2432a69fa77fac12b78f1fcc9d7b59edbeb381adf10b15bc4a520\"},\"execution_payload\":{\"parent_hash\":\"0x14c2242a8cfbce559e84c391f5f16d10d7719751b8558873012dc88ae5a193e8\",\"fee_recipient\":\"$1\",\"state_root\":\"0xdf8d96b2c292736d39e72e25802c2744d34d3d3c616de5b362425cab01f72fa5\",\"receipts_root\":\"0x4938a2bf640846d213b156a1a853548b369cd02917fa63d8766ab665d7930bac\",\"logs_bloom\":\"0x298610600038408c201080013832408850a00bc8f801920121840030a015310010e2a0e0108628110552062811441c84802f43825c4fc82140b036c58025a28800054c80a44025c052090a0f2c209a0400058040019ea0008e589084078048050880930113a2894082e0112408b088382402a851621042212aa40018a408d07e178c68691486411aa9a2809043b000a04c040000065a030028018540b04b1820271d00821b00c29059095022322c10a530060223240416140190056608200063c82248274ba8f0098e402041cd9f451031481a1010b8220824833520490221071898802d206348449116812280014a10a2d1c210100a30010802490f0a221849\",\"prev_randao\":\"0xc061711e135cd40531ec3ee29d17d3824c0e5f80d07f721e792ab83240aa0ab5\",\"block_number\":\"8737497\",\"gas_limit\":\"30000000\",\"gas_used\":\"16367052\",\"timestamp\":\"1680080352\",\"extra_data\":\"0xd883010b05846765746888676f312e32302e32856c696e7578\",\"base_fee_per_gas\":\"231613172261\",\"block_hash\":\"0x5aa9fd22a9238925adb2b038fd6eafc77adabf554051db5bc16ae5168a52eff6\",\"transactions\":[],\"withdrawals\":[],\"blob_gas_used\":\"2316131761\",\"excess_blob_gas\":\"231613172261\"},\"bls_to_execution_changes\":[],\"blob_kzg_commitments\":[]}},\"signature\":\"$2\"},\"kzg_proofs\":[],\"blobs\":[]}"
|
||||||
|
|
||||||
SigningNodeAddress = "127.0.0.1"
|
SigningNodeAddress = "127.0.0.1"
|
||||||
defaultSigningNodePort = 35333
|
defaultSigningNodePort = 35333
|
||||||
|
@ -84,43 +82,42 @@ func getNodePort(basePort: int, rt: RemoteSignerType): int =
|
||||||
of RemoteSignerType.VerifyingWeb3Signer:
|
of RemoteSignerType.VerifyingWeb3Signer:
|
||||||
basePort + 1
|
basePort + 1
|
||||||
|
|
||||||
func init(T: type ForkedBeaconBlock, contents: ProduceBlockResponseV2): T =
|
func init(
|
||||||
|
T: type ForkedBeaconBlock, contents: RestPublishedSignedBlockContents): T =
|
||||||
case contents.kind
|
case contents.kind
|
||||||
of ConsensusFork.Phase0 .. ConsensusFork.Bellatrix:
|
of ConsensusFork.Phase0 .. ConsensusFork.Bellatrix:
|
||||||
raiseAssert "Unsupported fork"
|
raiseAssert "Unsupported fork"
|
||||||
of ConsensusFork.Capella:
|
of ConsensusFork.Capella:
|
||||||
return ForkedBeaconBlock.init(contents.capellaData)
|
return ForkedBeaconBlock.init(contents.capellaData.message)
|
||||||
of ConsensusFork.Deneb:
|
of ConsensusFork.Deneb:
|
||||||
return ForkedBeaconBlock.init(contents.denebData.`block`)
|
return ForkedBeaconBlock.init(contents.denebData.signed_block.message)
|
||||||
of ConsensusFork.Electra:
|
of ConsensusFork.Electra:
|
||||||
debugComment "probably like the deneb case"
|
return ForkedBeaconBlock.init(contents.electraData.signed_block.message)
|
||||||
return default(T)
|
|
||||||
|
|
||||||
proc getBlock(
|
proc getBlock(
|
||||||
fork: ConsensusFork,
|
fork: ConsensusFork,
|
||||||
feeRecipient = SigningExpectedFeeRecipient
|
feeRecipient = SigningExpectedFeeRecipient
|
||||||
): ForkedBeaconBlock {.raises: [ResultError[cstring]].} =
|
): ForkedBeaconBlock {.raises: [ResultError[cstring]].} =
|
||||||
let
|
let blckData =
|
||||||
blckData =
|
try:
|
||||||
try:
|
case fork
|
||||||
case fork
|
of ConsensusFork.Phase0 .. ConsensusFork.Bellatrix:
|
||||||
of ConsensusFork.Phase0 .. ConsensusFork.Bellatrix: raiseAssert "Unsupported fork"
|
raiseAssert "Unsupported fork"
|
||||||
of ConsensusFork.Capella: CapellaBlock % [feeRecipient]
|
of ConsensusFork.Capella: CapellaBlock % [feeRecipient, SomeSignature]
|
||||||
of ConsensusFork.Deneb: DenebBlockContents % [feeRecipient]
|
of ConsensusFork.Deneb:
|
||||||
of ConsensusFork.Electra:
|
DenebBlockContents % [feeRecipient, SomeSignature]
|
||||||
debugComment "electra test signing node getblock"
|
of ConsensusFork.Electra:
|
||||||
raiseAssert "electra unsupported"
|
debugComment "electra test signing node getblock"
|
||||||
except ValueError:
|
raiseAssert "electra unsupported"
|
||||||
# https://github.com/nim-lang/Nim/pull/23356
|
except ValueError:
|
||||||
raiseAssert "Arguments match the format string"
|
# https://github.com/nim-lang/Nim/pull/23356
|
||||||
contentType = ContentTypeData(
|
raiseAssert "Arguments match the format string"
|
||||||
mediaType: MediaType.init("application/json"))
|
|
||||||
|
|
||||||
let b = decodeBytes(ProduceBlockResponseV2,
|
try:
|
||||||
blckData.toOpenArrayByte(0, len(blckData) - 1),
|
ForkedBeaconBlock.init(RestJson.decode(
|
||||||
Opt.some(contentType),
|
blckData, RestPublishedSignedBlockContents))
|
||||||
$fork).tryGet()
|
except SerializationError:
|
||||||
ForkedBeaconBlock.init(b)
|
raiseAssert "malformed block contents"
|
||||||
|
|
||||||
func init(t: typedesc[Web3SignerForkedBeaconBlock],
|
func init(t: typedesc[Web3SignerForkedBeaconBlock],
|
||||||
forked: ForkedBeaconBlock): Web3SignerForkedBeaconBlock =
|
forked: ForkedBeaconBlock): Web3SignerForkedBeaconBlock =
|
||||||
|
@ -371,6 +368,8 @@ let
|
||||||
fatal "Invalid base port arg", basePort = basePortStr, exc = exc.msg
|
fatal "Invalid base port arg", basePort = basePortStr, exc = exc.msg
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
|
from std/algorithm import sorted
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let res = createTestDir(RemoteSignerType.Web3Signer)
|
let res = createTestDir(RemoteSignerType.Web3Signer)
|
||||||
doAssert(res.isOk())
|
doAssert(res.isOk())
|
||||||
|
|
|
@ -103,7 +103,7 @@ suite "Sync committee pool":
|
||||||
privkey2 = MockPrivKeys[1.ValidatorIndex]
|
privkey2 = MockPrivKeys[1.ValidatorIndex]
|
||||||
|
|
||||||
bid1 = BlockId(
|
bid1 = BlockId(
|
||||||
slot: Slot(cfg.BELLATRIX_FORK_EPOCH.start_slot - 1),
|
slot: cfg.BELLATRIX_FORK_EPOCH.start_slot - 1,
|
||||||
root: eth2digest(@[1.byte]))
|
root: eth2digest(@[1.byte]))
|
||||||
|
|
||||||
sig1 = get_sync_committee_message_signature(
|
sig1 = get_sync_committee_message_signature(
|
||||||
|
|
|
@ -369,7 +369,7 @@ suite "SyncManager test suite":
|
||||||
aq = newAsyncQueue[BlockEntry]()
|
aq = newAsyncQueue[BlockEntry]()
|
||||||
chunkSize = 3'u64
|
chunkSize = 3'u64
|
||||||
numberOfChunks = 3'u64
|
numberOfChunks = 3'u64
|
||||||
finishSlot = Slot(startSlot + numberOfChunks * chunkSize - 1'u64)
|
finishSlot = startSlot + numberOfChunks * chunkSize - 1'u64
|
||||||
queueSize = 1
|
queueSize = 1
|
||||||
|
|
||||||
var counter =
|
var counter =
|
||||||
|
@ -734,7 +734,7 @@ suite "SyncManager test suite":
|
||||||
startSlot = Slot(0)
|
startSlot = Slot(0)
|
||||||
chunkSize = SLOTS_PER_EPOCH
|
chunkSize = SLOTS_PER_EPOCH
|
||||||
numberOfChunks = 4'u64
|
numberOfChunks = 4'u64
|
||||||
finishSlot = Slot(startSlot + numberOfChunks * chunkSize - 1'u64)
|
finishSlot = startSlot + numberOfChunks * chunkSize - 1'u64
|
||||||
queueSize = 1
|
queueSize = 1
|
||||||
|
|
||||||
var counter = int(startSlot)
|
var counter = int(startSlot)
|
||||||
|
@ -855,7 +855,7 @@ suite "SyncManager test suite":
|
||||||
startSlot = Slot(0)
|
startSlot = Slot(0)
|
||||||
chunkSize = SLOTS_PER_EPOCH
|
chunkSize = SLOTS_PER_EPOCH
|
||||||
numberOfChunks = 1'u64
|
numberOfChunks = 1'u64
|
||||||
finishSlot = Slot(startSlot + numberOfChunks * chunkSize - 1'u64)
|
finishSlot = startSlot + numberOfChunks * chunkSize - 1'u64
|
||||||
queueSize = 1
|
queueSize = 1
|
||||||
|
|
||||||
var counter = int(startSlot)
|
var counter = int(startSlot)
|
||||||
|
@ -902,7 +902,7 @@ suite "SyncManager test suite":
|
||||||
startSlot = Slot(0)
|
startSlot = Slot(0)
|
||||||
chunkSize = SLOTS_PER_EPOCH
|
chunkSize = SLOTS_PER_EPOCH
|
||||||
numberOfChunks = 4'u64
|
numberOfChunks = 4'u64
|
||||||
finishSlot = Slot(startSlot + numberOfChunks * chunkSize - 1'u64)
|
finishSlot = startSlot + numberOfChunks * chunkSize - 1'u64
|
||||||
queueSize = 1
|
queueSize = 1
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5de55bab8c4e161d3ae1c39f284c26262b5ebf82
|
Subproject commit 695d1c9dbec4fa0f746a15df259a19fed49e075e
|
Loading…
Reference in New Issue