mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-19 17:58:23 +00:00
move state_transition
to Result
(#3284)
* better error messages in api * avoid `BlockData` copies when replaying blocks
This commit is contained in:
parent
68247f81b3
commit
836f6984bb
@ -109,14 +109,14 @@ proc checkStateTransition(
|
||||
doAssert v.addr == addr dag.clearanceState.data
|
||||
assign(dag.clearanceState, dag.headState)
|
||||
|
||||
logScope:
|
||||
blockRoot = shortLog(signedBlock.root)
|
||||
blck = shortLog(signedBlock.message)
|
||||
|
||||
if not state_transition_block(
|
||||
let res = state_transition_block(
|
||||
dag.cfg, dag.clearanceState.data, signedBlock,
|
||||
cache, dag.updateFlags, restore):
|
||||
info "Invalid block"
|
||||
cache, dag.updateFlags, restore)
|
||||
if res.isErr():
|
||||
info "Invalid block",
|
||||
blockRoot = shortLog(signedBlock.root),
|
||||
blck = shortLog(signedBlock.message),
|
||||
error = res.error()
|
||||
|
||||
err(BlockError.Invalid)
|
||||
else:
|
||||
|
@ -810,9 +810,8 @@ proc getForkedBlock*(dag: ChainDAGRef, id: BlockId): Opt[ForkedTrustedSignedBeac
|
||||
return ok ForkedTrustedSignedBeaconBlock.init(data.get)
|
||||
|
||||
proc getForkedBlock*(dag: ChainDAGRef, blck: BlockRef): ForkedTrustedSignedBeaconBlock =
|
||||
let blck = dag.getForkedBlock(blck.bid)
|
||||
if blck.isSome():
|
||||
return blck.get()
|
||||
dag.getForkedBlock(blck.bid).expect(
|
||||
"BlockRef block should always load, database corrupt?")
|
||||
|
||||
proc get*(dag: ChainDAGRef, blck: BlockRef): BlockData =
|
||||
## Retrieve the associated block body of a block reference
|
||||
@ -841,10 +840,9 @@ proc advanceSlots(
|
||||
let preEpoch = getStateField(state.data, slot).epoch
|
||||
loadStateCache(dag, cache, state.blck, getStateField(state.data, slot).epoch)
|
||||
|
||||
doAssert process_slots(
|
||||
dag.cfg, state.data, getStateField(state.data, slot) + 1, cache, info,
|
||||
dag.updateFlags),
|
||||
"process_slots shouldn't fail when state slot is correct"
|
||||
process_slots(
|
||||
dag.cfg, state.data, getStateField(state.data, slot) + 1, cache, info,
|
||||
dag.updateFlags).expect("process_slots shouldn't fail when state slot is correct")
|
||||
if save:
|
||||
dag.putState(state)
|
||||
|
||||
@ -860,28 +858,36 @@ proc advanceSlots(
|
||||
|
||||
proc applyBlock(
|
||||
dag: ChainDAGRef,
|
||||
state: var StateData, blck: BlockData, flags: UpdateFlags,
|
||||
cache: var StateCache, info: var ForkedEpochInfo): bool =
|
||||
state: var StateData, blck: BlockRef, flags: UpdateFlags,
|
||||
cache: var StateCache, info: var ForkedEpochInfo) =
|
||||
# Apply a single block to the state - the state must be positioned at the
|
||||
# parent of the block with a slot lower than the one of the block being
|
||||
# applied
|
||||
doAssert state.blck == blck.refs.parent
|
||||
|
||||
var statePtr = unsafeAddr state # safe because `restore` is locally scoped
|
||||
func restore(v: var ForkedHashedBeaconState) =
|
||||
doAssert (addr(statePtr.data) == addr v)
|
||||
assign(statePtr[], dag.headState)
|
||||
doAssert state.blck == blck.parent
|
||||
|
||||
loadStateCache(dag, cache, state.blck, getStateField(state.data, slot).epoch)
|
||||
|
||||
let ok = withBlck(blck.data):
|
||||
case dag.cfg.blockForkAtEpoch(blck.slot.epoch)
|
||||
of BeaconBlockFork.Phase0:
|
||||
let data = dag.db.getPhase0Block(blck.root).expect("block loaded")
|
||||
state_transition(
|
||||
dag.cfg, state.data, blck, cache, info,
|
||||
flags + dag.updateFlags + {slotProcessed}, restore)
|
||||
if ok:
|
||||
state.blck = blck.refs
|
||||
dag.cfg, state.data, data, cache, info,
|
||||
flags + dag.updateFlags + {slotProcessed}, noRollback).expect(
|
||||
"Blocks from database must not fail to apply")
|
||||
of BeaconBlockFork.Altair:
|
||||
let data = dag.db.getAltairBlock(blck.root).expect("block loaded")
|
||||
state_transition(
|
||||
dag.cfg, state.data, data, cache, info,
|
||||
flags + dag.updateFlags + {slotProcessed}, noRollback).expect(
|
||||
"Blocks from database must not fail to apply")
|
||||
of BeaconBlockFork.Bellatrix:
|
||||
let data = dag.db.getMergeBlock(blck.root).expect("block loaded")
|
||||
state_transition(
|
||||
dag.cfg, state.data, data, cache, info,
|
||||
flags + dag.updateFlags + {slotProcessed}, noRollback).expect(
|
||||
"Blocks from database must not fail to apply")
|
||||
|
||||
ok
|
||||
state.blck = blck
|
||||
|
||||
proc updateStateData*(
|
||||
dag: ChainDAGRef, state: var StateData, bs: BlockSlot, save: bool,
|
||||
@ -1034,9 +1040,7 @@ proc updateStateData*(
|
||||
# again. Also, because we're applying blocks that were loaded from the
|
||||
# database, we can skip certain checks that have already been performed
|
||||
# before adding the block to the database.
|
||||
let ok =
|
||||
dag.applyBlock(state, dag.get(ancestors[i]), {}, cache, info)
|
||||
doAssert ok, "Blocks in database should never fail to apply.."
|
||||
dag.applyBlock(state, ancestors[i], {}, cache, info)
|
||||
|
||||
# ...and make sure to process empty slots as requested
|
||||
dag.advanceSlots(state, bs.slot, save, cache, info)
|
||||
|
@ -41,12 +41,11 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
|
||||
if proposer.isNone():
|
||||
raise newException(CatchableError,
|
||||
"could not retrieve block for slot: " & $slot)
|
||||
let message = await makeBeaconBlockForHeadAndSlot(
|
||||
let res = await makeBeaconBlockForHeadAndSlot(
|
||||
node, randao_reveal, proposer.get(), graffiti, head, slot)
|
||||
if message.isErr():
|
||||
raise newException(CatchableError,
|
||||
"could not retrieve block for slot: " & $slot)
|
||||
let blck = message.get()
|
||||
if res.isErr():
|
||||
raise newException(CatchableError, res.error())
|
||||
let blck = res.get()
|
||||
case blck.kind
|
||||
of BeaconBlockFork.Phase0:
|
||||
return blck.phase0Data
|
||||
|
@ -66,6 +66,11 @@ type
|
||||
altair.BeaconBlock |
|
||||
bellatrix.BeaconBlock
|
||||
|
||||
ForkySigVerifiedBeaconBlock* =
|
||||
phase0.SigVerifiedBeaconBlock |
|
||||
altair.SigVerifiedBeaconBlock |
|
||||
bellatrix.SigVerifiedBeaconBlock
|
||||
|
||||
ForkyTrustedBeaconBlock* =
|
||||
phase0.TrustedBeaconBlock |
|
||||
altair.TrustedBeaconBlock |
|
||||
|
@ -43,76 +43,47 @@
|
||||
import
|
||||
chronicles,
|
||||
stew/results,
|
||||
metrics,
|
||||
../extras,
|
||||
./datatypes/[phase0, altair, bellatrix],
|
||||
"."/[
|
||||
beaconstate, eth2_merkleization, forks, helpers, signatures,
|
||||
state_transition_block, state_transition_epoch, validator]
|
||||
|
||||
export extras, phase0, altair, bellatrix
|
||||
export results, extras, phase0, altair, bellatrix
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc verify_block_signature(
|
||||
#state: ForkyBeaconState, signed_block: SomeSomeSignedBeaconBlock): bool =
|
||||
state: ForkyBeaconState, signed_block: SomeForkySignedBeaconBlock): bool =
|
||||
state: ForkyBeaconState, signed_block: SomeForkySignedBeaconBlock):
|
||||
Result[void, cstring] =
|
||||
let
|
||||
proposer_index = signed_block.message.proposer_index
|
||||
if proposer_index >= state.validators.lenu64:
|
||||
notice "Invalid proposer index in block",
|
||||
blck = shortLog(signed_block.message)
|
||||
return false
|
||||
return err("block: invalid proposer index")
|
||||
|
||||
if not verify_block_signature(
|
||||
state.fork, state.genesis_validators_root, signed_block.message.slot,
|
||||
signed_block.root, state.validators[proposer_index].pubkey,
|
||||
signed_block.signature):
|
||||
notice "Block: signature verification failed",
|
||||
blck = shortLog(signedBlock)
|
||||
return false
|
||||
return err("block: signature verification failed")
|
||||
|
||||
true
|
||||
ok()
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc verifyStateRoot(state: ForkyBeaconState, blck: phase0.BeaconBlock or phase0.SigVerifiedBeaconBlock or altair.BeaconBlock or altair.SigVerifiedBeaconBlock or bellatrix.BeaconBlock or bellatrix.SigVerifiedBeaconBlock or bellatrix.TrustedBeaconBlock): bool =
|
||||
proc verifyStateRoot(
|
||||
state: ForkyBeaconState, blck: ForkyBeaconBlock | ForkySigVerifiedBeaconBlock):
|
||||
Result[void, cstring] =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
let state_root = hash_tree_root(state)
|
||||
if state_root != blck.state_root:
|
||||
notice "Block: root verification failed",
|
||||
block_state_root = shortLog(blck.state_root), state_root = shortLog(state_root)
|
||||
false
|
||||
err("block: state root verification failed")
|
||||
else:
|
||||
true
|
||||
ok()
|
||||
|
||||
func verifyStateRoot(state: phase0.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
func verifyStateRoot(
|
||||
state: ForkyBeaconState, blck: ForkyTrustedBeaconBlock):
|
||||
Result[void, cstring] =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
func verifyStateRoot(state: altair.BeaconState, blck: altair.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
func verifyStateRoot(state: bellatrix.BeaconState, blck: bellatrix.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
# one of these can happen on the fork block itself (it's a phase 0 block which
|
||||
# creates an Altair state)
|
||||
func verifyStateRoot(state: altair.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
func verifyStateRoot(state: bellatrix.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
func verifyStateRoot(state: bellatrix.BeaconState, blck: altair.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
func verifyStateRoot(state: phase0.BeaconState, blck: altair.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
ok()
|
||||
|
||||
type
|
||||
RollbackProc* = proc() {.gcsafe, raises: [Defect].}
|
||||
@ -213,14 +184,11 @@ proc maybeUpgradeState*(
|
||||
|
||||
proc process_slots*(
|
||||
cfg: RuntimeConfig, state: var ForkedHashedBeaconState, slot: Slot,
|
||||
cache: var StateCache, info: var ForkedEpochInfo, flags: UpdateFlags): bool =
|
||||
cache: var StateCache, info: var ForkedEpochInfo, flags: UpdateFlags):
|
||||
Result[void, cstring] =
|
||||
if not (getStateField(state, slot) < slot):
|
||||
if slotProcessed notin flags or getStateField(state, slot) != slot:
|
||||
notice "Unusual request for a slot in the past",
|
||||
state_root = shortLog(getStateRoot(state)),
|
||||
current_slot = getStateField(state, slot),
|
||||
target_slot = slot
|
||||
return false
|
||||
return err("process_slots: cannot rewind state to past slot")
|
||||
|
||||
# Update the state so its slot matches that of the block
|
||||
while getStateField(state, slot) < slot:
|
||||
@ -237,43 +205,28 @@ proc process_slots*(
|
||||
|
||||
maybeUpgradeState(cfg, state)
|
||||
|
||||
true
|
||||
ok()
|
||||
|
||||
proc state_transition_block_aux(
|
||||
cfg: RuntimeConfig,
|
||||
state: var ForkyHashedBeaconState,
|
||||
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
|
||||
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock |
|
||||
altair.SigVerifiedSignedBeaconBlock | altair.TrustedSignedBeaconBlock |
|
||||
bellatrix.TrustedSignedBeaconBlock | bellatrix.SigVerifiedSignedBeaconBlock |
|
||||
bellatrix.SignedBeaconBlock,
|
||||
cache: var StateCache, flags: UpdateFlags): bool =
|
||||
signedBlock: SomeForkySignedBeaconBlock,
|
||||
cache: var StateCache, flags: UpdateFlags): Result[void, cstring] =
|
||||
# Block updates - these happen when there's a new block being suggested
|
||||
# by the block proposer. Every actor in the network will update its state
|
||||
# according to the contents of this block - but first they will validate
|
||||
# that the block is sane.
|
||||
if not (skipBLSValidation in flags or
|
||||
verify_block_signature(state.data, signedBlock)):
|
||||
return false
|
||||
if skipBLSValidation notin flags:
|
||||
? verify_block_signature(state.data, signedBlock)
|
||||
|
||||
trace "state_transition: processing block, signature passed",
|
||||
signature = shortLog(signedBlock.signature),
|
||||
blockRoot = shortLog(signedBlock.root)
|
||||
|
||||
let res = process_block(cfg, state.data, signedBlock.message, flags, cache)
|
||||
? process_block(cfg, state.data, signedBlock.message, flags, cache)
|
||||
|
||||
if not res.isOk():
|
||||
debug "state_transition: process_block failed",
|
||||
blck = shortLog(signedBlock.message),
|
||||
slot = state.data.slot,
|
||||
eth1_deposit_index = state.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
return false
|
||||
|
||||
if not (skipStateRootValidation in flags or
|
||||
verifyStateRoot(state.data, signedBlock.message)):
|
||||
return false
|
||||
if skipStateRootValidation notin flags:
|
||||
? verifyStateRoot(state.data, signedBlock.message)
|
||||
|
||||
# only blocks currently being produced have an empty state root - we use a
|
||||
# separate function for those
|
||||
@ -281,7 +234,7 @@ proc state_transition_block_aux(
|
||||
"see makeBeaconBlock for block production"
|
||||
state.root = signedBlock.message.state_root
|
||||
|
||||
true
|
||||
ok()
|
||||
|
||||
type
|
||||
RollbackForkedHashedProc* =
|
||||
@ -293,13 +246,9 @@ func noRollback*(state: var ForkedHashedBeaconState) =
|
||||
proc state_transition_block*(
|
||||
cfg: RuntimeConfig,
|
||||
state: var ForkedHashedBeaconState,
|
||||
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
|
||||
phase0.TrustedSignedBeaconBlock |
|
||||
altair.SignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock |
|
||||
altair.TrustedSignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock |
|
||||
bellatrix.SigVerifiedSignedBeaconBlock | bellatrix.SignedBeaconBlock,
|
||||
signedBlock: SomeForkySignedBeaconBlock,
|
||||
cache: var StateCache, flags: UpdateFlags,
|
||||
rollback: RollbackForkedHashedProc): bool =
|
||||
rollback: RollbackForkedHashedProc): Result[void, cstring] =
|
||||
## `rollback` is called if the transition fails and the given state has been
|
||||
## partially changed. If a temporary state was given to `state_transition`,
|
||||
## it is safe to use `noRollback` and leave it broken, else the state
|
||||
@ -310,21 +259,20 @@ proc state_transition_block*(
|
||||
# Ensure state_transition_block()-only callers trigger this
|
||||
maybeUpgradeStateToAltair(cfg, state)
|
||||
|
||||
let success = withState(state):
|
||||
let res = withState(state):
|
||||
state_transition_block_aux(cfg, state, signedBlock, cache, flags)
|
||||
|
||||
if not success:
|
||||
if res.isErr():
|
||||
rollback(state)
|
||||
return false
|
||||
|
||||
true
|
||||
res
|
||||
|
||||
proc state_transition*(
|
||||
cfg: RuntimeConfig,
|
||||
state: var ForkedHashedBeaconState,
|
||||
signedBlock: SomeForkySignedBeaconBlock,
|
||||
cache: var StateCache, info: var ForkedEpochInfo, flags: UpdateFlags,
|
||||
rollback: RollbackForkedHashedProc): bool =
|
||||
rollback: RollbackForkedHashedProc): Result[void, cstring] =
|
||||
## Apply a block to the state, advancing the slot counter as necessary. The
|
||||
## given state must be of a lower slot, or, in case the `slotProcessed` flag
|
||||
## is set, can be the slot state of the same slot as the block (where the
|
||||
@ -340,10 +288,10 @@ proc state_transition*(
|
||||
## it is safe to use `noRollback` and leave it broken, else the state
|
||||
## object should be rolled back to a consistent state. If the transition fails
|
||||
## before the state has been updated, `rollback` will not be called.
|
||||
if not process_slots(
|
||||
? process_slots(
|
||||
cfg, state, signedBlock.message.slot, cache, info,
|
||||
flags + {skipLastStateRootCalculation}):
|
||||
return false
|
||||
flags + {skipLastStateRootCalculation})
|
||||
|
||||
state_transition_block(
|
||||
cfg, state, signedBlock, cache, flags, rollback)
|
||||
|
||||
@ -359,7 +307,7 @@ template partialBeaconBlock(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload): phase0.BeaconBlock =
|
||||
execution_payload: ExecutionPayload): phase0.BeaconBlock =
|
||||
phase0.BeaconBlock(
|
||||
slot: state.data.slot,
|
||||
proposer_index: proposer_index.uint64,
|
||||
@ -385,9 +333,9 @@ proc makeBeaconBlock*(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload,
|
||||
execution_payload: ExecutionPayload,
|
||||
rollback: RollbackHashedProc,
|
||||
cache: var StateCache): Result[phase0.BeaconBlock, string] =
|
||||
cache: var StateCache): Result[phase0.BeaconBlock, cstring] =
|
||||
## Create a block for the given state. The latest block applied to it will
|
||||
## be used for the parent_root value, and the slot will be take from
|
||||
## state.slot meaning process_slots must be called up to the slot for which
|
||||
@ -403,17 +351,12 @@ proc makeBeaconBlock*(
|
||||
let res = process_block(cfg, state.data, blck, {skipBlsValidation}, cache)
|
||||
|
||||
if res.isErr:
|
||||
warn "Unable to apply new block to state",
|
||||
blck = shortLog(blck),
|
||||
slot = state.data.slot,
|
||||
eth1_deposit_index = state.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
rollback(state)
|
||||
return err("Unable to apply new block to state: " & $res.error())
|
||||
return err(res.error())
|
||||
|
||||
state.root = hash_tree_root(state.data)
|
||||
blck.state_root = state.root
|
||||
|
||||
ok(blck)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.8/specs/altair/validator.md#preparing-a-beaconblock
|
||||
@ -428,7 +371,7 @@ template partialBeaconBlock(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload): altair.BeaconBlock =
|
||||
execution_payload: ExecutionPayload): altair.BeaconBlock =
|
||||
altair.BeaconBlock(
|
||||
slot: state.data.slot,
|
||||
proposer_index: proposer_index.uint64,
|
||||
@ -455,9 +398,9 @@ proc makeBeaconBlock*(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload,
|
||||
execution_payload: ExecutionPayload,
|
||||
rollback: RollbackAltairHashedProc,
|
||||
cache: var StateCache): Result[altair.BeaconBlock, string] =
|
||||
cache: var StateCache): Result[altair.BeaconBlock, cstring] =
|
||||
## Create a block for the given state. The latest block applied to it will
|
||||
## be used for the parent_root value, and the slot will be take from
|
||||
## state.slot meaning process_slots must be called up to the slot for which
|
||||
@ -468,22 +411,17 @@ proc makeBeaconBlock*(
|
||||
|
||||
var blck = partialBeaconBlock(cfg, state, proposer_index,
|
||||
randao_reveal, eth1_data, graffiti, attestations, deposits,
|
||||
exits, sync_aggregate, executionPayload)
|
||||
exits, sync_aggregate, execution_payload)
|
||||
|
||||
let res = process_block(cfg, state.data, blck, {skipBlsValidation}, cache)
|
||||
|
||||
if res.isErr:
|
||||
warn "Unable to apply new block to state",
|
||||
blck = shortLog(blck),
|
||||
slot = state.data.slot,
|
||||
eth1_deposit_index = state.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
rollback(state)
|
||||
return err("Unable to apply new block to state: " & $res.error())
|
||||
return err(res.error())
|
||||
|
||||
state.root = hash_tree_root(state.data)
|
||||
blck.state_root = state.root
|
||||
|
||||
ok(blck)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/merge/validator.md#block-proposal
|
||||
@ -498,7 +436,7 @@ template partialBeaconBlock(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload): bellatrix.BeaconBlock =
|
||||
execution_payload: ExecutionPayload): bellatrix.BeaconBlock =
|
||||
bellatrix.BeaconBlock(
|
||||
slot: state.data.slot,
|
||||
proposer_index: proposer_index.uint64,
|
||||
@ -513,7 +451,7 @@ template partialBeaconBlock(
|
||||
deposits: List[Deposit, Limit MAX_DEPOSITS](deposits),
|
||||
voluntary_exits: exits.voluntary_exits,
|
||||
sync_aggregate: sync_aggregate,
|
||||
execution_payload: executionPayload))
|
||||
execution_payload: execution_payload))
|
||||
|
||||
proc makeBeaconBlock*(
|
||||
cfg: RuntimeConfig,
|
||||
@ -526,9 +464,9 @@ proc makeBeaconBlock*(
|
||||
deposits: seq[Deposit],
|
||||
exits: BeaconBlockExits,
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload,
|
||||
execution_payload: ExecutionPayload,
|
||||
rollback: RollbackMergeHashedProc,
|
||||
cache: var StateCache): Result[bellatrix.BeaconBlock, string] =
|
||||
cache: var StateCache): Result[bellatrix.BeaconBlock, cstring] =
|
||||
## Create a block for the given state. The latest block applied to it will
|
||||
## be used for the parent_root value, and the slot will be take from
|
||||
## state.slot meaning process_slots must be called up to the slot for which
|
||||
@ -539,22 +477,17 @@ proc makeBeaconBlock*(
|
||||
|
||||
var blck = partialBeaconBlock(cfg, state, proposer_index,
|
||||
randao_reveal, eth1_data, graffiti, attestations, deposits,
|
||||
exits, sync_aggregate, executionPayload)
|
||||
exits, sync_aggregate, execution_payload)
|
||||
|
||||
let res = process_block(cfg, state.data, blck, {skipBlsValidation}, cache)
|
||||
|
||||
if res.isErr:
|
||||
warn "Unable to apply new block to state",
|
||||
blck = shortLog(blck),
|
||||
slot = state.data.slot,
|
||||
eth1_deposit_index = state.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
rollback(state)
|
||||
return err("Unable to apply new block to state: " & $res.error())
|
||||
return err(res.error())
|
||||
|
||||
state.root = hash_tree_root(state.data)
|
||||
blck.state_root = state.root
|
||||
|
||||
ok(blck)
|
||||
|
||||
proc makeBeaconBlock*(
|
||||
@ -570,13 +503,13 @@ proc makeBeaconBlock*(
|
||||
sync_aggregate: SyncAggregate,
|
||||
executionPayload: ExecutionPayload,
|
||||
rollback: RollbackForkedHashedProc,
|
||||
cache: var StateCache): Result[ForkedBeaconBlock, string] =
|
||||
cache: var StateCache): Result[ForkedBeaconBlock, cstring] =
|
||||
## Create a block for the given state. The latest block applied to it will
|
||||
## be used for the parent_root value, and the slot will be take from
|
||||
## state.slot meaning process_slots must be called up to the slot for which
|
||||
## the block is to be created.
|
||||
|
||||
template makeBeaconBlock(kind: untyped): Result[ForkedBeaconBlock, string] =
|
||||
template makeBeaconBlock(kind: untyped): Result[ForkedBeaconBlock, cstring] =
|
||||
# To create a block, we'll first apply a partial block to the state, skipping
|
||||
# some validations.
|
||||
|
||||
@ -590,17 +523,12 @@ proc makeBeaconBlock*(
|
||||
{skipBlsValidation}, cache)
|
||||
|
||||
if res.isErr:
|
||||
warn "Unable to apply new block to state",
|
||||
blck = shortLog(blck),
|
||||
slot = state.`kind Data`.data.slot,
|
||||
eth1_deposit_index = state.`kind Data`.data.eth1_deposit_index,
|
||||
deposit_root = shortLog(state.`kind Data`.data.eth1_data.deposit_root),
|
||||
error = res.error
|
||||
rollback(state)
|
||||
return err("Unable to apply new block to state: " & $res.error())
|
||||
return err(res.error())
|
||||
|
||||
state.`kind Data`.root = hash_tree_root(state.`kind Data`.data)
|
||||
blck.`kind Data`.state_root = state.`kind Data`.root
|
||||
|
||||
ok(blck)
|
||||
|
||||
case state.kind
|
||||
|
@ -233,7 +233,7 @@ p2pProtocol BeaconSync(version = 1,
|
||||
case blck.kind
|
||||
of BeaconBlockFork.Phase0:
|
||||
await response.write(blck.phase0Data.asSigned)
|
||||
of BeaconBlockFork.Altair, BeaconBlockFork.Bellatrix:
|
||||
else:
|
||||
# Skipping all subsequent blocks should be OK because the spec says:
|
||||
# "Clients MAY limit the number of blocks in the response."
|
||||
# https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/p2p-interface.md#beaconblocksbyrange
|
||||
|
@ -448,21 +448,21 @@ proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
|
||||
# Advance to the given slot without calculating state root - we'll only
|
||||
# need a state root _with_ the block applied
|
||||
var info: ForkedEpochInfo
|
||||
if not process_slots(
|
||||
node.dag.cfg, stateData.data, slot, cache, info,
|
||||
{skipLastStateRootCalculation}):
|
||||
return ForkedBlockResult.err("Unable to advance state to slot")
|
||||
|
||||
process_slots(
|
||||
node.dag.cfg, stateData.data, slot, cache, info,
|
||||
{skipLastStateRootCalculation}).expect("advancing 1 slot should not fail")
|
||||
|
||||
let
|
||||
eth1Proposal = node.getBlockProposalEth1Data(stateData.data)
|
||||
|
||||
if eth1Proposal.hasMissingDeposits:
|
||||
error "Eth1 deposits not available. Skipping block proposal", slot
|
||||
warn "Eth1 deposits not available. Skipping block proposal", slot
|
||||
return ForkedBlockResult.err("Eth1 deposits not available")
|
||||
|
||||
let exits = withState(stateData.data):
|
||||
node.exitPool[].getBeaconBlockExits(state.data)
|
||||
return makeBeaconBlock(
|
||||
let res = makeBeaconBlock(
|
||||
node.dag.cfg,
|
||||
stateData.data,
|
||||
validator_index,
|
||||
@ -479,8 +479,16 @@ proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
|
||||
default(merge.ExecutionPayload),
|
||||
noRollback, # Temporary state - no need for rollback
|
||||
cache)
|
||||
if res.isErr():
|
||||
# This is almost certainly a bug, but it's complex enough that there's a
|
||||
# small risk it might happen even when most proposals succeed - thus we
|
||||
# log instead of asserting
|
||||
error "Cannot create block for proposal",
|
||||
slot, head = shortLog(head), error = res.error()
|
||||
return err($res.error)
|
||||
return ok(res.get())
|
||||
do:
|
||||
warn "Cannot get proposal state - skipping block productioon, database corrupt?",
|
||||
error "Cannot get proposal state - skipping block production, database corrupt?",
|
||||
head = shortLog(head),
|
||||
slot
|
||||
|
||||
|
@ -95,9 +95,11 @@ proc doTransition(conf: NcliConf) =
|
||||
var
|
||||
cache = StateCache()
|
||||
info = ForkedEpochInfo()
|
||||
if not state_transition(getRuntimeConfig(conf.eth2Network),
|
||||
stateY[], blckX, cache, info, flags, noRollback):
|
||||
error "State transition failed"
|
||||
let res = state_transition(
|
||||
getRuntimeConfig(conf.eth2Network), stateY[], blckX, cache, info,
|
||||
flags, noRollback)
|
||||
if res.isErr():
|
||||
error "State transition failed", error = res.error()
|
||||
quit 1
|
||||
else:
|
||||
saveSSZFile(conf.postState, stateY[])
|
||||
@ -126,9 +128,9 @@ proc doSlots(conf: NcliConf) =
|
||||
for i in 0'u64..<conf.slot:
|
||||
let isEpoch = (getStateField(stateY[], slot) + 1).is_epoch
|
||||
withTimer(timers[if isEpoch: tApplyEpochSlot else: tApplySlot]):
|
||||
doAssert process_slots(
|
||||
process_slots(
|
||||
defaultRuntimeConfig, stateY[], getStateField(stateY[], slot) + 1,
|
||||
cache, info, {})
|
||||
cache, info, {}).expect("should be able to advance slot")
|
||||
|
||||
withTimer(timers[tSaveState]):
|
||||
saveSSZFile(conf.postState, stateY[])
|
||||
|
@ -246,19 +246,19 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
|
||||
while getStateField(stateData[].data, slot) < b.message.slot:
|
||||
let isEpoch = (getStateField(stateData[].data, slot) + 1).is_epoch()
|
||||
withTimer(timers[if isEpoch: tAdvanceEpoch else: tAdvanceSlot]):
|
||||
let ok = process_slots(
|
||||
process_slots(
|
||||
dag.cfg, stateData[].data, getStateField(stateData[].data, slot) + 1, cache,
|
||||
info, {})
|
||||
doAssert ok, "Slot processing can't fail with correct inputs"
|
||||
info, {}).expect("Slot processing can't fail with correct inputs")
|
||||
|
||||
var start = Moment.now()
|
||||
withTimer(timers[tApplyBlock]):
|
||||
if conf.resetCache:
|
||||
cache = StateCache()
|
||||
if not state_transition_block(
|
||||
dag.cfg, stateData[].data, b, cache, {}, noRollback):
|
||||
let res = state_transition_block(
|
||||
dag.cfg, stateData[].data, b, cache, {}, noRollback)
|
||||
if res.isErr():
|
||||
dump("./", b)
|
||||
echo "State transition failed (!)"
|
||||
echo "State transition failed (!) ", res.error()
|
||||
quit 1
|
||||
if conf.printTimes:
|
||||
echo b.message.slot, ",", toHex(b.root.data), ",", nanoseconds(Moment.now() - start)
|
||||
@ -665,24 +665,24 @@ proc cmdValidatorPerf(conf: DbConf, cfg: RuntimeConfig) =
|
||||
flags =
|
||||
if nextSlot == blck.message.slot: {skipLastStateRootCalculation}
|
||||
else: {}
|
||||
let ok = process_slots(
|
||||
dag.cfg, state[].data, nextSlot, cache, info, flags)
|
||||
doAssert ok, "Slot processing can't fail with correct inputs"
|
||||
process_slots(
|
||||
dag.cfg, state[].data, nextSlot, cache, info, flags).expect(
|
||||
"Slot processing can't fail with correct inputs")
|
||||
|
||||
if getStateField(state[].data, slot).is_epoch():
|
||||
processEpoch()
|
||||
|
||||
if not state_transition_block(
|
||||
dag.cfg, state[].data, blck, cache, {}, noRollback):
|
||||
echo "State transition failed (!)"
|
||||
let res = state_transition_block(
|
||||
dag.cfg, state[].data, blck, cache, {}, noRollback)
|
||||
if res.isErr:
|
||||
echo "State transition failed (!) ", res.error()
|
||||
quit 1
|
||||
|
||||
# Capture rewards of empty slots as well
|
||||
while getStateField(state[].data, slot) < ends:
|
||||
let ok = process_slots(
|
||||
process_slots(
|
||||
dag.cfg, state[].data, getStateField(state[].data, slot) + 1, cache,
|
||||
info, {})
|
||||
doAssert ok, "Slot processing can't fail with correct inputs"
|
||||
info, {}).expect("Slot processing can't fail with correct inputs")
|
||||
|
||||
if getStateField(state[].data, slot).is_epoch():
|
||||
processEpoch()
|
||||
@ -911,24 +911,24 @@ proc cmdValidatorDb(conf: DbConf, cfg: RuntimeConfig) =
|
||||
if nextSlot == blck.message.slot: {skipLastStateRootCalculation}
|
||||
else: {}
|
||||
|
||||
let ok = process_slots(cfg, state[].data, nextSlot, cache, info, flags)
|
||||
doAssert ok, "Slot processing can't fail with correct inputs"
|
||||
process_slots(cfg, state[].data, nextSlot, cache, info, flags).expect(
|
||||
"Slot processing can't fail with correct inputs")
|
||||
|
||||
if getStateField(state[].data, slot).is_epoch():
|
||||
processEpoch()
|
||||
|
||||
if not state_transition_block(
|
||||
cfg, state[].data, blck, cache, {}, noRollback):
|
||||
echo "State transition failed (!)"
|
||||
let res = state_transition_block(
|
||||
cfg, state[].data, blck, cache, {}, noRollback)
|
||||
if res.isErr():
|
||||
echo "State transition failed (!) ", res.error()
|
||||
quit 1
|
||||
|
||||
# Capture rewards of empty slots as well, including the epoch that got
|
||||
# finalized
|
||||
while getStateField(state[].data, slot) <= ends:
|
||||
let ok = process_slots(
|
||||
process_slots(
|
||||
cfg, state[].data, getStateField(state[].data, slot) + 1, cache,
|
||||
info, {})
|
||||
doAssert ok, "Slot processing can't fail with correct inputs"
|
||||
info, {}).expect("Slot processing can't fail with correct inputs")
|
||||
|
||||
if getStateField(state[].data, slot).is_epoch():
|
||||
processEpoch()
|
||||
|
@ -125,7 +125,8 @@ proc nfuzz_block(input: openArray[byte], xoutput: ptr byte,
|
||||
data.state = fhState.phase0Data.data
|
||||
|
||||
decodeAndProcess(BlockInput):
|
||||
state_transition(defaultRuntimeConfig, data, data.beaconBlock, flags, noRollback)
|
||||
state_transition(
|
||||
defaultRuntimeConfig, data, data.beaconBlock, flags, noRollback).isOk
|
||||
|
||||
proc nfuzz_block_header(input: openArray[byte], xoutput: ptr byte,
|
||||
xoutput_size: ptr uint, disable_bls: bool): bool {.exportc, raises: [FuzzCrashError, Defect].} =
|
||||
|
@ -45,15 +45,15 @@ proc runTest(testName, testDir, unitTestName: string) =
|
||||
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, altair.SignedBeaconBlock)
|
||||
|
||||
if hasPostState:
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("block should apply: " & $i)
|
||||
else:
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert (i + 1 < numBlocks) or not success,
|
||||
doAssert (i + 1 < numBlocks) or not res.isOk(),
|
||||
"We didn't expect these invalid blocks to be processed"
|
||||
|
||||
if hasPostState:
|
||||
|
@ -41,7 +41,7 @@ proc runTest(identifier: string) =
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, fhPreState[],
|
||||
getStateField(fhPreState[], slot) + num_slots, cache, info, {})
|
||||
getStateField(fhPreState[], slot) + num_slots, cache, info, {}).isOk()
|
||||
|
||||
getStateRoot(fhPreState[]) == postState[].hash_tree_root()
|
||||
let newPreState = newClone(fhPreState.altairData.data)
|
||||
|
@ -159,8 +159,8 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
||||
var
|
||||
cache = StateCache()
|
||||
info = ForkedEpochInfo()
|
||||
doAssert process_slots(
|
||||
cfg, forked[], Slot(UPDATE_TIMEOUT), cache, info, flags = {})
|
||||
process_slots(
|
||||
cfg, forked[], Slot(UPDATE_TIMEOUT), cache, info, flags = {}).expect("no failure")
|
||||
let
|
||||
snapshot_period = sync_committee_period(store.optimistic_header.slot)
|
||||
update_period = sync_committee_period(state.slot)
|
||||
@ -226,8 +226,8 @@ suite "EF - Altair - Unittests - Sync protocol" & preset():
|
||||
cache = StateCache()
|
||||
info = ForkedEpochInfo()
|
||||
blocks = newSeq[ForkedSignedBeaconBlock]()
|
||||
doAssert process_slots(
|
||||
cfg, forked[], Slot(SLOTS_PER_EPOCH * 2), cache, info, flags = {})
|
||||
process_slots(
|
||||
cfg, forked[], Slot(SLOTS_PER_EPOCH * 2), cache, info, flags = {}).expect("no failure")
|
||||
for epoch in 0 ..< 3:
|
||||
for slot in 0 ..< SLOTS_PER_EPOCH:
|
||||
blocks.add block_for_next_slot(cfg, forked[], cache,
|
||||
|
@ -58,17 +58,17 @@ proc runTest(testName, testDir, unitTestName: string) =
|
||||
if i <= transitionInfo.fork_block:
|
||||
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, phase0.SignedBeaconBlock)
|
||||
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
cfg, fhPreState[], blck, cache, info,
|
||||
flags = {skipStateRootValidation}, noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("no failure when applying block " & $i)
|
||||
else:
|
||||
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, altair.SignedBeaconBlock)
|
||||
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
cfg, fhPreState[], blck, cache, info,
|
||||
flags = {skipStateRootValidation}, noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("no failure when applying block " & $i)
|
||||
|
||||
let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, altair.BeaconState))
|
||||
when false:
|
||||
|
@ -53,15 +53,15 @@ proc runTest(testName, testDir, unitTestName: string) =
|
||||
bellatrix.SignedBeaconBlock)
|
||||
|
||||
if hasPostState:
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("no failure when applying block " & $i)
|
||||
else:
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert (i + 1 < numBlocks) or not success,
|
||||
doAssert (i + 1 < numBlocks) or not res.isOk,
|
||||
"We didn't expect these invalid blocks to be processed"
|
||||
|
||||
if hasPostState:
|
||||
|
@ -42,7 +42,7 @@ proc runTest(identifier: string) =
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, fhPreState[],
|
||||
getStateField(fhPreState[], slot) + num_slots, cache, info, {})
|
||||
getStateField(fhPreState[], slot) + num_slots, cache, info, {}).isOk()
|
||||
|
||||
getStateRoot(fhPreState[]) == postState[].hash_tree_root()
|
||||
let newPreState = newClone(fhPreState.mergeData.data)
|
||||
|
@ -60,19 +60,19 @@ proc runTest(testName, testDir, unitTestName: string) =
|
||||
testPath/"blocks_" & $i & ".ssz_snappy", SSZ,
|
||||
altair.SignedBeaconBlock)
|
||||
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
cfg, fhPreState[], blck, cache, info,
|
||||
flags = {skipStateRootValidation}, noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("no failure when applying block " & $i)
|
||||
else:
|
||||
let blck = parseTest(
|
||||
testPath/"blocks_" & $i & ".ssz_snappy", SSZ,
|
||||
bellatrix.SignedBeaconBlock)
|
||||
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
cfg, fhPreState[], blck, cache, info,
|
||||
flags = {skipStateRootValidation}, noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
res.expect("no failure when applying block " & $i)
|
||||
|
||||
let postState = newClone(parseTest(
|
||||
testPath/"post.ssz_snappy", SSZ, bellatrix.BeaconState))
|
||||
|
@ -45,15 +45,14 @@ proc runTest(testName, testDir, unitTestName: string) =
|
||||
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, phase0.SignedBeaconBlock)
|
||||
|
||||
if hasPostState:
|
||||
let success = state_transition(
|
||||
state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert success, "Failure when applying block " & $i
|
||||
noRollback).expect("should apply block")
|
||||
else:
|
||||
let success = state_transition(
|
||||
let res = state_transition(
|
||||
defaultRuntimeConfig, fhPreState[], blck, cache, info, flags = {},
|
||||
noRollback)
|
||||
doAssert (i + 1 < numBlocks) or not success,
|
||||
doAssert (i + 1 < numBlocks) or not res.isOk(),
|
||||
"We didn't expect these invalid blocks to be processed"
|
||||
|
||||
if hasPostState:
|
||||
|
@ -39,7 +39,7 @@ proc runTest(identifier: string) =
|
||||
process_slots(
|
||||
defaultRuntimeConfig,
|
||||
fhPreState[], getStateField(fhPreState[], slot) + num_slots, cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
getStateRoot(fhPreState[]) == postState[].hash_tree_root()
|
||||
let newPreState = newClone(fhPreState.phase0Data.data)
|
||||
|
@ -82,7 +82,7 @@ proc mockBlock*(
|
||||
tmpState = assignClone(state)
|
||||
if getStateField(state, slot) != slot:
|
||||
var info = ForkedEpochInfo()
|
||||
doAssert process_slots(cfg, tmpState[], slot, cache, info, flags = {})
|
||||
process_slots(cfg, tmpState[], slot, cache, info, flags = {}).expect("no failure")
|
||||
|
||||
result.kind = case tmpState[].kind
|
||||
of BeaconStateFork.Phase0: BeaconBlockFork.Phase0
|
||||
|
@ -74,7 +74,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
dag.cfg, state.data, getStateField(state.data, slot) + 1, cache, info,
|
||||
{})
|
||||
{}).isOk()
|
||||
|
||||
test "Can add and retrieve simple attestations" & preset():
|
||||
let
|
||||
@ -106,7 +106,7 @@ suite "Attestation pool processing" & preset():
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
let attestations = pool[].getAttestationsForBlock(state.data, cache)
|
||||
|
||||
@ -128,7 +128,7 @@ suite "Attestation pool processing" & preset():
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
withState(state.data): state.latest_block_root == root1
|
||||
|
||||
@ -211,7 +211,7 @@ suite "Attestation pool processing" & preset():
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
check:
|
||||
pool[].getAttestationsForBlock(state.data, cache).len() == 2
|
||||
@ -261,7 +261,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
getStateField(state.data, slot) + 1, cache, info, {})
|
||||
getStateField(state.data, slot) + 1, cache, info, {}).isOk()
|
||||
|
||||
doAssert attestations.uint64 > MAX_ATTESTATIONS,
|
||||
"6*SLOTS_PER_EPOCH validators > 128 mainnet MAX_ATTESTATIONS"
|
||||
@ -283,7 +283,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data, getStateField(state.data, slot) + 1,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
let
|
||||
bc1 = get_beacon_committee(state[].data,
|
||||
@ -298,10 +298,6 @@ suite "Attestation pool processing" & preset():
|
||||
attestation0, @[bc0[0]], attestation0.loadSig,
|
||||
attestation0.data.slot.start_beacon_time)
|
||||
|
||||
discard process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {})
|
||||
|
||||
let attestations = pool[].getAttestationsForBlock(state.data, cache)
|
||||
|
||||
check:
|
||||
@ -328,7 +324,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {})
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {}).isOk()
|
||||
|
||||
let attestations = pool[].getAttestationsForBlock(state.data, cache)
|
||||
|
||||
@ -359,7 +355,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {})
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {}).isOk()
|
||||
|
||||
let attestations = pool[].getAttestationsForBlock(state.data, cache)
|
||||
|
||||
@ -389,7 +385,7 @@ suite "Attestation pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data,
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {})
|
||||
MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, info, {}).isOk()
|
||||
|
||||
let attestations = pool[].getAttestationsForBlock(state.data, cache)
|
||||
|
||||
|
@ -118,7 +118,7 @@ suite "Block pool processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state[], getStateField(state[], slot) + 1, cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
let
|
||||
b4 = addTestBlock(state[], cache).phase0Data
|
||||
@ -283,7 +283,7 @@ suite "Block pool altair processing" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
cfg, state[], cfg.ALTAIR_FORK_EPOCH.start_slot(), cache,
|
||||
info, {})
|
||||
info, {}).isOk()
|
||||
|
||||
state[].kind == BeaconStateFork.Altair
|
||||
|
||||
@ -362,7 +362,7 @@ suite "chain DAG finalization tests" & preset():
|
||||
process_slots(
|
||||
defaultRuntimeConfig, tmpState[],
|
||||
getStateField(tmpState[], slot) + (5 * SLOTS_PER_EPOCH).uint64,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
let lateBlock = addTestBlock(tmpState[], cache).phase0Data
|
||||
block:
|
||||
@ -472,7 +472,7 @@ suite "chain DAG finalization tests" & preset():
|
||||
|
||||
doAssert process_slots(
|
||||
defaultRuntimeConfig, prestate[], getStateField(prestate[], slot) + 1,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
# create another block, orphaning the head
|
||||
let blck = makeTestBlock(prestate[], cache).phase0Data
|
||||
@ -502,7 +502,7 @@ suite "chain DAG finalization tests" & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, dag.headState.data, Slot(SLOTS_PER_EPOCH * 6 + 2),
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
var blck = makeTestBlock(
|
||||
dag.headState.data, cache,
|
||||
@ -607,7 +607,7 @@ suite "Diverging hardforks":
|
||||
process_slots(
|
||||
phase0RuntimeConfig, tmpState[],
|
||||
getStateField(tmpState[], slot) + (3 * SLOTS_PER_EPOCH).uint64,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
# Because the first block is after the Altair transition, the only block in
|
||||
# common is the tail block
|
||||
@ -629,7 +629,7 @@ suite "Diverging hardforks":
|
||||
process_slots(
|
||||
phase0RuntimeConfig, tmpState[],
|
||||
getStateField(tmpState[], slot) + SLOTS_PER_EPOCH.uint64,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
# There's a block in the shared-correct phase0 hardfork, before epoch 2
|
||||
var
|
||||
@ -641,7 +641,7 @@ suite "Diverging hardforks":
|
||||
process_slots(
|
||||
phase0RuntimeConfig, tmpState[],
|
||||
getStateField(tmpState[], slot) + (3 * SLOTS_PER_EPOCH).uint64,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
var
|
||||
b2 = addTestBlock(tmpState[], cache).phase0Data
|
||||
|
@ -52,7 +52,7 @@ suite "Gossip validation " & preset():
|
||||
check:
|
||||
process_slots(
|
||||
defaultRuntimeConfig, state.data, getStateField(state.data, slot) + 1,
|
||||
cache, info, {})
|
||||
cache, info, {}).isOk()
|
||||
|
||||
test "Empty committee when no committee for slot":
|
||||
template committee(idx: uint64): untyped =
|
||||
|
@ -32,8 +32,9 @@ suite "Spec helpers":
|
||||
forked = newClone(initGenesisState())
|
||||
cache = StateCache()
|
||||
info = ForkedEpochInfo()
|
||||
doAssert process_slots(defaultRuntimeConfig, forked[],
|
||||
Slot(100), cache, info, flags = {})
|
||||
process_slots(
|
||||
defaultRuntimeConfig, forked[], Slot(100), cache, info,
|
||||
flags = {}).expect("no failure")
|
||||
|
||||
let
|
||||
state = forked[].phase0Data.data
|
||||
|
@ -24,6 +24,21 @@ suite "Beacon state" & preset():
|
||||
makeInitialDeposits(SLOTS_PER_EPOCH, {}), {}))
|
||||
check: state.validators.lenu64 == SLOTS_PER_EPOCH
|
||||
|
||||
test "process_slots":
|
||||
var
|
||||
cfg = defaultRuntimeConfig
|
||||
state = (ref ForkedHashedBeaconState)(
|
||||
kind: BeaconStateFork.Phase0,
|
||||
phase0Data: initialize_hashed_beacon_state_from_eth1(
|
||||
defaultRuntimeConfig, Eth2Digest(), 0,
|
||||
makeInitialDeposits(SLOTS_PER_EPOCH, {}), {skipBlsValidation}))
|
||||
cache: StateCache
|
||||
info: ForkedEpochInfo
|
||||
check:
|
||||
process_slots(cfg, state[], Slot 1, cache, info, {}).isOk()
|
||||
process_slots(cfg, state[], Slot 1, cache, info, {}).isErr()
|
||||
process_slots(cfg, state[], Slot 1, cache, info, {slotProcessed}).isOk()
|
||||
|
||||
test "latest_block_root":
|
||||
var
|
||||
cfg = defaultRuntimeConfig
|
||||
@ -38,7 +53,7 @@ suite "Beacon state" & preset():
|
||||
|
||||
check: # Works for genesis block
|
||||
state[].phase0Data.latest_block_root() == genBlock.root
|
||||
process_slots(cfg, state[], Slot 1, cache, info, {})
|
||||
process_slots(cfg, state[], Slot 1, cache, info, {}).isOk()
|
||||
state[].phase0Data.latest_block_root() == genBlock.root
|
||||
|
||||
let blck = addTestBlock(
|
||||
@ -46,7 +61,7 @@ suite "Beacon state" & preset():
|
||||
|
||||
check: # Works for random blocks
|
||||
state[].phase0Data.latest_block_root() == blck.root
|
||||
process_slots(cfg, state[], Slot 2, cache, info, {})
|
||||
process_slots(cfg, state[], Slot 2, cache, info, {}).isOk()
|
||||
state[].phase0Data.latest_block_root() == blck.root
|
||||
|
||||
test "get_beacon_proposer_index":
|
||||
@ -68,7 +83,7 @@ suite "Beacon state" & preset():
|
||||
state[].phase0Data.data, cache, Epoch(2).start_slot()).isNone()
|
||||
|
||||
check:
|
||||
process_slots(cfg, state[], Epoch(1).start_slot(), cache, info, {})
|
||||
process_slots(cfg, state[], Epoch(1).start_slot(), cache, info, {}).isOk()
|
||||
get_beacon_proposer_index(state[].phase0Data.data, cache, Slot 1).isNone()
|
||||
get_beacon_proposer_index(
|
||||
state[].phase0Data.data, cache, Epoch(1).start_slot()).isSome()
|
||||
|
@ -88,8 +88,9 @@ proc addTestBlock*(
|
||||
# Create and add a block to state - state will advance by one slot!
|
||||
if nextSlot:
|
||||
var info = ForkedEpochInfo()
|
||||
doAssert process_slots(
|
||||
cfg, state, getStateField(state, slot) + 1, cache, info, flags)
|
||||
process_slots(
|
||||
cfg, state, getStateField(state, slot) + 1, cache, info, flags).expect(
|
||||
"can advance 1")
|
||||
|
||||
let
|
||||
proposer_index = get_beacon_proposer_index(
|
||||
|
@ -73,8 +73,8 @@ proc getTestStates*(
|
||||
for i, epoch in stateEpochs:
|
||||
let slot = epoch.Epoch.start_slot
|
||||
if getStateField(tmpState[], slot) < slot:
|
||||
doAssert process_slots(
|
||||
cfg, tmpState[], slot, cache, info, {})
|
||||
process_slots(
|
||||
cfg, tmpState[], slot, cache, info, {}).expect("no failure")
|
||||
|
||||
if i mod 3 == 0:
|
||||
withState(tmpState[]):
|
||||
|
2
vendor/nim-stew
vendored
2
vendor/nim-stew
vendored
@ -1 +1 @@
|
||||
Subproject commit 6ad35b876fb6ebe0dfee0f697af173acc47906ee
|
||||
Subproject commit b464505b4dcbe2ef52d19b2cfca8f2be4ebf2c7e
|
Loading…
x
Reference in New Issue
Block a user