REST cleanups (#3255)

* REST cleanups

* reject out-of-range committee requests
* print all hex values as lower-case
* allow requesting state information by head state root
* turn `DomainType` into array (follow spec)
* `uint_to_bytesXX` -> `uint_to_bytes` (follow spec)
* fix wrong dependent root in `/eth/v1/validator/duties/proposer/`
* update documentation - `--subscribe-all-subnets` is no longer needed
when using the REST interface with validator clients
* more fixes
* common helpers for dependent block
* remove test rules obsoleted by more strict epoch tests
* fix trailing commas

* Update docs/the_nimbus_book/src/rest-api.md
* Update docs/the_nimbus_book/src/rest-api.md

Co-authored-by: sacha <sacha@status.im>
This commit is contained in:
Jacek Sieka 2022-01-08 21:06:34 +01:00 committed by GitHub
parent 25bb927e62
commit 6f7e0e3393
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 242 additions and 331 deletions

View File

@ -57,7 +57,6 @@ type
## Slot time for this BlockSlot which may differ from blck.slot when time
## has advanced without blocks
template root*(blck: BlockRef): Eth2Digest = blck.bid.root
template slot*(blck: BlockRef): Slot = blck.bid.slot
@ -213,6 +212,20 @@ func isProposed*(bsi: BlockSlotId): bool =
## slot)
bsi.bid.isProposed(bsi.slot)
func dependentBlock*(head, tail: BlockRef, epoch: Epoch): BlockRef =
## The block that determined the proposer shuffling in the given epoch
let dependentSlot =
if epoch >= Epoch(1): epoch.compute_start_slot_at_epoch() - 1
else: Slot(0)
let res = head.atSlot(dependentSlot)
if isNil(res.blck): tail
else: res.blck
func prevDependentBlock*(head, tail: BlockRef, epoch: Epoch): BlockRef =
## The block that determined the attester shuffling in the given epoch
if epoch >= 1: head.dependentBlock(tail, epoch - 1)
else: head.dependentBlock(tail, epoch)
func shortLog*(v: BlockId): string =
# epoch:root when logging epoch, root:slot when logging slot!
shortLog(v.root) & ":" & $v.slot

View File

@ -11,7 +11,7 @@ import
# Standard library
std/[options, sets, tables, hashes],
# Status libraries
stew/endians2, chronicles,
chronicles,
# Internals
../spec/[signatures_batch, forks, helpers],
../spec/datatypes/[phase0, altair, bellatrix],

View File

@ -1362,25 +1362,15 @@ proc updateHead*(
dag.headState.data, finalized_checkpoint))
if not(isNil(dag.onHeadChanged)):
let currentEpoch = epoch(newHead.slot)
let
currentDutyDepRoot =
if currentEpoch > dag.tail.slot.epoch:
dag.head.atSlot(
compute_start_slot_at_epoch(currentEpoch) - 1).blck.root
else:
dag.tail.root
previousDutyDepRoot =
if currentEpoch > dag.tail.slot.epoch + 1:
dag.head.atSlot(
compute_start_slot_at_epoch(currentEpoch - 1) - 1).blck.root
else:
dag.tail.root
currentEpoch = epoch(newHead.slot)
depBlock = dag.head.dependentBlock(dag.tail, currentEpoch)
prevDepBlock = dag.head.prevDependentBlock(dag.tail, currentEpoch)
epochTransition = (finalizedHead != dag.finalizedHead)
let data = HeadChangeInfoObject.init(dag.head.slot, dag.head.root,
getStateRoot(dag.headState.data),
epochTransition, previousDutyDepRoot,
currentDutyDepRoot)
epochTransition, depBlock.root,
prevDepBlock.root)
dag.onHeadChanged(data)
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics

View File

@ -9,7 +9,6 @@ import
std/[typetraits, sequtils, strutils, sets],
stew/[results, base10],
chronicles,
nimcrypto/utils as ncrutils,
./rest_utils,
../beacon_node, ../networking/eth2_network,
../consensus_object_pools/[blockchain_dag, exit_pool, spec_cache],
@ -121,14 +120,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -144,14 +142,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -177,14 +174,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -209,14 +205,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -338,14 +333,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -407,14 +401,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -501,14 +494,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
return RestApiResponse.jsonError(Http500, NoImplementationError)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
@ -519,8 +511,18 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
$repoch.error())
let res = repoch.get()
if res > MaxEpoch:
return RestApiResponse.jsonError(Http400, EpochOverflowValueError)
if res > bslot.slot.epoch + MIN_SEED_LOOKAHEAD:
return RestApiResponse.jsonError(
Http400, InvalidEpochValueError,
"Requested epoch more than 1 epoch past state epoch")
if res + EPOCHS_PER_HISTORICAL_VECTOR <
bslot.slot.epoch + MIN_SEED_LOOKAHEAD:
return RestApiResponse.jsonError(
Http400, InvalidEpochValueError,
"Requested epoch earlier than what committees can be computed for")
some(res)
else:
none[Epoch]()
@ -540,7 +542,24 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if rslot.isErr():
return RestApiResponse.jsonError(Http400, InvalidSlotValueError,
$rslot.error())
some(rslot.get())
let res = rslot.get()
if vepoch.isSome():
if res.epoch != vepoch.get():
return RestApiResponse.jsonError(Http400, InvalidSlotValueError,
"Slot does not match requested epoch")
else:
if res.epoch > bslot.slot.epoch + 1:
return RestApiResponse.jsonError(
Http400, InvalidEpochValueError,
"Requested slot more than 1 epoch past state epoch")
if res.epoch + EPOCHS_PER_HISTORICAL_VECTOR <
bslot.slot.epoch + MIN_SEED_LOOKAHEAD:
return RestApiResponse.jsonError(
Http400, InvalidEpochValueError,
"Requested slot earlier than what committees can be computed for")
some(res)
else:
none[Slot]()
node.withStateForBlockSlot(bslot):
@ -590,13 +609,15 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if state_id.isErr():
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
$state_id.error())
let sid = state_id.get()
let bres = node.getBlockSlot(sid)
if bres.isErr():
if sid.kind == StateQueryKind.Root:
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
# in current version of database.
let sid = state_id.get()
if sid.kind == StateQueryKind.Root:
return RestApiResponse.jsonError(Http500, NoImplementationError)
let bres = node.getBlockSlot(sid)
return RestApiResponse.jsonError(Http404, StateNotFoundError,
$bres.error())
bres.get()
let qepoch =

View File

@ -4,8 +4,7 @@
# * 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 stew/[endians2, base10], chronicles,
nimcrypto/utils as ncrutils
import stew/[byteutils, base10], chronicles
import ".."/beacon_node,
".."/eth1/eth1_monitor,
".."/spec/forks,
@ -170,38 +169,31 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
# JUSTIFICATION_BITS_LENGTH
# ENDIANNESS
BLS_WITHDRAWAL_PREFIX:
"0x" & ncrutils.toHex([BLS_WITHDRAWAL_PREFIX]),
to0xHex([BLS_WITHDRAWAL_PREFIX]),
ETH1_ADDRESS_WITHDRAWAL_PREFIX:
"0x" & ncrutils.toHex([ETH1_ADDRESS_WITHDRAWAL_PREFIX]),
to0xHex([ETH1_ADDRESS_WITHDRAWAL_PREFIX]),
DOMAIN_BEACON_PROPOSER:
"0x" & ncrutils.toHex(
uint32(DOMAIN_BEACON_PROPOSER).toBytesLE()),
to0xHex(DOMAIN_BEACON_PROPOSER.data),
DOMAIN_BEACON_ATTESTER:
"0x" & ncrutils.toHex(
uint32(DOMAIN_BEACON_ATTESTER).toBytesLE()),
to0xHex(DOMAIN_BEACON_ATTESTER.data),
DOMAIN_RANDAO:
"0x" & ncrutils.toHex(
uint32(DOMAIN_RANDAO).toBytesLE()),
to0xHex(DOMAIN_RANDAO.data),
DOMAIN_DEPOSIT:
"0x" & ncrutils.toHex(
uint32(DOMAIN_DEPOSIT).toBytesLE()),
to0xHex(DOMAIN_DEPOSIT.data),
DOMAIN_VOLUNTARY_EXIT:
"0x" & ncrutils.toHex(
uint32(DOMAIN_VOLUNTARY_EXIT).toBytesLE()),
to0xHex(DOMAIN_VOLUNTARY_EXIT.data),
DOMAIN_SELECTION_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_SELECTION_PROOF).toBytesLE()),
to0xHex(DOMAIN_SELECTION_PROOF.data),
DOMAIN_AGGREGATE_AND_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_AGGREGATE_AND_PROOF).toBytesLE()),
to0xHex(DOMAIN_AGGREGATE_AND_PROOF.data),
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/altair/beacon-chain.md#constants
TIMELY_SOURCE_FLAG_INDEX:
"0x" & ncrutils.toHex([byte(TIMELY_SOURCE_FLAG_INDEX)]),
to0xHex([byte(TIMELY_SOURCE_FLAG_INDEX)]),
TIMELY_TARGET_FLAG_INDEX:
"0x" & ncrutils.toHex([byte(TIMELY_TARGET_FLAG_INDEX)]),
to0xHex([byte(TIMELY_TARGET_FLAG_INDEX)]),
TIMELY_HEAD_FLAG_INDEX:
"0x" & ncrutils.toHex([byte(TIMELY_HEAD_FLAG_INDEX)]),
to0xHex([byte(TIMELY_HEAD_FLAG_INDEX)]),
TIMELY_SOURCE_WEIGHT:
Base10.toString(uint64(TIMELY_SOURCE_WEIGHT)),
TIMELY_TARGET_WEIGHT:
@ -215,14 +207,11 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
WEIGHT_DENOMINATOR:
Base10.toString(uint64(WEIGHT_DENOMINATOR)),
DOMAIN_SYNC_COMMITTEE:
"0x" & ncrutils.toHex(
uint32(DOMAIN_SYNC_COMMITTEE).toBytesLE()),
to0xHex(DOMAIN_SYNC_COMMITTEE.data),
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF).toBytesLE()),
to0xHex(DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF.data),
DOMAIN_CONTRIBUTION_AND_PROOF:
"0x" & ncrutils.toHex(
uint32(DOMAIN_CONTRIBUTION_AND_PROOF).toBytesLE()),
to0xHex(DOMAIN_CONTRIBUTION_AND_PROOF.data),
# PARTICIPATION_FLAG_WEIGHTS
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/validator.md#constants

View File

@ -1,10 +1,9 @@
import
std/[sequtils],
stew/results,
stew/[byteutils, results],
chronicles,
eth/p2p/discoveryv5/enr,
libp2p/[multiaddress, multicodec, peerstore],
nimcrypto/utils as ncrutils,
../version, ../beacon_node, ../sync/sync_manager,
../networking/[eth2_network, peer_pool],
../spec/datatypes/base,
@ -158,8 +157,8 @@ proc installNodeApiHandlers*(router: var RestRouter, node: BeaconNode) =
discovery_addresses: discoveryAddresses,
metadata: (
seq_number: node.network.metadata.seq_number,
syncnets: "0x" & ncrutils.toHex(node.network.metadata.syncnets.bytes),
attnets: "0x" & ncrutils.toHex(node.network.metadata.attnets.bytes)
syncnets: to0xHex(node.network.metadata.syncnets.bytes),
attnets: to0xHex(node.network.metadata.attnets.bytes)
)
)
)

View File

@ -1,6 +1,5 @@
import std/[options, macros],
stew/byteutils, presto,
nimcrypto/utils as ncrutils,
../spec/[forks],
../spec/eth2_apis/[rest_types, eth2_rest_serialization],
../beacon_node,

View File

@ -4,8 +4,7 @@
# * 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, strutils, sets]
import stew/[results, base10], chronicles,
nimcrypto/utils as ncrutils
import stew/[results, base10], chronicles
import ".."/[beacon_chain_db, beacon_node],
".."/networking/eth2_network,
".."/consensus_object_pools/[blockchain_dag, spec_cache,
@ -54,9 +53,13 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
if epoch.isErr():
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
$epoch.error())
let res = epoch.get()
if res > MaxEpoch:
return RestApiResponse.jsonError(Http400, EpochOverflowValueError)
let
res = epoch.get()
wallTime = node.beaconClock.now() + MAXIMUM_GOSSIP_CLOCK_DISPARITY
wallEpoch = wallTime.slotOrZero().epoch
if res > wallEpoch + 1:
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
"Cannot request duties past next epoch")
res
let qhead =
block:
@ -64,11 +67,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
if res.isErr():
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
res.get()
let droot =
if qepoch >= Epoch(2):
qhead.atSlot(compute_start_slot_at_epoch(qepoch - 1) - 1).blck.root
else:
node.dag.genesis.root
let droot = qhead.prevDependentBlock(node.dag.tail, qepoch).root
let duties =
block:
var res: seq[RestAttesterDuty]
@ -112,9 +111,13 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
if epoch.isErr():
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
$epoch.error())
let res = epoch.get()
if res > MaxEpoch:
return RestApiResponse.jsonError(Http400, EpochOverflowValueError)
let
res = epoch.get()
wallTime = node.beaconClock.now() + MAXIMUM_GOSSIP_CLOCK_DISPARITY
wallEpoch = wallTime.slotOrZero().epoch
if res > wallEpoch + 1:
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
"Cannot request duties past next epoch")
res
let qhead =
block:
@ -122,11 +125,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
if res.isErr():
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
res.get()
let droot =
if qepoch >= Epoch(2):
qhead.atSlot(compute_start_slot_at_epoch(qepoch - 1) - 1).blck.root
else:
node.dag.genesis.root
let droot = qhead.dependentBlock(node.dag.tail, qepoch).root
let duties =
block:
var res: seq[RestProposerDuty]
@ -504,8 +503,6 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
router.api(MethodPost,
"/eth/v1/validator/beacon_committee_subscriptions") do (
contentBody: Option[ContentBody]) -> RestApiResponse:
# TODO (cheatfate): This call could not be finished because more complex
# peer manager implementation needed.
let requests =
block:
if contentBody.isNone():
@ -605,7 +602,8 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
subs
warn "Sync committee subscription request served, but not implemented"
# TODO because we subscribe to all sync committee subnets, we don not need
# to remember which ones are requested by validator clients
return RestApiResponse.jsonMsgResponse(SyncCommitteeSubscriptionSuccess)
# https://ethereum.github.io/beacon-APIs/#/Validator/produceSyncCommitteeContribution

View File

@ -9,10 +9,9 @@
import
std/[parseutils, sequtils, strutils, sets],
stew/results,
stew/[byteutils, results],
json_rpc/servers/httpserver,
chronicles,
nimcrypto/utils as ncrutils,
../beacon_node,
../networking/eth2_network,
../validators/validator_duties,
@ -452,7 +451,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
for item in node.attestationPool[].attestations(qslot, qindex):
let atuple = (
aggregation_bits: "0x" & ncrutils.toHex(item.aggregation_bits.bytes),
aggregation_bits: to0xHex(item.aggregation_bits.bytes),
data: item.data,
signature: item.signature
)

View File

@ -8,10 +8,9 @@
{.push raises: [Defect].}
import
stew/endians2,
stew/[byteutils],
json_rpc/servers/httpserver,
chronicles,
nimcrypto/utils as ncrutils,
../beacon_node,
../eth1/eth1_monitor,
../spec/forks
@ -59,7 +58,7 @@ proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
"EFFECTIVE_BALANCE_INCREMENT": $EFFECTIVE_BALANCE_INCREMENT,
"GENESIS_FORK_VERSION":
"0x" & $node.dag.cfg.GENESIS_FORK_VERSION,
"BLS_WITHDRAWAL_PREFIX": "0x" & ncrutils.toHex([BLS_WITHDRAWAL_PREFIX]),
"BLS_WITHDRAWAL_PREFIX": to0xHex([BLS_WITHDRAWAL_PREFIX]),
"GENESIS_DELAY": $node.dag.cfg.GENESIS_DELAY,
"SECONDS_PER_SLOT": $SECONDS_PER_SLOT,
"MIN_ATTESTATION_INCLUSION_DELAY": $MIN_ATTESTATION_INCLUSION_DELAY,
@ -88,19 +87,19 @@ proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
"MAX_DEPOSITS": $MAX_DEPOSITS,
"MAX_VOLUNTARY_EXITS": $MAX_VOLUNTARY_EXITS,
"DOMAIN_BEACON_PROPOSER":
"0x" & ncrutils.toHex(uint32(DOMAIN_BEACON_PROPOSER).toBytesLE()),
to0xHex(DOMAIN_BEACON_PROPOSER.data),
"DOMAIN_BEACON_ATTESTER":
"0x" & ncrutils.toHex(uint32(DOMAIN_BEACON_ATTESTER).toBytesLE()),
to0xHex(DOMAIN_BEACON_ATTESTER.data),
"DOMAIN_RANDAO":
"0x" & ncrutils.toHex(uint32(DOMAIN_RANDAO).toBytesLE()),
to0xHex(DOMAIN_RANDAO.data),
"DOMAIN_DEPOSIT":
"0x" & ncrutils.toHex(uint32(DOMAIN_DEPOSIT).toBytesLE()),
to0xHex(DOMAIN_DEPOSIT.data),
"DOMAIN_VOLUNTARY_EXIT":
"0x" & ncrutils.toHex(uint32(DOMAIN_VOLUNTARY_EXIT).toBytesLE()),
to0xHex(DOMAIN_VOLUNTARY_EXIT.data),
"DOMAIN_SELECTION_PROOF":
"0x" & ncrutils.toHex(uint32(DOMAIN_SELECTION_PROOF).toBytesLE()),
to0xHex(DOMAIN_SELECTION_PROOF.data),
"DOMAIN_AGGREGATE_AND_PROOF":
"0x" & ncrutils.toHex(uint32(DOMAIN_AGGREGATE_AND_PROOF).toBytesLE())
to0xHex(DOMAIN_AGGREGATE_AND_PROOF.data)
}
rpcServer.rpc("get_v1_config_deposit_contract") do () -> JsonNode:

View File

@ -7,12 +7,13 @@
{.push raises: [Defect].}
import std/[options, sequtils],
import
std/[options, sequtils],
stew/byteutils,
chronicles,
json_rpc/servers/httpserver,
eth/p2p/discoveryv5/enr,
libp2p/[multiaddress, multicodec, peerstore],
nimcrypto/utils as ncrutils,
../beacon_node, ../version,
../networking/[eth2_network, peer_pool],
../sync/sync_manager,
@ -174,7 +175,7 @@ proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
p2p_addresses: p2pAddresses,
discovery_addresses: discoveryAddresses,
metadata: (node.network.metadata.seq_number,
"0x" & ncrutils.toHex(node.network.metadata.attnets.bytes))
to0xHex(node.network.metadata.attnets.bytes))
)
rpcServer.rpc("get_v1_node_peers") do (state: Option[seq[string]],

View File

@ -724,7 +724,7 @@ func get_next_sync_committee_keys(state: altair.BeaconState | bellatrix.BeaconSt
hash_buffer: array[40, byte]
hash_buffer[0..31] = seed.data
while index < SYNC_COMMITTEE_SIZE:
hash_buffer[32..39] = uint_to_bytes8(uint64(i div 32))
hash_buffer[32..39] = uint_to_bytes(uint64(i div 32))
let
shuffled_index = compute_shuffled_index(uint64(i mod active_validator_count), active_validator_count, seed)
candidate_index = active_validator_indices[shuffled_index]

View File

@ -30,8 +30,9 @@ import
stew/[endians2, objects, results, byteutils],
blscurve,
chronicles,
json_serialization,
nimcrypto/utils as ncrutils
json_serialization
from nimcrypto/utils import burnMem
export options, results, json_serialization, blscurve
@ -474,4 +475,4 @@ func infinity*(T: type ValidatorSig): T =
result.blob[0] = byte 0xC0
proc burnMem*(key: var ValidatorPrivKey) =
ncrutils.burnMem(addr key, sizeof(ValidatorPrivKey))
burnMem(addr key, sizeof(ValidatorPrivKey))

View File

@ -120,20 +120,7 @@ template maxSize*(n: int) {.pragma.}
type
# Domains
# ---------------------------------------------------------------
DomainType* = enum
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#domain-types
DOMAIN_BEACON_PROPOSER = 0
DOMAIN_BEACON_ATTESTER = 1
DOMAIN_RANDAO = 2
DOMAIN_DEPOSIT = 3
DOMAIN_VOLUNTARY_EXIT = 4
DOMAIN_SELECTION_PROOF = 5
DOMAIN_AGGREGATE_AND_PROOF = 6
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/altair/beacon-chain.md#domain-types
DOMAIN_SYNC_COMMITTEE = 7
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF = 8
DOMAIN_CONTRIBUTION_AND_PROOF = 9
DomainType* = distinct array[4, byte]
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#custom-types
Eth2Domain* = array[32, byte]
@ -526,6 +513,21 @@ type
# time of attestation.
previous_epoch_head_attesters_raw*: Gwei
const
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#domain-types
DOMAIN_BEACON_PROPOSER* = DomainType([byte 0x00, 0x00, 0x00, 0x00])
DOMAIN_BEACON_ATTESTER* = DomainType([byte 0x01, 0x00, 0x00, 0x00])
DOMAIN_RANDAO* = DomainType([byte 0x02, 0x00, 0x00, 0x00])
DOMAIN_DEPOSIT* = DomainType([byte 0x03, 0x00, 0x00, 0x00])
DOMAIN_VOLUNTARY_EXIT* = DomainType([byte 0x04, 0x00, 0x00, 0x00])
DOMAIN_SELECTION_PROOF* = DomainType([byte 0x05, 0x00, 0x00, 0x00])
DOMAIN_AGGREGATE_AND_PROOF* = DomainType([byte 0x06, 0x00, 0x00, 0x00])
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/altair/beacon-chain.md#domain-types
DOMAIN_SYNC_COMMITTEE* = DomainType([byte 0x07, 0x00, 0x00, 0x00])
DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF* = DomainType([byte 0x08, 0x00, 0x00, 0x00])
DOMAIN_CONTRIBUTION_AND_PROOF* = DomainType([byte 0x09, 0x00, 0x00, 0x00])
func getImmutableValidatorData*(validator: Validator): ImmutableValidatorData2 =
let cookedKey = validator.pubkey.load() # Loading the pubkey is slow!
doAssert cookedKey.isSome,
@ -607,22 +609,16 @@ proc readValue*(reader: var JsonReader, value: var SubnetId)
reader, "Subnet id must be <= " & $ATTESTATION_SUBNET_COUNT)
value = SubnetId(v)
template writeValue*(writer: var JsonWriter, value: Version | ForkDigest) =
writeValue(writer, $value)
template writeValue*(
writer: var JsonWriter, value: Version | ForkDigest | DomainType) =
writeValue(writer, to0xHex(distinctBase(value)))
proc readValue*(reader: var JsonReader, value: var Version)
proc readValue*(
reader: var JsonReader, value: var (Version | ForkDigest | DomainType))
{.raises: [IOError, SerializationError, Defect].} =
let hex = reader.readValue(string)
try:
hexToByteArray(hex, array[4, byte](value))
except ValueError:
raiseUnexpectedValue(reader, "Hex string of 4 bytes expected")
proc readValue*(reader: var JsonReader, value: var ForkDigest)
{.raises: [IOError, SerializationError, Defect].} =
let hex = reader.readValue(string)
try:
hexToByteArray(hex, array[4, byte](value))
hexToByteArray(hex, distinctBase(value))
except ValueError:
raiseUnexpectedValue(reader, "Hex string of 4 bytes expected")
@ -734,8 +730,8 @@ template newClone*[T](x: ref T not nil): ref T =
template lenu64*(x: untyped): untyped =
uint64(len(x))
func `$`*(v: ForkDigest | Version): string =
toHex(array[4, byte](v))
func `$`*(v: ForkDigest | Version | DomainType): string =
toHex(distinctBase(v))
func toGaugeValue*(x: uint64 | Epoch | Slot): int64 =
if x > uint64(int64.high):
@ -744,16 +740,17 @@ func toGaugeValue*(x: uint64 | Epoch | Slot): int64 =
int64(x)
# TODO where's borrow support when you need it
func `==`*(a, b: ForkDigest | Version): bool =
func `==`*(a, b: ForkDigest | Version | DomainType): bool =
array[4, byte](a) == array[4, byte](b)
func `<`*(a, b: ForkDigest | Version): bool =
uint32.fromBytesBE(array[4, byte](a)) < uint32.fromBytesBE(array[4, byte](b))
func len*(v: ForkDigest | Version): int = sizeof(v)
func len*(v: ForkDigest | Version | DomainType): int = sizeof(v)
func low*(v: ForkDigest | Version): int = 0
func high*(v: ForkDigest | Version): int = len(v) - 1
func `[]`*(v: ForkDigest | Version, idx: int): byte = array[4, byte](v)[idx]
func `[]`*(v: ForkDigest | Version | DomainType, idx: int): byte =
array[4, byte](v)[idx]
template bytes*(v: ForkDigest): array[4, byte] =
template data*(v: ForkDigest | Version | DomainType): array[4, byte] =
distinctBase(v)
func shortLog*(s: Slot): uint64 =

View File

@ -5,8 +5,8 @@
# 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, endians2], presto/common,
libp2p/peerid, nimcrypto/utils as ncrutils,
import stew/[assign2, results, base10, byteutils], presto/common,
libp2p/peerid,
serialization, json_serialization, json_serialization/std/[options, net, sets]
import ".."/[eth2_ssz_serialization, forks],
".."/datatypes/[phase0, altair, bellatrix],
@ -320,7 +320,7 @@ proc sszResponse*(t: typedesc[RestApiResponse], data: auto): RestApiResponse =
RestApiResponse.response(res, Http200, "application/octet-stream")
template hexOriginal(data: openarray[byte]): string =
"0x" & ncrutils.toHex(data, true)
to0xHex(data)
proc decodeJsonString*[T](t: typedesc[T],
data: JsonString,
@ -384,25 +384,6 @@ proc readValue*(reader: var JsonReader[RestJson], value: var UInt256) {.
raiseUnexpectedValue(reader,
"UInt256 value should be a valid decimal string")
## DomainType
proc writeValue*(w: var JsonWriter[RestJson], value: DomainType) {.
raises: [IOError, Defect].} =
writeValue(w, hexOriginal(uint32(value).toBytesLE()))
proc readValue*(reader: var JsonReader[RestJson], value: var DomainType) {.
raises: [IOError, SerializationError, Defect].} =
try:
let
data = hexToByteArray(reader.readValue(string), 4)
res = uint32.fromBytesLE(data)
if res >= uint32(low(DomainType)) and res <= uint32(high(DomainType)):
value = cast[DomainType](res)
else:
raiseUnexpectedValue(reader, "Incorrect DomainType value")
except ValueError:
raiseUnexpectedValue(reader,
"DomainType value should be a valid hex string")
## Slot
proc writeValue*(writer: var JsonWriter[RestJson], value: Slot) {.
raises: [IOError, Defect].} =
@ -648,43 +629,15 @@ proc writeValue*(writer: var JsonWriter[RestJson], value: Eth1Address) {.
writeValue(writer, hexOriginal(distinctBase(value)))
## Version
proc readValue*(reader: var JsonReader[RestJson], value: var 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,
"Version value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: Version) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
## ForkDigest
proc readValue*(reader: var JsonReader[RestJson], value: var ForkDigest) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), distinctBase(value))
except ValueError:
raiseUnexpectedValue(reader,
"ForkDigest value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: ForkDigest) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
## GraffitiBytes
proc readValue*(reader: var JsonReader[RestJson], value: var GraffitiBytes) {.
raises: [IOError, SerializationError, Defect].} =
try:
hexToByteArray(reader.readValue(string), distinctBase(value))
except ValueError:
raiseUnexpectedValue(reader,
"GraffitiBytes value should be a valid hex string")
proc writeValue*(writer: var JsonWriter[RestJson], value: GraffitiBytes) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
raiseUnexpectedValue(
reader, "Expected a valid hex string with " & $value.len() & " bytes")
## ForkedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],

View File

@ -424,19 +424,10 @@ func bytes_to_uint64*(data: openArray[byte]): uint64 =
# Little-endian data representation
uint64.fromBytesLE(data)
# Have 1, 4, and 8-byte versions. Spec only defines 8-byte version, but useful
# to check invariants on rest.
func uint_to_bytes8*(x: uint64): array[8, byte] =
x.toBytesLE()
func uint_to_bytes4*(x: uint64): array[4, byte] =
doAssert x < 2'u64^32
# Little-endian data representation
result[0] = ((x shr 0) and 0xff).byte
result[1] = ((x shr 8) and 0xff).byte
result[2] = ((x shr 16) and 0xff).byte
result[3] = ((x shr 24) and 0xff).byte
func uint_to_bytes*(x: uint64): array[8, byte] = toBytesLE(x)
func uint_to_bytes*(x: uint32): array[4, byte] = toBytesLE(x)
func uint_to_bytes*(x: uint16): array[2, byte] = toBytesLE(x)
func uint_to_bytes*(x: uint8): array[1, byte] = toBytesLE(x)
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#compute_domain
func compute_domain*(
@ -446,7 +437,7 @@ func compute_domain*(
## Return the domain for the ``domain_type`` and ``fork_version``.
let fork_data_root =
compute_fork_data_root(fork_version, genesis_validators_root)
result[0..3] = uint_to_bytes4(domain_type.uint64)
result[0..3] = domain_type.data
result[4..31] = fork_data_root.data.toOpenArray(0, 27)
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#get_domain
@ -491,8 +482,8 @@ func get_seed*(state: ForkyBeaconState, epoch: Epoch, domain_type: DomainType):
static:
doAssert EPOCHS_PER_HISTORICAL_VECTOR > MIN_SEED_LOOKAHEAD
seed_input[0..3] = uint_to_bytes4(domain_type.uint64)
seed_input[4..11] = uint_to_bytes8(epoch.uint64)
seed_input[0..3] = domain_type.data
seed_input[4..11] = uint_to_bytes(epoch.uint64)
seed_input[12..43] =
get_randao_mix(state, # Avoid underflow
epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD - 1).data

View File

@ -9,10 +9,7 @@
import
std/[macros, strutils, parseutils, tables],
stew/endians2, stint, web3/[ethtypes]
export
toBytesBE
stew/[byteutils], stint, web3/[ethtypes]
const
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#withdrawal-prefixes
@ -376,7 +373,7 @@ template parse(T: type byte, input: string): T =
func parse(T: type Version, input: string): T
{.raises: [ValueError, Defect].} =
Version toBytesBE(uint32 parse(uint64, input))
Version hexToByteArray(input, 4)
template parse(T: type Slot, input: string): T =
Slot parse(uint64, input)

View File

@ -48,7 +48,7 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
# and take a uint64 from it, and modulo it to get a pivot within range.
let
pivotDigest = eth2digest(buf.toOpenArray(0, PIVOT_VIEW_SIZE - 1))
pivot = bytes_to_uint64(pivotDigest.data.toOpenArray(0, 7)) mod listSize
pivot = bytes_to_uint64(pivotDigest.data.toOpenArray(0, 7)) mod list_size
# Split up the for-loop in two:
# 1. Handle the part from 0 (incl) to pivot (incl). This is mirrored around
@ -77,7 +77,7 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
# (of the part left to the pivot).
# This makes us process each pear exactly once (instead of unnecessarily
# twice, like in the spec)
buf[33..<37] = uint_to_bytes4(pivot shr 8)
buf[33..<37] = uint_to_bytes(uint32(pivot shr 8))
var
mirror = (pivot + 1) shr 1
@ -92,7 +92,7 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
# Every 256th bit (aligned to j).
if (j and 0xff) == 0xff:
# just overwrite the last part of the buffer, reuse the start (seed, round)
buf[33..<37] = uint_to_bytes4(j shr 8)
buf[33..<37] = uint_to_bytes(uint32(j shr 8))
source = eth2digest(buf)
# Same trick with byte retrieval. Only every 8th.
@ -116,7 +116,7 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
# Again, seed and round input is in place, just update the position.
# We start at the end, and work back to the mirror point.
# This makes us process each pear exactly once (instead of unnecessarily twice, like in the spec)
buf[33..<37] = uint_to_bytes4(lend shr 8)
buf[33..<37] = uint_to_bytes(uint32(lend shr 8))
source = eth2digest(buf)
byteV = source.data[(lend and 0xff) shr 3]
@ -344,7 +344,7 @@ func compute_shuffled_index*(
flip = ((index_count + pivot) - cur_idx_permuted) mod index_count
position = max(cur_idx_permuted, flip)
source_buffer[33..36] = uint_to_bytes4((position shr 8))
source_buffer[33..36] = uint_to_bytes(uint32(position shr 8))
let
source = eth2digest(source_buffer).data
byte_value = source[(position mod 256) shr 3]
@ -370,7 +370,7 @@ func compute_proposer_index(state: ForkyBeaconState,
buffer: array[32+8, byte]
buffer[0..31] = seed.data
while true:
buffer[32..39] = uint_to_bytes8(i div 32)
buffer[32..39] = uint_to_bytes(i div 32)
let
candidate_index =
indices[compute_shuffled_index(i mod seq_len, seq_len, seed)]
@ -411,7 +411,7 @@ func get_beacon_proposer_index*(
var res: Option[ValidatorIndex]
for i in 0..<SLOTS_PER_EPOCH:
buffer[32..39] = uint_to_bytes8((start + i).uint64)
buffer[32..39] = uint_to_bytes((start + i).uint64)
let seed = eth2digest(buffer)
let pi = compute_proposer_index(state, indices, seed)
if start + i == slot:

View File

@ -96,15 +96,15 @@ proc sendResponseChunk*(response: UntypedResponse,
of BeaconBlockFork.Phase0:
response.stream.writeChunk(some ResponseCode.Success,
SSZ.encode(val.phase0Data),
response.peer.network.forkDigests.phase0.bytes)
response.peer.network.forkDigests.phase0.data)
of BeaconBlockFork.Altair:
response.stream.writeChunk(some ResponseCode.Success,
SSZ.encode(val.altairData),
response.peer.network.forkDigests.altair.bytes)
response.peer.network.forkDigests.altair.data)
of BeaconBlockFork.Bellatrix:
response.stream.writeChunk(some ResponseCode.Success,
SSZ.encode(val.mergeData),
response.peer.network.forkDigests.bellatrix.bytes)
response.peer.network.forkDigests.bellatrix.data)
func shortLog*(s: StatusMsg): auto =
(

View File

@ -2,10 +2,12 @@
The `JSON-RPC API` is a collection of APIs for querying the state of the application at runtime.
The API is based on the common [eth2 APIs](https://github.com/ethereum/eth2.0-APIs) with the exception that `JSON-RPC` is used instead of [http `REST`](./rest-api.md) (the method names, parameters and results are all the same except for the encoding / access method).
The API is based on an early version of the common [beacon APIs](https://github.com/ethereum/beacon-APIs) with the exception that `JSON-RPC` is used instead of [http `REST`](./rest-api.md) (the method names, parameters and results are all the same except for the encoding / access method).
Nimbus also implements the [common REST API](./rest-api.md) - new applications should consider using it instead of JSON RPC.
The `JSON-RPC API` should not be exposed to the public internet.
## Introduction
The `nimbus-eth2` API is implemented using JSON-RPC 2.0. To query it, you can use a JSON-RPC library in the language of your choice, or a tool like `curl` to access it from the command line. A tool like [jq](https://stedolan.github.io/jq/) is helpful to pretty-print the responses.

View File

@ -1,21 +1,24 @@
# REST API
Nimbus supports the [common REST API](https://ethereum.github.io/beacon-APIs/) for runtime communication. To enable it, use the `--rest` option when starting the beacon node, then access the API from http://localhost:5052/. The port and listening address can be further configured through the options `--rest-port` and `--rest-address`.
Nimbus exposes a high-performance implementation of the [Beacon Node API](https://ethereum.github.io/beacon-APIs/).
The API is a REST interface, accessed via HTTP. The API should not, unless protected by additional security layers, be exposed to the public Internet as the API includes multiple endpoints which could open your node to denial-of-service (DoS) attacks through endpoints triggering heavy processing.
The API is a `REST` interface accessed via `HTTP`. The API should not, unless protected by additional security layers, be exposed to the public Internet as the API includes multiple endpoints which could open your node to denial-of-service (DoS) attacks.
The beacon node (BN) maintains the state of the beacon chain by communicating with other beacon nodes in the Ethereum network. Conceptually, it does not maintain keypairs that participate with the beacon chain.
The API can be used with any conforming consumer, including alternative validator client implementations, explorers and tooling.
The validator client (VC) is a conceptually separate entity which utilizes private keys to perform validator related tasks, called "duties", on the beacon chain. These duties include the production of beacon blocks and signing of attestations.
## Configuration
> Please note that using a validator client with a Nimbus beacon node requires the node to be launched with the `--subscribe-all-subnets` option. This limitation will be removed in Nimbus 1.6.
By default, the REST interface is disabled. To enable it, start the beacon node with the `--rest` option, then access the API from http://localhost:5052/.
The goal of this specification is to promote interoperability between various beacon node implementations.
> **Warning:** If you are using a validator client with a Nimbus beacon node, and running a Nimbus version prior to `v1.5.5`, then you will need to launch the node with the `--subscribe-all-subnets` option enabled.
By default, only connections from the same machine are entertained. The port and listening address can be further configured through the options `--rest-port` and `--rest-address`.
## Specification
The specification is documented [here](https://ethereum.github.io/beacon-APIs/).
See the Readme [here](https://github.com/ethereum/beacon-apis).
See the Readme [here](https://github.com/ethereum/beacon-APIs).
## Quickly test your tooling against Nimbus
@ -25,7 +28,4 @@ See the Readme [here](https://github.com/ethereum/beacon-apis).
* http://unstable.mainnet.beacon-api.nimbus.team/
* http://unstable.prater.beacon-api.nimbus.team/
Note that right now these are very much unstable testing instances. They may be unresponsive at times - so **please do not rely on them for validation**. We may also disable them at any time.

View File

@ -1037,7 +1037,7 @@
},
"response": {
"status": {"operator": "oneof", "value": ["404", "200"]},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}]
}
},
{
@ -1139,7 +1139,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -1150,7 +1150,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -1161,7 +1161,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -1172,7 +1172,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -1183,7 +1183,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -1270,7 +1270,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "oneof", "value": ["400", "200"]},
"status": {"operator": "oneof", "value": ["400", "200"]}
}
},
{
@ -1489,18 +1489,6 @@
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "slot": "", "validators": [""]}]}]
}
},
{
"topics": ["beacon", "states_committees"],
"request": {
"url": "/eth/v1/beacon/states/head/committees?slot=18446744073709551615",
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "200"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "slot": "", "validators": [""]}]}]
}
},
{
"topics": ["beacon", "states_committees"],
"request": {
@ -1525,18 +1513,6 @@
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "slot": "", "validators": [""]}]}]
}
},
{
"topics": ["beacon", "states_committees"],
"request": {
"url": "/eth/v1/beacon/states/head/committees?epoch=576460752303423487",
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "200"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "slot": "", "validators": [""]}]}]
}
},
{
"topics": ["beacon", "states_committees"],
"request": {
@ -2939,19 +2915,6 @@
"body": [{"operator": "jstructcmps", "value": {"dependent_root": "", "data": [{"pubkey": "", "validator_index": "", "slot": ""}]}}]
}
},
{
"topics": ["validator", "proposer_duties", "mainnet"],
"comment": "Maximum epoch for mainnet parameters",
"request": {
"url": "/eth/v1/validator/duties/proposer/576460752303423487",
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "503"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
}
},
{
"topics": ["validator", "proposer_duties", "mainnet"],
"comment": "Maximum epoch + 1 for mainnet parameters",
@ -3138,7 +3101,7 @@
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "oneof", "value": ["400", "200"]},
"status": {"operator": "oneof", "value": ["400", "200"]}
}
},
{
@ -3188,24 +3151,10 @@
"request": {
"method": "POST",
"url": "/eth/v1/validator/duties/attester/0",
"headers": {"Accept": "application/json"},
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"},
}
},
{
"topics": ["validator", "attester_duties"],
"request": {
"url": "/eth/v1/validator/duties/attester/576460752303423487",
"method": "POST",
"headers": {"Accept": "application/json"},
"body": {"content-type": "application/json", "data": "[\"0\"]"}
},
"response": {
"status": {"operator": "equals", "value": "503"},
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
"status": {"operator": "equals", "value": "400"}
}
},
{
@ -3255,7 +3204,7 @@
"request": {
"url": "/eth/v1/validator/duties/attester/foobar",
"method": "POST",
"headers": {"Accept": "application/json"},
"headers": {"Accept": "application/json"}
},
"response": {
"status": {"operator": "equals", "value": "400"}

View File

@ -1041,7 +1041,8 @@ proc startTests(conf: RestTesterConf, uri: Uri,
let tcaseRes = fut.read()
results[tcaseRes.index] = tcaseRes.data
notice "Got test result", index = tcaseRes.index,
notice "Got test result", name = rules[tcaseRes.index].getTestName(),
index = tcaseRes.index,
value = tcaseRes.data.kind
pending[i] = nil

View File

@ -59,6 +59,10 @@ suite "BlockSlot and helpers":
s1 = BlockRef(bid: BlockId(slot: Slot(1)), parent: s0)
s2 = BlockRef(bid: BlockId(slot: Slot(2)), parent: s1)
s4 = BlockRef(bid: BlockId(slot: Slot(4)), parent: s2)
se1 = BlockRef(bid:
BlockId(slot: Epoch(1).compute_start_slot_at_epoch()), parent: s2)
se2 = BlockRef(bid:
BlockId(slot: Epoch(2).compute_start_slot_at_epoch()), parent: se1)
check:
s0.atSlot(Slot(0)).blck == s0
@ -69,6 +73,14 @@ suite "BlockSlot and helpers":
s4.atSlot() == s4.atSlot(s4.slot)
se2.dependentBlock(s0, Epoch(2)) == se1
se2.dependentBlock(s0, Epoch(1)) == s2
se2.dependentBlock(s0, Epoch(0)) == s0
se2.prevDependentBlock(s0, Epoch(2)) == s2
se2.prevDependentBlock(s0, Epoch(1)) == s0
se2.prevDependentBlock(s0, Epoch(0)) == s0
test "parent sanity":
let
s0 = BlockRef(bid: BlockId(slot: Slot(0)))

2
vendor/nim-stew vendored

@ -1 +1 @@
Subproject commit 543c7edbc710a3f9d329e094499159a315ee4905
Subproject commit 17cd8c846fd6238f074b67875d17617c90ccace5