nimbus-eth2/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim
Jacek Sieka f70ff38b53
enable styleCheck:usages (#3573)
Some upstream repos still need fixes, but this gets us close enough that
style hints can be enabled by default.

In general, "canonical" spellings are preferred even if they violate
nep-1 - this applies in particular to spec-related stuff like
`genesis_validators_root` which appears throughout the codebase.
2022-04-08 16:22:49 +00:00

2280 lines
80 KiB
Nim

# Copyright (c) 2018-2022 Status Research & Development GmbH
# Licensed and distributed under either of
# * 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).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import std/typetraits
import stew/[assign2, results, base10, byteutils], presto/common,
libp2p/peerid, serialization, json_serialization,
json_serialization/std/[options, net, sets]
import ".."/[eth2_ssz_serialization, forks, keystore],
".."/datatypes/[phase0, altair, bellatrix],
".."/../validators/slashing_protection_common,
"."/[rest_types, rest_keymanager_types]
import nimcrypto/utils as ncrutils
export
eth2_ssz_serialization, results, peerid, common, serialization,
json_serialization, options, net, sets, rest_types, slashing_protection_common
from web3/ethtypes import BlockHash
export ethtypes.BlockHash
Json.createFlavor RestJson
const
DecimalSet = {'0' .. '9'}
# Base10 (decimal) set of chars
ValidatorKeySize = RawPubKeySize * 2
# Size of `ValidatorPubKey` hexadecimal value (without 0x)
ValidatorSigSize = RawSigSize * 2
# Size of `ValidatorSig` hexadecimal value (without 0x)
RootHashSize = sizeof(Eth2Digest) * 2
# Size of `xxx_root` hexadecimal value (without 0x)
Phase0Version =
[byte('p'), byte('h'), byte('a'), byte('s'), byte('e'), byte('0')]
AltairVersion =
[byte('a'), byte('l'), byte('t'), byte('a'), byte('i'), byte('r')]
type
RestGenericError* = object
code*: uint64
message*: string
stacktraces*: Option[seq[string]]
RestAttestationError* = object
code*: uint64
message*: string
failures*: seq[RestFailureItem]
EncodeTypes* =
AttesterSlashing |
ProposerSlashing |
phase0.SignedBeaconBlock |
altair.SignedBeaconBlock |
bellatrix.SignedBeaconBlock |
SignedVoluntaryExit |
Web3SignerRequest |
KeystoresAndSlashingProtection |
DeleteKeystoresBody |
ImportRemoteKeystoresBody
EncodeArrays* =
seq[ValidatorIndex] |
seq[Attestation] |
seq[SignedAggregateAndProof] |
seq[RestCommitteeSubscription] |
seq[RestSyncCommitteeSubscription] |
seq[RestSyncCommitteeMessage] |
seq[RestSignedContributionAndProof] |
seq[RemoteKeystoreInfo]
DecodeTypes* =
DataEnclosedObject |
DataMetaEnclosedObject |
DataRootEnclosedObject |
GetBlockV2Response |
GetKeystoresResponse |
GetRemoteKeystoresResponse |
GetStateV2Response |
GetStateForkResponse |
ProduceBlockResponseV2 |
RestAttestationError |
RestValidator |
RestGenericError |
Web3SignerErrorResponse |
Web3SignerKeysResponse |
Web3SignerSignatureResponse |
Web3SignerStatusResponse
# These types may be extended with additional fields in the future.
# Locally unknown fields are silently ignored when decoding them.
ExtensibleDecodeTypes* =
GetSpecResponse |
GetSpecVCResponse
SszDecodeTypes* =
GetPhase0StateSszResponse |
GetPhase0BlockSszResponse
{.push raises: [Defect].}
proc prepareJsonResponse*(t: typedesc[RestApiResponse], d: auto): seq[byte] =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("data", d)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
res
proc prepareJsonStringResponse*(t: typedesc[RestApiResponse], d: auto): string =
let res =
block:
var default: string
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.writeValue(d)
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
res
proc jsonResponseWRoot*(t: typedesc[RestApiResponse], data: auto,
dependent_root: Eth2Digest): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("dependent_root", dependent_root)
writer.writeField("data", data)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/json")
proc jsonResponse*(t: typedesc[RestApiResponse], data: auto): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("data", data)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/json")
proc jsonResponsePlain*(t: typedesc[RestApiResponse],
data: auto): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.writeValue(data)
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/json")
proc jsonResponseWMeta*(t: typedesc[RestApiResponse],
data: auto, meta: auto): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("data", data)
writer.writeField("meta", meta)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/json")
proc jsonMsgResponse*(t: typedesc[RestApiResponse],
msg: string = ""): RestApiResponse =
let data =
block:
var default: seq[byte]
try:
var defstrings: seq[string]
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("code", "200")
writer.writeField("message", msg)
writer.writeField("stacktraces", defstrings)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(data, Http200, "application/json")
proc jsonError*(t: typedesc[RestApiResponse], status: HttpCode = Http200,
msg: string = ""): RestApiResponse =
let data =
block:
var default: string
try:
var defstrings: seq[string]
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("code", Base10.toString(uint64(status.toInt())))
writer.writeField("message", msg)
writer.writeField("stacktraces", defstrings)
writer.endRecord()
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
RestApiResponse.error(status, data, "application/json")
proc jsonError*(t: typedesc[RestApiResponse], status: HttpCode = Http200,
msg: string = "", stacktrace: string): RestApiResponse =
let data =
block:
var default: string
try:
var defstrings: seq[string]
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("code", Base10.toString(uint64(status.toInt())))
writer.writeField("message", msg)
if len(stacktrace) > 0:
writer.writeField("stacktraces", [stacktrace])
else:
writer.writeField("stacktraces", defstrings)
writer.endRecord()
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
RestApiResponse.error(status, data, "application/json")
proc jsonError*(t: typedesc[RestApiResponse], status: HttpCode = Http200,
msg: string = "",
stacktraces: openArray[string]): RestApiResponse =
let data =
block:
var default: string
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("code", Base10.toString(uint64(status.toInt())))
writer.writeField("message", msg)
writer.writeField("stacktraces", stacktraces)
writer.endRecord()
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
RestApiResponse.error(status, data, "application/json")
proc jsonErrorList*(t: typedesc[RestApiResponse],
status: HttpCode = Http200,
msg: string = "", failures: auto): RestApiResponse =
let data =
block:
var default: string
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.beginRecord()
writer.writeField("code", Base10.toString(uint64(status.toInt())))
writer.writeField("message", msg)
writer.writeField("failures", failures)
writer.endRecord()
stream.getOutput(string)
except SerializationError:
default
except IOError:
default
RestApiResponse.error(status, data, "application/json")
proc sszResponse*(t: typedesc[RestApiResponse], data: auto): RestApiResponse =
let res =
block:
var default: seq[byte]
try:
var stream = memoryOutput()
var writer = SszWriter.init(stream)
writer.writeValue(data)
stream.getOutput(seq[byte])
except SerializationError:
default
except IOError:
default
RestApiResponse.response(res, Http200, "application/octet-stream")
template hexOriginal(data: openArray[byte]): string =
to0xHex(data)
proc decodeJsonString*[T](t: typedesc[T],
data: JsonString,
requireAllFields = true): Result[T, cstring] =
try:
ok(RestJson.decode(string(data), T, requireAllFields = requireAllFields))
except SerializationError:
err("Unable to deserialize data")
## uint64
proc writeValue*(w: var JsonWriter[RestJson], value: uint64) {.
raises: [IOError, Defect].} =
writeValue(w, Base10.toString(value))
proc readValue*(reader: var JsonReader[RestJson], value: var uint64) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
value = res.get()
else:
reader.raiseUnexpectedValue($res.error() & ": " & svalue)
proc writeValue*(w: var JsonWriter[RestJson], value: uint8) {.
raises: [IOError, Defect].} =
writeValue(w, Base10.toString(value))
proc readValue*(reader: var JsonReader[RestJson], value: var uint8) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint8, svalue)
if res.isOk():
value = res.get()
else:
reader.raiseUnexpectedValue($res.error() & ": " & svalue)
proc writeValue*(w: var JsonWriter[RestJson], value: JustificationBits) {.
raises: [IOError, Defect].} =
w.writeValue hexOriginal([uint8(value)])
proc readValue*(reader: var JsonReader[RestJson], value: var JustificationBits) {.
raises: [IOError, SerializationError, Defect].} =
let hex = reader.readValue(string)
try:
value = JustificationBits(hexToByteArray(hex, 1)[0])
except ValueError:
raiseUnexpectedValue(reader,
"The `justification_bits` value must be a hex string")
## UInt256
proc writeValue*(w: var JsonWriter[RestJson], value: UInt256) {.
raises: [IOError, Defect].} =
writeValue(w, toString(value))
proc readValue*(reader: var JsonReader[RestJson], value: var UInt256) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
try:
value = parse(svalue, UInt256, 10)
except ValueError:
raiseUnexpectedValue(reader,
"UInt256 value should be a valid decimal string")
## Slot
proc writeValue*(writer: var JsonWriter[RestJson], value: Slot) {.
raises: [IOError, Defect].} =
writeValue(writer, Base10.toString(uint64(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var Slot) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
value = Slot(res.get())
else:
reader.raiseUnexpectedValue($res.error())
## Epoch
proc writeValue*(writer: var JsonWriter[RestJson], value: Epoch) {.
raises: [IOError, Defect].} =
writeValue(writer, Base10.toString(uint64(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var Epoch) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
value = Epoch(res.get())
else:
reader.raiseUnexpectedValue($res.error())
## ValidatorIndex
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorIndex)
{.raises: [IOError, Defect].} =
writeValue(writer, Base10.toString(uint64(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorIndex)
{.raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
let v = res.get()
if v < VALIDATOR_REGISTRY_LIMIT:
value = ValidatorIndex(v)
else:
reader.raiseUnexpectedValue(
"Validator index is bigger then VALIDATOR_REGISTRY_LIMIT")
else:
reader.raiseUnexpectedValue($res.error())
proc writeValue*(writer: var JsonWriter[RestJson], value: IndexInSyncCommittee)
{.raises: [IOError, Defect].} =
writeValue(writer, Base10.toString(distinctBase(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var IndexInSyncCommittee)
{.raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
let v = res.get()
if v < SYNC_COMMITTEE_SIZE:
value = IndexInSyncCommittee(v)
else:
reader.raiseUnexpectedValue(
"Index in committee is bigger than SYNC_COMMITTEE_SIZE")
else:
reader.raiseUnexpectedValue($res.error())
## RestValidatorIndex
proc writeValue*(writer: var JsonWriter[RestJson],
value: RestValidatorIndex) {.
raises: [IOError, Defect].} =
writeValue(writer, Base10.toString(uint64(value)))
proc readValue*(reader: var JsonReader[RestJson],
value: var RestValidatorIndex) {.
raises: [IOError, SerializationError, Defect].} =
let svalue = reader.readValue(string)
let res = Base10.decode(uint64, svalue)
if res.isOk():
let v = res.get()
value = RestValidatorIndex(v)
else:
reader.raiseUnexpectedValue($res.error())
## CommitteeIndex
proc writeValue*(writer: var JsonWriter[RestJson], value: CommitteeIndex) {.
raises: [IOError, Defect].} =
writeValue(writer, value.asUInt64)
proc readValue*(reader: var JsonReader[RestJson], value: var CommitteeIndex) {.
raises: [IOError, SerializationError, Defect].} =
var v: uint64
reader.readValue(v)
let res = CommitteeIndex.init(v)
if res.isOk():
value = res.get()
else:
reader.raiseUnexpectedValue($res.error())
## ValidatorSig
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorSig) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(toRaw(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorSig) {.
raises: [IOError, SerializationError, Defect].} =
let hexValue = reader.readValue(string)
let res = ValidatorSig.fromHex(hexValue)
if res.isOk():
value = res.get()
else:
reader.raiseUnexpectedValue($res.error())
## TrustedSig
proc writeValue*(writer: var JsonWriter[RestJson], value: TrustedSig) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(toRaw(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var TrustedSig) {.
raises: [IOError, SerializationError, Defect].} =
let hexValue = reader.readValue(string)
let res = ValidatorSig.fromHex(hexValue)
if res.isOk():
value = cast[TrustedSig](res.get())
else:
reader.raiseUnexpectedValue($res.error())
## ValidatorPubKey
proc writeValue*(writer: var JsonWriter[RestJson], value: ValidatorPubKey) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(toRaw(value)))
proc readValue*(reader: var JsonReader[RestJson], value: var ValidatorPubKey) {.
raises: [IOError, SerializationError, Defect].} =
let hexValue = reader.readValue(string)
let res = ValidatorPubKey.fromHex(hexValue)
if res.isOk():
value = res.get()
else:
reader.raiseUnexpectedValue($res.error())
## BitSeq
proc readValue*(reader: var JsonReader[RestJson], value: var BitSeq) {.
raises: [IOError, SerializationError, Defect].} =
try:
value = BitSeq hexToSeqByte(reader.readValue(string))
except ValueError:
raiseUnexpectedValue(reader, "A BitSeq value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: BitSeq) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(value.bytes()))
## BitList
proc readValue*(reader: var JsonReader[RestJson], value: var BitList) {.
raises: [IOError, SerializationError, Defect].} =
type T = type(value)
value = T readValue(reader, BitSeq)
proc writeValue*(writer: var JsonWriter[RestJson], value: BitList) {.
raises: [IOError, Defect].} =
writeValue(writer, BitSeq value)
## BitArray
proc readValue*(reader: var JsonReader[RestJson], value: var BitArray) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(readValue(reader, string), value.bytes)
except ValueError:
raiseUnexpectedValue(reader,
"A BitArray value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: BitArray) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(value.bytes))
## BlockHash
proc readValue*(reader: var JsonReader[RestJson], value: var BlockHash) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), distinctBase(value))
except ValueError:
raiseUnexpectedValue(reader,
"BlockHash value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: BlockHash) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
## Eth2Digest
proc readValue*(reader: var JsonReader[RestJson], value: var Eth2Digest) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), value.data)
except ValueError:
raiseUnexpectedValue(reader,
"Eth2Digest value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: Eth2Digest) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(value.data))
## BloomLogs
proc readValue*(reader: var JsonReader[RestJson], value: var BloomLogs) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), value.data)
except ValueError:
raiseUnexpectedValue(reader,
"BloomLogs value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: BloomLogs) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(value.data))
## HashArray
proc readValue*(reader: var JsonReader[RestJson], value: var HashArray) {.
raises: [IOError, SerializationError, Defect].} =
readValue(reader, value.data)
proc writeValue*(writer: var JsonWriter[RestJson], value: HashArray) {.
raises: [IOError, Defect].} =
writeValue(writer, value.data)
## HashList
proc readValue*(reader: var JsonReader[RestJson], value: var HashList) {.
raises: [IOError, SerializationError, Defect].} =
readValue(reader, value.data)
value.resetCache()
proc writeValue*(writer: var JsonWriter[RestJson], value: HashList) {.
raises: [IOError, Defect].} =
writeValue(writer, value.data)
## Eth1Address
proc readValue*(reader: var JsonReader[RestJson], value: var Eth1Address) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), distinctBase(value))
except ValueError:
raiseUnexpectedValue(reader,
"Eth1Address value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: Eth1Address) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
proc writeValue*(writer: var JsonWriter[RestJson], value: GraffitiBytes)
{.raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
proc readValue*(reader: var JsonReader[RestJson], T: type GraffitiBytes): T
{.raises: [IOError, SerializationError, Defect].} =
try:
init(GraffitiBytes, reader.readValue(string))
except ValueError as err:
reader.raiseUnexpectedValue err.msg
## Version
proc readValue*(
reader: var JsonReader[RestJson],
value: var (Version | ForkDigest | DomainType | GraffitiBytes)) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), distinctBase(value))
except ValueError:
raiseUnexpectedValue(
reader, "Expected a valid hex string with " & $value.len() & " bytes")
## ForkedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
value: var ForkedBeaconBlock) {.
raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconBlockFork]
data: Option[JsonString]
for fieldName in readObjectFields(reader):
case fieldName
of "version":
if version.isSome():
reader.raiseUnexpectedField("Multiple version fields found",
"ForkedBeaconBlock")
let vres = reader.readValue(string)
case vres
of "phase0":
version = some(BeaconBlockFork.Phase0)
of "altair":
version = some(BeaconBlockFork.Altair)
of "bellatrix":
version = some(BeaconBlockFork.Bellatrix)
else:
reader.raiseUnexpectedValue("Incorrect version field value")
of "data":
if data.isSome():
reader.raiseUnexpectedField("Multiple data fields found",
"ForkedBeaconBlock")
data = some(reader.readValue(JsonString))
else:
reader.raiseUnexpectedField(fieldName, "ForkedBeaconBlock")
if version.isNone():
reader.raiseUnexpectedValue("Field version is missing")
if data.isNone():
reader.raiseUnexpectedValue("Field data is missing")
case version.get():
of BeaconBlockFork.Phase0:
let res =
try:
some(RestJson.decode(string(data.get()), phase0.BeaconBlock,
requireAllFields = true))
except SerializationError:
none[phase0.BeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect phase0 block format")
value = ForkedBeaconBlock.init(res.get())
of BeaconBlockFork.Altair:
let res =
try:
some(RestJson.decode(string(data.get()), altair.BeaconBlock,
requireAllFields = true))
except SerializationError:
none[altair.BeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect altair block format")
value = ForkedBeaconBlock.init(res.get())
of BeaconBlockFork.Bellatrix:
let res =
try:
some(RestJson.decode(string(data.get()), bellatrix.BeaconBlock,
requireAllFields = true))
except SerializationError:
none[bellatrix.BeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect bellatrix block format")
value = ForkedBeaconBlock.init(res.get())
proc writeValue*(writer: var JsonWriter[RestJson], value: ForkedBeaconBlock) {.
raises: [IOError, Defect].} =
writer.beginRecord()
case value.kind
of BeaconBlockFork.Phase0:
writer.writeField("version", "phase0")
writer.writeField("data", value.phase0Data)
of BeaconBlockFork.Altair:
writer.writeField("version", "altair")
writer.writeField("data", value.altairData)
of BeaconBlockFork.Bellatrix:
writer.writeField("version", "bellatrix")
writer.writeField("data", value.bellatrixData)
writer.endRecord()
## RestPublishedBeaconBlockBody
proc readValue*(reader: var JsonReader[RestJson],
value: var RestPublishedBeaconBlockBody) {.
raises: [IOError, SerializationError, Defect].} =
var
randao_reveal: Option[ValidatorSig]
eth1_data: Option[Eth1Data]
graffiti: Option[GraffitiBytes]
proposer_slashings: Option[
List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]]
attester_slashings: Option[
List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]]
attestations: Option[List[Attestation, Limit MAX_ATTESTATIONS]]
deposits: Option[List[Deposit, Limit MAX_DEPOSITS]]
voluntary_exits: Option[
List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]]
sync_aggregate: Option[SyncAggregate]
execution_payload: Option[ExecutionPayload]
for fieldName in readObjectFields(reader):
case fieldName
of "randao_reveal":
if randao_reveal.isSome():
reader.raiseUnexpectedField("Multiple `randao_reveal` fields found",
"RestPublishedBeaconBlockBody")
randao_reveal = some(reader.readValue(ValidatorSig))
of "eth1_data":
if eth1_data.isSome():
reader.raiseUnexpectedField("Multiple `eth1_data` fields found",
"RestPublishedBeaconBlockBody")
eth1_data = some(reader.readValue(Eth1Data))
of "graffiti":
if graffiti.isSome():
reader.raiseUnexpectedField("Multiple `graffiti` fields found",
"RestPublishedBeaconBlockBody")
graffiti = some(reader.readValue(GraffitiBytes))
of "proposer_slashings":
if proposer_slashings.isSome():
reader.raiseUnexpectedField(
"Multiple `proposer_slashings` fields found",
"RestPublishedBeaconBlockBody")
proposer_slashings = some(
reader.readValue(List[ProposerSlashing, Limit MAX_PROPOSER_SLASHINGS]))
of "attester_slashings":
if attester_slashings.isSome():
reader.raiseUnexpectedField(
"Multiple `attester_slashings` fields found",
"RestPublishedBeaconBlockBody")
attester_slashings = some(
reader.readValue(List[AttesterSlashing, Limit MAX_ATTESTER_SLASHINGS]))
of "attestations":
if attestations.isSome():
reader.raiseUnexpectedField("Multiple `attestations` fields found",
"RestPublishedBeaconBlockBody")
attestations = some(
reader.readValue(List[Attestation, Limit MAX_ATTESTATIONS]))
of "deposits":
if deposits.isSome():
reader.raiseUnexpectedField("Multiple `deposits` fields found",
"RestPublishedBeaconBlockBody")
deposits = some(reader.readValue(List[Deposit, Limit MAX_DEPOSITS]))
of "voluntary_exits":
if voluntary_exits.isSome():
reader.raiseUnexpectedField("Multiple `voluntary_exits` fields found",
"RestPublishedBeaconBlockBody")
voluntary_exits = some(
reader.readValue(List[SignedVoluntaryExit, Limit MAX_VOLUNTARY_EXITS]))
of "sync_aggregate":
if sync_aggregate.isSome():
reader.raiseUnexpectedField("Multiple `sync_aggregate` fields found",
"RestPublishedBeaconBlockBody")
sync_aggregate = some(reader.readValue(SyncAggregate))
of "execution_payload":
if execution_payload.isSome():
reader.raiseUnexpectedField("Multiple `execution_payload` fields found",
"RestPublishedBeaconBlockBody")
execution_payload = some(reader.readValue(ExecutionPayload))
else:
# Ignore unknown fields
discard
if randao_reveal.isNone():
reader.raiseUnexpectedValue("Field `randao_reveal` is missing")
if eth1_data.isNone():
reader.raiseUnexpectedValue("Field `eth1_data` is missing")
if graffiti.isNone():
reader.raiseUnexpectedValue("Field `graffiti` is missing")
if proposer_slashings.isNone():
reader.raiseUnexpectedValue("Field `proposer_slashings` is missing")
if attester_slashings.isNone():
reader.raiseUnexpectedValue("Field `attester_slashings` is missing")
if attestations.isNone():
reader.raiseUnexpectedValue("Field `attestations` is missing")
if deposits.isNone():
reader.raiseUnexpectedValue("Field `deposits` is missing")
if voluntary_exits.isNone():
reader.raiseUnexpectedValue("Field `voluntary_exits` is missing")
let bodyKind =
if execution_payload.isSome() and sync_aggregate.isSome():
BeaconBlockFork.Bellatrix
elif execution_payload.isNone() and sync_aggregate.isSome():
BeaconBlockFork.Altair
else:
BeaconBlockFork.Phase0
case bodyKind
of BeaconBlockFork.Phase0:
value = RestPublishedBeaconBlockBody(
kind: BeaconBlockFork.Phase0,
phase0Body: phase0.BeaconBlockBody(
randao_reveal: randao_reveal.get(),
eth1_data: eth1_data.get(),
graffiti: graffiti.get(),
proposer_slashings: proposer_slashings.get(),
attester_slashings: attester_slashings.get(),
attestations: attestations.get(),
deposits: deposits.get(),
voluntary_exits: voluntary_exits.get()
)
)
of BeaconBlockFork.Altair:
value = RestPublishedBeaconBlockBody(
kind: BeaconBlockFork.Altair,
altairBody: altair.BeaconBlockBody(
randao_reveal: randao_reveal.get(),
eth1_data: eth1_data.get(),
graffiti: graffiti.get(),
proposer_slashings: proposer_slashings.get(),
attester_slashings: attester_slashings.get(),
attestations: attestations.get(),
deposits: deposits.get(),
voluntary_exits: voluntary_exits.get(),
sync_aggregate: sync_aggregate.get()
)
)
of BeaconBlockFork.Bellatrix:
value = RestPublishedBeaconBlockBody(
kind: BeaconBlockFork.Bellatrix,
bellatrixBody: bellatrix.BeaconBlockBody(
randao_reveal: randao_reveal.get(),
eth1_data: eth1_data.get(),
graffiti: graffiti.get(),
proposer_slashings: proposer_slashings.get(),
attester_slashings: attester_slashings.get(),
attestations: attestations.get(),
deposits: deposits.get(),
voluntary_exits: voluntary_exits.get(),
sync_aggregate: sync_aggregate.get(),
execution_payload: execution_payload.get()
)
)
## RestPublishedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
value: var RestPublishedBeaconBlock) {.
raises: [IOError, SerializationError, Defect].} =
var
slot: Option[Slot]
proposer_index: Option[uint64]
parent_root: Option[Eth2Digest]
state_root: Option[Eth2Digest]
blockBody: Option[RestPublishedBeaconBlockBody]
for fieldName in readObjectFields(reader):
case fieldName
of "slot":
if slot.isSome():
reader.raiseUnexpectedField("Multiple `slot` fields found",
"RestPublishedBeaconBlock")
slot = some(reader.readValue(Slot))
of "proposer_index":
if proposer_index.isSome():
reader.raiseUnexpectedField("Multiple `proposer_index` fields found",
"RestPublishedBeaconBlock")
proposer_index = some(reader.readValue(uint64))
of "parent_root":
if parent_root.isSome():
reader.raiseUnexpectedField("Multiple `parent_root` fields found",
"RestPublishedBeaconBlock")
parent_root = some(reader.readValue(Eth2Digest))
of "state_root":
if state_root.isSome():
reader.raiseUnexpectedField("Multiple `state_root` fields found",
"RestPublishedBeaconBlock")
state_root = some(reader.readValue(Eth2Digest))
of "body":
if blockBody.isSome():
reader.raiseUnexpectedField("Multiple `body` fields found",
"RestPublishedBeaconBlock")
blockBody = some(reader.readValue(RestPublishedBeaconBlockBody))
else:
# Ignore unknown fields
discard
if slot.isNone():
reader.raiseUnexpectedValue("Field `slot` is missing")
if proposer_index.isNone():
reader.raiseUnexpectedValue("Field `proposer_index` is missing")
if parent_root.isNone():
reader.raiseUnexpectedValue("Field `parent_root` is missing")
if state_root.isNone():
reader.raiseUnexpectedValue("Field `state_root` is missing")
if blockBody.isNone():
reader.raiseUnexpectedValue("Field `body` is missing")
let body = blockBody.get()
value = RestPublishedBeaconBlock(
case body.kind
of BeaconBlockFork.Phase0:
ForkedBeaconBlock.init(
phase0.BeaconBlock(
slot: slot.get(),
proposer_index: proposer_index.get(),
parent_root: parent_root.get(),
state_root: state_root.get(),
body: body.phase0Body
)
)
of BeaconBlockFork.Altair:
ForkedBeaconBlock.init(
altair.BeaconBlock(
slot: slot.get(),
proposer_index: proposer_index.get(),
parent_root: parent_root.get(),
state_root: state_root.get(),
body: body.altairBody
)
)
of BeaconBlockFork.Bellatrix:
ForkedBeaconBlock.init(
bellatrix.BeaconBlock(
slot: slot.get(),
proposer_index: proposer_index.get(),
parent_root: parent_root.get(),
state_root: state_root.get(),
body: body.bellatrixBody
)
)
)
## RestPublishedSignedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
value: var RestPublishedSignedBeaconBlock) {.
raises: [IOError, SerializationError, Defect].} =
var signature: Option[ValidatorSig]
var message: Option[RestPublishedBeaconBlock]
for fieldName in readObjectFields(reader):
case fieldName
of "message":
if message.isSome():
reader.raiseUnexpectedField("Multiple `message` fields found",
"RestPublishedSignedBeaconBlock")
message = some(reader.readValue(RestPublishedBeaconBlock))
of "signature":
if signature.isSome():
reader.raiseUnexpectedField("Multiple `signature` fields found",
"RestPublishedSignedBeaconBlock")
signature = some(reader.readValue(ValidatorSig))
else:
# Ignore unknown fields
discard
if signature.isNone():
reader.raiseUnexpectedValue("Field `signature` is missing")
if message.isNone():
reader.raiseUnexpectedValue("Field `message` is missing")
let blck = ForkedBeaconBlock(message.get())
value = RestPublishedSignedBeaconBlock(
case blck.kind
of BeaconBlockFork.Phase0:
ForkedSignedBeaconBlock.init(
phase0.SignedBeaconBlock(
message: blck.phase0Data,
signature: signature.get()
)
)
of BeaconBlockFork.Altair:
ForkedSignedBeaconBlock.init(
altair.SignedBeaconBlock(
message: blck.altairData,
signature: signature.get()
)
)
of BeaconBlockFork.Bellatrix:
ForkedSignedBeaconBlock.init(
bellatrix.SignedBeaconBlock(
message: blck.bellatrixData,
signature: signature.get()
)
)
)
## ForkedSignedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
value: var ForkedSignedBeaconBlock) {.
raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconBlockFork]
data: Option[JsonString]
for fieldName in readObjectFields(reader):
case fieldName
of "version":
if version.isSome():
reader.raiseUnexpectedField("Multiple version fields found",
"ForkedSignedBeaconBlock")
let vres = reader.readValue(string)
case vres
of "phase0":
version = some(BeaconBlockFork.Phase0)
of "altair":
version = some(BeaconBlockFork.Altair)
of "bellatrix":
version = some(BeaconBlockFork.Bellatrix)
else:
reader.raiseUnexpectedValue("Incorrect version field value")
of "data":
if data.isSome():
reader.raiseUnexpectedField("Multiple data fields found",
"ForkedSignedBeaconBlock")
data = some(reader.readValue(JsonString))
else:
reader.raiseUnexpectedField(fieldName, "ForkedSignedBeaconBlock")
if version.isNone():
reader.raiseUnexpectedValue("Field version is missing")
if data.isNone():
reader.raiseUnexpectedValue("Field data is missing")
case version.get():
of BeaconBlockFork.Phase0:
let res =
try:
some(RestJson.decode(string(data.get()), phase0.SignedBeaconBlock,
requireAllFields = true))
except SerializationError:
none[phase0.SignedBeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect phase0 block format")
value = ForkedSignedBeaconBlock.init(res.get())
of BeaconBlockFork.Altair:
let res =
try:
some(RestJson.decode(string(data.get()), altair.SignedBeaconBlock,
requireAllFields = true))
except SerializationError:
none[altair.SignedBeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect altair block format")
value = ForkedSignedBeaconBlock.init(res.get())
of BeaconBlockFork.Bellatrix:
let res =
try:
some(RestJson.decode(string(data.get()), bellatrix.SignedBeaconBlock,
requireAllFields = true))
except SerializationError:
none[bellatrix.SignedBeaconBlock]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect bellatrix block format")
value = ForkedSignedBeaconBlock.init(res.get())
withBlck(value):
blck.root = hash_tree_root(blck.message)
proc writeValue*(writer: var JsonWriter[RestJson],
value: ForkedSignedBeaconBlock) {.
raises: [IOError, Defect].} =
writer.beginRecord()
case value.kind
of BeaconBlockFork.Phase0:
writer.writeField("version", "phase0")
writer.writeField("data", value.phase0Data)
of BeaconBlockFork.Altair:
writer.writeField("version", "altair")
writer.writeField("data", value.altairData)
of BeaconBlockFork.Bellatrix:
writer.writeField("version", "bellatrix")
writer.writeField("data", value.bellatrixData)
writer.endRecord()
# ForkedHashedBeaconState is used where a `ForkedBeaconState` normally would
# be used, mainly because caching the hash early on is easier to do
proc readValue*(reader: var JsonReader[RestJson],
value: var ForkedHashedBeaconState) {.
raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconStateFork]
data: Option[JsonString]
for fieldName in readObjectFields(reader):
case fieldName
of "version":
if version.isSome():
reader.raiseUnexpectedField("Multiple version fields found",
"ForkedBeaconState")
let vres = reader.readValue(string)
version = case vres
of "phase0": some(BeaconStateFork.Phase0)
of "altair": some(BeaconStateFork.Altair)
of "bellatrix": some(BeaconStateFork.Bellatrix)
else: reader.raiseUnexpectedValue("Incorrect version field value")
of "data":
if data.isSome():
reader.raiseUnexpectedField("Multiple data fields found",
"ForkedBeaconState")
data = some(reader.readValue(JsonString))
else:
reader.raiseUnexpectedField(fieldName, "ForkedBeaconState")
if version.isNone():
reader.raiseUnexpectedValue("Field version is missing")
if data.isNone():
reader.raiseUnexpectedValue("Field data is missing")
# Use a temporary to avoid stack instances and `value` mutation in case of
# exception
let
tmp = (ref ForkedHashedBeaconState)(kind: version.get())
template toValue(field: untyped) =
if tmp[].kind == value.kind:
assign(value.field, tmp[].field)
else:
value = tmp[] # slow, but rare (hopefully)
value.field.root = hash_tree_root(value.field.data)
case version.get():
of BeaconStateFork.Phase0:
try:
tmp[].phase0Data.data = RestJson.decode(
string(data.get()), phase0.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect phase0 beacon state format")
toValue(phase0Data)
of BeaconStateFork.Altair:
try:
tmp[].altairData.data = RestJson.decode(
string(data.get()), altair.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect altair beacon state format")
toValue(altairData)
of BeaconStateFork.Bellatrix:
try:
tmp[].bellatrixData.data = RestJson.decode(
string(data.get()), bellatrix.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect altair beacon state format")
toValue(bellatrixData)
proc writeValue*(writer: var JsonWriter[RestJson], value: ForkedHashedBeaconState) {.
raises: [IOError, Defect].} =
writer.beginRecord()
case value.kind
of BeaconStateFork.Phase0:
writer.writeField("version", "phase0")
writer.writeField("data", value.phase0Data.data)
of BeaconStateFork.Altair:
writer.writeField("version", "altair")
writer.writeField("data", value.altairData.data)
of BeaconStateFork.Bellatrix:
writer.writeField("version", "bellatrix")
writer.writeField("data", value.bellatrixData.data)
writer.endRecord()
# Web3SignerRequest
proc writeValue*(writer: var JsonWriter[RestJson],
value: Web3SignerRequest) {.
raises: [IOError, Defect].} =
case value.kind
of Web3SignerRequestKind.AggregationSlot:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "AGGREGATION_SLOT")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("aggregation_slot", value.aggregationSlot)
of Web3SignerRequestKind.AggregateAndProof:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "AGGREGATE_AND_PROOF")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("aggregate_and_proof", value.aggregateAndProof)
of Web3SignerRequestKind.Attestation:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "ATTESTATION")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("attestation", value.attestation)
of Web3SignerRequestKind.Block:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "BLOCK")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("block", value.blck)
of Web3SignerRequestKind.BlockV2:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "BLOCK_V2")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("beacon_block", value.beaconBlock)
of Web3SignerRequestKind.Deposit:
writer.writeField("type", "DEPOSIT")
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("deposit", value.deposit)
of Web3SignerRequestKind.RandaoReveal:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "RANDAO_REVEAL")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("randao_reveal", value.randaoReveal)
of Web3SignerRequestKind.VoluntaryExit:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "VOLUNTARY_EXIT")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("voluntary_exit", value.voluntaryExit)
of Web3SignerRequestKind.SyncCommitteeMessage:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "SYNC_COMMITTEE_MESSAGE")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("sync_committee_message", value.syncCommitteeMessage)
of Web3SignerRequestKind.SyncCommitteeSelectionProof:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "SYNC_COMMITTEE_SELECTION_PROOF")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("sync_aggregator_selection_data",
value.syncAggregatorSelectionData)
of Web3SignerRequestKind.SyncCommitteeContributionAndProof:
doAssert(value.forkInfo.isSome(),
"forkInfo should be set for this type of request")
writer.writeField("type", "SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF")
writer.writeField("fork_info", value.forkInfo.get())
if isSome(value.signingRoot):
writer.writeField("signingRoot", value.signingRoot)
writer.writeField("contribution_and_proof",
value.syncCommitteeContributionAndProof)
proc readValue*(reader: var JsonReader[RestJson],
value: var Web3SignerRequest) {.
raises: [IOError, SerializationError, Defect].} =
var
requestKind: Option[Web3SignerRequestKind]
forkInfo: Option[Web3SignerForkInfo]
signingRoot: Option[Eth2Digest]
data: Option[JsonString]
dataName: string
for fieldName in readObjectFields(reader):
case fieldName
of "type":
if requestKind.isSome():
reader.raiseUnexpectedField("Multiple `type` fields found",
"Web3SignerRequest")
let vres = reader.readValue(string)
requestKind = some(
case vres
of "AGGREGATION_SLOT":
Web3SignerRequestKind.AggregationSlot
of "AGGREGATE_AND_PROOF":
Web3SignerRequestKind.AggregateAndProof
of "ATTESTATION":
Web3SignerRequestKind.Attestation
of "BLOCK":
Web3SignerRequestKind.Block
of "BLOCK_V2":
Web3SignerRequestKind.BlockV2
of "DEPOSIT":
Web3SignerRequestKind.Deposit
of "RANDAO_REVEAL":
Web3SignerRequestKind.RandaoReveal
of "VOLUNTARY_EXIT":
Web3SignerRequestKind.VoluntaryExit
of "SYNC_COMMITTEE_MESSAGE":
Web3SignerRequestKind.SyncCommitteeMessage
of "SYNC_COMMITTEE_SELECTION_PROOF":
Web3SignerRequestKind.SyncCommitteeSelectionProof
of "SYNC_COMMITTEE_CONTRIBUTION_AND_PROOF":
Web3SignerRequestKind.SyncCommitteeContributionAndProof
else:
reader.raiseUnexpectedValue("Unexpected `type` value")
)
of "fork_info":
if forkInfo.isSome():
reader.raiseUnexpectedField("Multiple `fork_info` fields found",
"Web3SignerRequest")
forkInfo = some(reader.readValue(Web3SignerForkInfo))
of "signingRoot":
if signingRoot.isSome():
reader.raiseUnexpectedField("Multiple `signingRoot` fields found",
"Web3SignerRequest")
signingRoot = some(reader.readValue(Eth2Digest))
of "aggregation_slot", "aggregate_and_proof", "block", "beacon_block",
"randao_reveal", "voluntary_exit", "sync_committee_message",
"sync_aggregator_selection_data", "contribution_and_proof":
if data.isSome():
reader.raiseUnexpectedField("Multiple data fields found",
"Web3SignerRequest")
dataName = fieldName
data = some(reader.readValue(JsonString))
else:
# We ignore all unknown fields.
discard
if requestKind.isNone():
reader.raiseUnexpectedValue("Field `type` is missing")
value =
case requestKind.get()
of Web3SignerRequestKind.AggregationSlot:
if dataName != "aggregation_slot":
reader.raiseUnexpectedValue("Field `aggregation_slot` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(Web3SignerAggregationSlotData,
data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `aggregation_slot` format")
res.get()
Web3SignerRequest(kind: Web3SignerRequestKind.AggregationSlot,
forkInfo: forkInfo, signingRoot: signingRoot, aggregationSlot: data
)
of Web3SignerRequestKind.AggregateAndProof:
if dataName != "aggregate_and_proof":
reader.raiseUnexpectedValue("Field `aggregate_and_proof` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(AggregateAndProof, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `aggregate_and_proof` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.AggregateAndProof,
forkInfo: forkInfo, signingRoot: signingRoot, aggregateAndProof: data
)
of Web3SignerRequestKind.Attestation:
if dataName != "attestation":
reader.raiseUnexpectedValue("Field `attestation` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(AttestationData, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `attestation` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.Attestation,
forkInfo: forkInfo, signingRoot: signingRoot, attestation: data
)
of Web3SignerRequestKind.Block:
if dataName != "block":
reader.raiseUnexpectedValue("Field `block` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(phase0.BeaconBlock, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `block` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.Block,
forkInfo: forkInfo, signingRoot: signingRoot, blck: data
)
of Web3SignerRequestKind.BlockV2:
if dataName != "beacon_block":
reader.raiseUnexpectedValue("Field `beacon_block` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(ForkedBeaconBlock, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `beacon_block` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.BlockV2,
forkInfo: forkInfo, signingRoot: signingRoot, beaconBlock: data
)
of Web3SignerRequestKind.Deposit:
if dataName != "deposit":
reader.raiseUnexpectedValue("Field `deposit` is missing")
let data =
block:
let res = decodeJsonString(Web3SignerDepositData, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `deposit` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.Deposit,
signingRoot: signingRoot, deposit: data
)
of Web3SignerRequestKind.RandaoReveal:
if dataName != "randao_reveal":
reader.raiseUnexpectedValue("Field `randao_reveal` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(Web3SignerRandaoRevealData, data.get(),
true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `randao_reveal` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.RandaoReveal,
forkInfo: forkInfo, signingRoot: signingRoot, randaoReveal: data
)
of Web3SignerRequestKind.VoluntaryExit:
if dataName != "voluntary_exit":
reader.raiseUnexpectedValue("Field `voluntary_exit` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(VoluntaryExit, data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `voluntary_exit` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.VoluntaryExit,
forkInfo: forkInfo, signingRoot: signingRoot, voluntaryExit: data
)
of Web3SignerRequestKind.SyncCommitteeMessage:
if dataName != "sync_committee_message":
reader.raiseUnexpectedValue(
"Field `sync_committee_message` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(Web3SignerSyncCommitteeMessageData,
data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `sync_committee_message` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.SyncCommitteeMessage,
forkInfo: forkInfo, signingRoot: signingRoot,
syncCommitteeMessage: data
)
of Web3SignerRequestKind.SyncCommitteeSelectionProof:
if dataName != "sync_aggregator_selection_data":
reader.raiseUnexpectedValue(
"Field `sync_aggregator_selection_data` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(SyncAggregatorSelectionData,
data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `sync_aggregator_selection_data` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.SyncCommitteeSelectionProof,
forkInfo: forkInfo, signingRoot: signingRoot,
syncAggregatorSelectionData: data
)
of Web3SignerRequestKind.SyncCommitteeContributionAndProof:
if dataName != "contribution_and_proof":
reader.raiseUnexpectedValue(
"Field `contribution_and_proof` is missing")
if forkInfo.isNone():
reader.raiseUnexpectedValue("Field `fork_info` is missing")
let data =
block:
let res = decodeJsonString(ContributionAndProof,
data.get(), true)
if res.isErr():
reader.raiseUnexpectedValue(
"Incorrect field `contribution_and_proof` format")
res.get()
Web3SignerRequest(
kind: Web3SignerRequestKind.SyncCommitteeContributionAndProof,
forkInfo: forkInfo, signingRoot: signingRoot,
syncCommitteeContributionAndProof: data
)
## RemoteKeystoreStatus
proc writeValue*(writer: var JsonWriter[RestJson],
value: RemoteKeystoreStatus) {.raises: [IOError, Defect].} =
writer.beginRecord()
writer.writeField("status", $value.status)
if value.message.isSome():
writer.writeField("message", value.message.get())
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson],
value: var RemoteKeystoreStatus) {.
raises: [IOError, SerializationError, Defect].} =
var message: Option[string]
var status: Option[KeystoreStatus]
for fieldName in readObjectFields(reader):
case fieldName
of "message":
if message.isSome():
reader.raiseUnexpectedField("Multiple `message` fields found",
"RemoteKeystoreStatus")
message = some(reader.readValue(string))
of "status":
if status.isSome():
reader.raiseUnexpectedField("Multiple `status` fields found",
"RemoteKeystoreStatus")
let res = reader.readValue(string)
status = some(
case res
of "error":
KeystoreStatus.error
of "not_active":
KeystoreStatus.notActive
of "not_found":
KeystoreStatus.notFound
of "deleted":
KeystoreStatus.deleted
of "duplicate":
KeystoreStatus.duplicate
of "imported":
KeystoreStatus.imported
else:
reader.raiseUnexpectedValue("Invalid `status` value")
)
else:
# We ignore all unknown fields.
discard
if status.isNone():
reader.raiseUnexpectedValue("Field `status` is missing")
value = RemoteKeystoreStatus(status: status.get(), message: message)
## ScryptSalt
proc readValue*(reader: var JsonReader[RestJson], value: var ScryptSalt) {.
raises: [SerializationError, IOError, Defect].} =
let res = ncrutils.fromHex(reader.readValue(string))
if len(res) == 0:
reader.raiseUnexpectedValue("Invalid scrypt salt value")
value = ScryptSalt(res)
## Pbkdf2Params
proc writeValue*(writer: var JsonWriter[RestJson], value: Pbkdf2Params) {.
raises: [IOError, Defect].} =
writer.beginRecord()
writer.writeField("dklen", JsonString(Base10.toString(value.dklen)))
writer.writeField("c", JsonString(Base10.toString(value.c)))
writer.writeField("prf", value.prf)
writer.writeField("salt", value.salt)
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson], value: var Pbkdf2Params) {.
raises: [SerializationError, IOError, Defect].} =
var
dklen: Option[uint64]
c: Option[uint64]
prf: Option[PrfKind]
salt: Option[Pbkdf2Salt]
for fieldName in readObjectFields(reader):
case fieldName
of "dklen":
if dklen.isSome():
reader.raiseUnexpectedField("Multiple `dklen` fields found",
"Pbkdf2Params")
dklen = some(reader.readValue(uint64))
of "c":
if c.isSome():
reader.raiseUnexpectedField("Multiple `c` fields found",
"Pbkdf2Params")
c = some(reader.readValue(uint64))
of "prf":
if prf.isSome():
reader.raiseUnexpectedField("Multiple `prf` fields found",
"Pbkdf2Params")
prf = some(reader.readValue(PrfKind))
of "salt":
if salt.isSome():
reader.raiseUnexpectedField("Multiple `salt` fields found",
"Pbkdf2Params")
salt = some(reader.readValue(Pbkdf2Salt))
else:
# Ignore unknown field names.
discard
if dklen.isNone():
reader.raiseUnexpectedValue("Field `dklen` is missing")
if c.isNone():
reader.raiseUnexpectedValue("Field `c` is missing")
if prf.isNone():
reader.raiseUnexpectedValue("Field `prf` is missing")
if salt.isNone():
reader.raiseUnexpectedValue("Field `salt` is missing")
value = Pbkdf2Params(
dklen: dklen.get(),
c: c.get(),
prf: prf.get(),
salt: salt.get()
)
## ScryptParams
proc writeValue*(writer: var JsonWriter[RestJson], value: ScryptParams) {.
raises: [IOError, Defect].} =
writer.beginRecord()
writer.writeField("dklen", JsonString(Base10.toString(value.dklen)))
writer.writeField("n", JsonString(Base10.toString(uint64(value.n))))
writer.writeField("p", JsonString(Base10.toString(uint64(value.p))))
writer.writeField("r", JsonString(Base10.toString(uint64(value.r))))
writer.writeField("salt", value.salt)
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson], value: var ScryptParams) {.
raises: [SerializationError, IOError, Defect].} =
var
dklen: Option[uint64]
n, p, r: Option[int]
salt: Option[ScryptSalt]
for fieldName in readObjectFields(reader):
case fieldName
of "dklen":
if dklen.isSome():
reader.raiseUnexpectedField("Multiple `dklen` fields found",
"ScryptParams")
dklen = some(reader.readValue(uint64))
of "n":
if n.isSome():
reader.raiseUnexpectedField("Multiple `n` fields found",
"ScryptParams")
let res = reader.readValue(int)
if res < 0:
reader.raiseUnexpectedValue("Unexpected negative `n` value")
n = some(res)
of "p":
if p.isSome():
reader.raiseUnexpectedField("Multiple `p` fields found",
"ScryptParams")
let res = reader.readValue(int)
if res < 0:
reader.raiseUnexpectedValue("Unexpected negative `p` value")
p = some(res)
of "r":
if r.isSome():
reader.raiseUnexpectedField("Multiple `r` fields found",
"ScryptParams")
let res = reader.readValue(int)
if res < 0:
reader.raiseUnexpectedValue("Unexpected negative `r` value")
r = some(res)
of "salt":
if salt.isSome():
reader.raiseUnexpectedField("Multiple `salt` fields found",
"ScryptParams")
salt = some(reader.readValue(ScryptSalt))
else:
# Ignore unknown field names.
discard
if dklen.isNone():
reader.raiseUnexpectedValue("Field `dklen` is missing")
if n.isNone():
reader.raiseUnexpectedValue("Field `n` is missing")
if p.isNone():
reader.raiseUnexpectedValue("Field `p` is missing")
if r.isNone():
reader.raiseUnexpectedValue("Field `r` is missing")
if salt.isNone():
reader.raiseUnexpectedValue("Field `salt` is missing")
value = ScryptParams(
dklen: dklen.get(),
n: n.get(), p: p.get(), r: r.get(),
salt: salt.get()
)
## Keystore
proc writeValue*(writer: var JsonWriter[RestJson], value: Keystore) {.
raises: [IOError, Defect].} =
writer.beginRecord()
writer.writeField("crypto", value.crypto)
if not(isNil(value.description)):
writer.writeField("description", value.description[])
writer.writeField("pubkey", value.pubkey)
writer.writeField("path", string(value.path))
writer.writeField("uuid", value.uuid)
writer.writeField("version", JsonString(
Base10.toString(uint64(value.version))))
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson], value: var Keystore) {.
raises: [SerializationError, IOError, Defect].} =
var
crypto: Option[Crypto]
description: Option[string]
pubkey: Option[ValidatorPubKey]
path: Option[KeyPath]
uuid: Option[string]
version: Option[int]
for fieldName in readObjectFields(reader):
case fieldName
of "crypto":
if crypto.isSome():
reader.raiseUnexpectedField("Multiple `crypto` fields found",
"Keystore")
crypto = some(reader.readValue(Crypto))
of "description":
let res = reader.readValue(string)
if description.isSome():
description = some(description.get() & "\n" & res)
else:
description = some(res)
of "pubkey":
if pubkey.isSome():
reader.raiseUnexpectedField("Multiple `pubkey` fields found",
"Keystore")
pubkey = some(reader.readValue(ValidatorPubKey))
of "path":
if path.isSome():
reader.raiseUnexpectedField("Multiple `path` fields found",
"Keystore")
let res = validateKeyPath(reader.readValue(string))
if res.isErr():
reader.raiseUnexpectedValue("Invalid `path` value")
path = some(res.get())
of "uuid":
if uuid.isSome():
reader.raiseUnexpectedField("Multiple `uuid` fields found",
"Keystore")
uuid = some(reader.readValue(string))
of "version":
if version.isSome():
reader.raiseUnexpectedField("Multiple `version` fields found",
"Keystore")
let res = reader.readValue(int)
if res < 0:
reader.raiseUnexpectedValue("Unexpected negative `version` value")
version = some(res)
else:
# Ignore unknown field names.
discard
if crypto.isNone():
reader.raiseUnexpectedValue("Field `crypto` is missing")
if pubkey.isNone():
reader.raiseUnexpectedValue("Field `pubkey` is missing")
if path.isNone():
reader.raiseUnexpectedValue("Field `path` is missing")
if uuid.isNone():
reader.raiseUnexpectedValue("Field `uuid` is missing")
if version.isNone():
reader.raiseUnexpectedValue("Field `version` is missing")
value = Keystore(
crypto: crypto.get(),
pubkey: pubkey.get(),
path: path.get(),
uuid: uuid.get(),
description: if description.isNone(): nil else: newClone(description.get()),
version: version.get(),
)
## KeystoresAndSlashingProtection
proc writeValue*(writer: var JsonWriter[RestJson],
value: KeystoresAndSlashingProtection) {.
raises: [IOError, Defect].} =
writer.beginRecord()
writer.writeField("keystores", value.keystores)
writer.writeField("passwords", value.passwords)
if value.slashing_protection.isSome():
writer.writeField("slashing_protection", value.slashing_protection)
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson],
value: var KeystoresAndSlashingProtection) {.
raises: [SerializationError, IOError, Defect].} =
var
keystores: seq[Keystore]
passwords: seq[string]
slashing: Option[SPDIR]
for fieldName in readObjectFields(reader):
case fieldName
of "keystores":
keystores = reader.readValue(seq[Keystore])
of "passwords":
passwords = reader.readValue(seq[string])
of "slashing_protection":
if slashing.isSome():
reader.raiseUnexpectedField(
"Multiple `slashing_protection` fields found",
"KeystoresAndSlashingProtection")
slashing = some(reader.readValue(SPDIR))
else:
# Ignore unknown field names.
discard
if len(keystores) == 0:
reader.raiseUnexpectedValue("Missing `keystores` value")
if len(passwords) == 0:
reader.raiseUnexpectedValue("Missing `passwords` value")
value = KeystoresAndSlashingProtection(
keystores: keystores, passwords: passwords, slashing_protection: slashing
)
proc parseRoot(value: string): Result[Eth2Digest, cstring] =
try:
ok(Eth2Digest(data: hexToByteArray[32](value)))
except ValueError:
err("Unable to decode root value")
proc decodeBody*[T](t: typedesc[T],
body: ContentBody): Result[T, cstring] =
if body.contentType != "application/json":
return err("Unsupported content type")
let data =
try:
RestJson.decode(body.data, T)
except SerializationError as exc:
return err("Unable to deserialize data")
except CatchableError:
return err("Unexpected deserialization error")
ok(data)
proc encodeBytes*[T: EncodeTypes](value: T,
contentType: string): RestResult[seq[byte]] =
case contentType
of "application/json":
let data =
block:
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.writeValue(value)
stream.getOutput(seq[byte])
except IOError:
return err("Input/output error")
except SerializationError:
return err("Serialization error")
ok(data)
else:
err("Content-Type not supported")
proc encodeBytes*[T: EncodeArrays](value: T,
contentType: string): RestResult[seq[byte]] =
case contentType
of "application/json":
let data =
block:
try:
var stream = memoryOutput()
var writer = JsonWriter[RestJson].init(stream)
writer.writeArray(value)
stream.getOutput(seq[byte])
except IOError:
return err("Input/output error")
except SerializationError:
return err("Serialization error")
ok(data)
else:
err("Content-Type not supported")
proc decodeBytes*[T: DecodeTypes](t: typedesc[T], value: openArray[byte],
contentType: string): RestResult[T] =
const isExtensibleType = t is ExtensibleDecodeTypes
case contentType
of "application/json":
try:
ok RestJson.decode(value, T, allowUnknownFields = isExtensibleType)
except SerializationError:
err("Serialization error")
else:
err("Content-Type not supported")
proc decodeBytes*[T: SszDecodeTypes](t: typedesc[T], value: openArray[byte],
contentType: string, updateRoot = true): RestResult[T] =
case contentType
of "application/octet-stream":
try:
var v: RestResult[T]
v.ok(T()) # This optimistically avoids an expensive genericAssign
readSszBytes(value, v.get(), updateRoot)
v
except SerializationError as exc:
err("Serialization error")
else:
err("Content-Type not supported")
proc encodeString*(value: string): RestResult[string] =
ok(value)
proc encodeString*(value: Epoch|Slot|CommitteeIndex|SyncSubcommitteeIndex): RestResult[string] =
ok(Base10.toString(uint64(value)))
proc encodeString*(value: ValidatorSig): RestResult[string] =
ok(hexOriginal(toRaw(value)))
proc encodeString*(value: GraffitiBytes): RestResult[string] =
ok(hexOriginal(distinctBase(value)))
proc encodeString*(value: Eth2Digest): RestResult[string] =
ok(hexOriginal(value.data))
proc encodeString*(value: ValidatorIdent): RestResult[string] =
case value.kind
of ValidatorQueryKind.Index:
ok(Base10.toString(uint64(value.index)))
of ValidatorQueryKind.Key:
ok(hexOriginal(toRaw(value.key)))
proc encodeString*(value: ValidatorPubKey): RestResult[string] =
ok(hexOriginal(toRaw(value)))
proc encodeString*(value: StateIdent): RestResult[string] =
case value.kind
of StateQueryKind.Slot:
ok(Base10.toString(uint64(value.slot)))
of StateQueryKind.Root:
ok(hexOriginal(value.root.data))
of StateQueryKind.Named:
case value.value
of StateIdentType.Head:
ok("head")
of StateIdentType.Genesis:
ok("genesis")
of StateIdentType.Finalized:
ok("finalized")
of StateIdentType.Justified:
ok("justified")
proc encodeString*(value: BlockIdent): RestResult[string] =
case value.kind
of BlockQueryKind.Slot:
ok(Base10.toString(uint64(value.slot)))
of BlockQueryKind.Root:
ok(hexOriginal(value.root.data))
of BlockQueryKind.Named:
case value.value
of BlockIdentType.Head:
ok("head")
of BlockIdentType.Genesis:
ok("genesis")
of BlockIdentType.Finalized:
ok("finalized")
proc decodeString*(t: typedesc[PeerStateKind],
value: string): Result[PeerStateKind, cstring] =
case value
of "disconnected":
ok(PeerStateKind.Disconnected)
of "connecting":
ok(PeerStateKind.Connecting)
of "connected":
ok(PeerStateKind.Connected)
of "disconnecting":
ok(PeerStateKind.Disconnecting)
else:
err("Incorrect peer's state value")
proc encodeString*(value: PeerStateKind): Result[string, cstring] =
case value
of PeerStateKind.Disconnected:
ok("disconnected")
of PeerStateKind.Connecting:
ok("connecting")
of PeerStateKind.Connected:
ok("connected")
of PeerStateKind.Disconnecting:
ok("disconnecting")
proc decodeString*(t: typedesc[PeerDirectKind],
value: string): Result[PeerDirectKind, cstring] =
case value
of "inbound":
ok(PeerDirectKind.Inbound)
of "outbound":
ok(PeerDirectKind.Outbound)
else:
err("Incorrect peer's direction value")
proc encodeString*(value: PeerDirectKind): Result[string, cstring] =
case value
of PeerDirectKind.Inbound:
ok("inbound")
of PeerDirectKind.Outbound:
ok("outbound")
proc encodeString*(peerid: PeerId): Result[string, cstring] =
ok($peerid)
proc decodeString*(t: typedesc[EventTopic],
value: string): Result[EventTopic, cstring] =
case value
of "head":
ok(EventTopic.Head)
of "block":
ok(EventTopic.Block)
of "attestation":
ok(EventTopic.Attestation)
of "voluntary_exit":
ok(EventTopic.VoluntaryExit)
of "finalized_checkpoint":
ok(EventTopic.FinalizedCheckpoint)
of "chain_reorg":
ok(EventTopic.ChainReorg)
of "contribution_and_proof":
ok(EventTopic.ContributionAndProof)
else:
err("Incorrect event's topic value")
proc decodeString*(t: typedesc[ValidatorSig],
value: string): Result[ValidatorSig, cstring] =
if len(value) != ValidatorSigSize + 2:
return err("Incorrect validator signature value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect validator signature encoding")
ValidatorSig.fromHex(value)
proc decodeString*(t: typedesc[ValidatorPubKey],
value: string): Result[ValidatorPubKey, cstring] =
if len(value) != ValidatorKeySize + 2:
return err("Incorrect validator's key value length")
if value[0] != '0' and value[1] != 'x':
err("Incorrect validator's key encoding")
else:
ValidatorPubKey.fromHex(value)
proc decodeString*(t: typedesc[GraffitiBytes],
value: string): Result[GraffitiBytes, cstring] =
try:
ok(GraffitiBytes.init(value))
except ValueError:
err("Unable to decode graffiti value")
proc decodeString*(t: typedesc[string],
value: string): Result[string, cstring] =
ok(value)
proc decodeString*(t: typedesc[Slot], value: string): Result[Slot, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Slot(res))
proc decodeString*(t: typedesc[Epoch], value: string): Result[Epoch, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Epoch(res))
proc decodeString*(t: typedesc[uint64],
value: string): Result[uint64, cstring] =
Base10.decode(uint64, value)
proc decodeString*(t: typedesc[StateIdent],
value: string): Result[StateIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect state root value length")
else:
let res = ? parseRoot(value)
ok(StateIdent(kind: StateQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Head))
of "genesis":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Genesis))
of "finalized":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Finalized))
of "justified":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Justified))
else:
err("Incorrect state identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[BlockIdent],
value: string): Result[BlockIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect block root value length")
else:
let res = ? parseRoot(value)
ok(BlockIdent(kind: BlockQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Head))
of "genesis":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Genesis))
of "finalized":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Finalized))
else:
err("Incorrect block identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[ValidatorIdent],
value: string): Result[ValidatorIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != ValidatorKeySize + 2:
err("Incorrect validator's key value length")
else:
let res = ? ValidatorPubKey.fromHex(value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Key,
key: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
else:
err("Incorrect validator identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
proc decodeString*(t: typedesc[PeerId],
value: string): Result[PeerId, cstring] =
PeerId.init(value)
proc decodeString*(t: typedesc[CommitteeIndex],
value: string): Result[CommitteeIndex, cstring] =
let res = ? Base10.decode(uint64, value)
CommitteeIndex.init(res)
proc decodeString*(t: typedesc[SyncSubcommitteeIndex],
value: string): Result[SyncSubcommitteeIndex, cstring] =
let res = ? Base10.decode(uint64, value)
SyncSubcommitteeIndex.init(res)
proc decodeString*(t: typedesc[Eth2Digest],
value: string): Result[Eth2Digest, cstring] =
if len(value) != RootHashSize + 2:
return err("Incorrect root value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect root value encoding")
parseRoot(value)
proc decodeString*(t: typedesc[ValidatorFilter],
value: string): Result[ValidatorFilter, cstring] =
case value
of "pending_initialized":
ok({ValidatorFilterKind.PendingInitialized})
of "pending_queued":
ok({ValidatorFilterKind.PendingQueued})
of "active_ongoing":
ok({ValidatorFilterKind.ActiveOngoing})
of "active_exiting":
ok({ValidatorFilterKind.ActiveExiting})
of "active_slashed":
ok({ValidatorFilterKind.ActiveSlashed})
of "exited_unslashed":
ok({ValidatorFilterKind.ExitedUnslashed})
of "exited_slashed":
ok({ValidatorFilterKind.ExitedSlashed})
of "withdrawal_possible":
ok({ValidatorFilterKind.WithdrawalPossible})
of "withdrawal_done":
ok({ValidatorFilterKind.WithdrawalDone})
of "pending":
ok({
ValidatorFilterKind.PendingInitialized,
ValidatorFilterKind.PendingQueued
})
of "active":
ok({
ValidatorFilterKind.ActiveOngoing,
ValidatorFilterKind.ActiveExiting,
ValidatorFilterKind.ActiveSlashed
})
of "exited":
ok({
ValidatorFilterKind.ExitedUnslashed,
ValidatorFilterKind.ExitedSlashed
})
of "withdrawal":
ok({
ValidatorFilterKind.WithdrawalPossible,
ValidatorFilterKind.WithdrawalDone
})
else:
err("Incorrect validator state identifier value")