use ForkedHashedBeaconState in StateData (#2634)

* use ForkedHashedBeaconState in StateData

* fix FAR_FUTURE_EPOCH -> slot overflow; almost always use assign()

* avoid stack allocation in maybeUpgradeStateToAltair()

* create and use dispatch functions for check_attester_slashing(), check_proposer_slashing(), and check_voluntary_exit()

* use getStateRoot() instead of various state.data.hbsPhase0.root

* remove withStateVars.hashedState(), which doesn't work as a design anymore

* introduce spec/datatypes/altair into beacon_chain_db

* fix inefficient codegen for getStateField(largeStateField)

* state_transition_slots() doesn't either need/use blocks or runtime presets

* combine process_slots(HBS)/state_transition_slots(HBS) which differ only in last-slot htr optimization

* getStateField(StateData, ...) was replaced by getStateField(ForkedHashedBeaconState, ...)

* fix rollback

* switch some state_transition(), process_slots, makeTestBlocks(), etc to use ForkedHashedBeaconState

* remove state_transition(phase0.HashedBeaconState)

* remove process_slots(phase0.HashedBeaconState)

* remove state_transition_block(phase0.HashedBeaconState)

* remove unused callWithBS(); separate case expression from if statement

* switch back from nested-ref-object construction to (ref Foo)(Bar())
This commit is contained in:
tersec 2021-06-11 17:51:46 +00:00 committed by GitHub
parent f2588be9ab
commit 146fa48454
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1050 additions and 957 deletions

View File

@ -13,7 +13,8 @@ import
serialization, chronicles, snappy, serialization, chronicles, snappy,
eth/db/[kvstore, kvstore_sqlite3], eth/db/[kvstore, kvstore_sqlite3],
./networking/network_metadata, ./beacon_chain_db_immutable, ./networking/network_metadata, ./beacon_chain_db_immutable,
./spec/[crypto, datatypes, digest, state_transition], ./spec/[crypto, digest, state_transition],
./spec/datatypes/[phase0, altair],
./ssz/[ssz_serialization, merkleization], ./ssz/[ssz_serialization, merkleization],
./filepath ./filepath
@ -159,14 +160,14 @@ func subkey[N: static int](kind: DbKeyKind, key: array[N, byte]):
result[0] = byte ord(kind) result[0] = byte ord(kind)
result[1 .. ^1] = key result[1 .. ^1] = key
func subkey(kind: type BeaconState, key: Eth2Digest): auto = func subkey(kind: type phase0.BeaconState, key: Eth2Digest): auto =
subkey(kHashToState, key.data) subkey(kHashToState, key.data)
func subkey( func subkey(
kind: type BeaconStateNoImmutableValidators, key: Eth2Digest): auto = kind: type BeaconStateNoImmutableValidators, key: Eth2Digest): auto =
subkey(kHashToStateOnlyMutableValidators, key.data) subkey(kHashToStateOnlyMutableValidators, key.data)
func subkey(kind: type SignedBeaconBlock, key: Eth2Digest): auto = func subkey(kind: type phase0.SignedBeaconBlock, key: Eth2Digest): auto =
subkey(kHashToBlock, key.data) subkey(kHashToBlock, key.data)
func subkey(kind: type BeaconBlockSummary, key: Eth2Digest): auto = func subkey(kind: type BeaconBlockSummary, key: Eth2Digest): auto =
@ -459,7 +460,7 @@ proc close*(db: BeaconchainDB) =
db.db = nil db.db = nil
func toBeaconBlockSummary(v: SomeBeaconBlock): BeaconBlockSummary = func toBeaconBlockSummary(v: SomeSomeBeaconBlock): BeaconBlockSummary =
BeaconBlockSummary( BeaconBlockSummary(
slot: v.slot, slot: v.slot,
parent_root: v.parent_root, parent_root: v.parent_root,
@ -470,7 +471,7 @@ proc putBeaconBlockSummary(
# Summaries are too simple / small to compress, store them as plain SSZ # Summaries are too simple / small to compress, store them as plain SSZ
db.summaries.putSSZ(root.data, value) db.summaries.putSSZ(root.data, value)
proc putBlock*(db: BeaconChainDB, value: TrustedSignedBeaconBlock) = proc putBlock*(db: BeaconChainDB, value: phase0.TrustedSignedBeaconBlock) =
db.blocks.putSnappySSZ(value.root.data, value) db.blocks.putSnappySSZ(value.root.data, value)
db.putBeaconBlockSummary(value.root, value.message.toBeaconBlockSummary()) db.putBeaconBlockSummary(value.root, value.message.toBeaconBlockSummary())
@ -485,13 +486,13 @@ proc updateImmutableValidators*(
db.immutableValidatorsDb.add immutableValidator db.immutableValidatorsDb.add immutableValidator
db.immutableValidators.add immutableValidator db.immutableValidators.add immutableValidator
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: BeaconState) = proc putState*(db: BeaconChainDB, key: Eth2Digest, value: phase0.BeaconState) =
db.updateImmutableValidators(value.validators.asSeq()) db.updateImmutableValidators(value.validators.asSeq())
db.statesNoVal.putSnappySSZ( db.statesNoVal.putSnappySSZ(
key.data, key.data,
isomorphicCast[BeaconStateNoImmutableValidators](value)) isomorphicCast[BeaconStateNoImmutableValidators](value))
proc putState*(db: BeaconChainDB, value: BeaconState) = proc putState*(db: BeaconChainDB, value: phase0.BeaconState) =
db.putState(hash_tree_root(value), value) db.putState(hash_tree_root(value), value)
func stateRootKey(root: Eth2Digest, slot: Slot): array[40, byte] = func stateRootKey(root: Eth2Digest, slot: Slot): array[40, byte] =
@ -535,18 +536,20 @@ proc putEth2FinalizedTo*(db: BeaconChainDB,
eth1Checkpoint: DepositContractSnapshot) = eth1Checkpoint: DepositContractSnapshot) =
db.keyValues.putSnappySSZ(subkey(kDepositsFinalizedByEth2), eth1Checkpoint) db.keyValues.putSnappySSZ(subkey(kDepositsFinalizedByEth2), eth1Checkpoint)
proc getBlock(db: BeaconChainDBV0, key: Eth2Digest): Opt[TrustedSignedBeaconBlock] = proc getBlock(db: BeaconChainDBV0, key: Eth2Digest): Opt[phase0.TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database # We only store blocks that we trust in the database
result.ok(TrustedSignedBeaconBlock()) result.ok(default(phase0.TrustedSignedBeaconBlock))
if db.backend.getSnappySSZ(subkey(SignedBeaconBlock, key), result.get) != GetResult.found: if db.backend.getSnappySSZ(
subkey(phase0.SignedBeaconBlock, key), result.get) != GetResult.found:
result.err() result.err()
else: else:
# set root after deserializing (so it doesn't get zeroed) # set root after deserializing (so it doesn't get zeroed)
result.get().root = key result.get().root = key
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[TrustedSignedBeaconBlock] = proc getBlock*(db: BeaconChainDB, key: Eth2Digest):
Opt[phase0.TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database # We only store blocks that we trust in the database
result.ok(TrustedSignedBeaconBlock()) result.ok(default(phase0.TrustedSignedBeaconBlock))
if db.blocks.getSnappySSZ(key.data, result.get) != GetResult.found: if db.blocks.getSnappySSZ(key.data, result.get) != GetResult.found:
result = db.v0.getBlock(key) result = db.v0.getBlock(key)
else: else:
@ -555,7 +558,7 @@ proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[TrustedSignedBeaconBlock
proc getStateOnlyMutableValidators( proc getStateOnlyMutableValidators(
immutableValidators: openArray[ImmutableValidatorData2], immutableValidators: openArray[ImmutableValidatorData2],
store: KvStoreRef, key: openArray[byte], output: var BeaconState, store: KvStoreRef, key: openArray[byte], output: var phase0.BeaconState,
rollback: RollbackProc): bool = rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid ## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible ## re-allocating it if possible
@ -598,7 +601,7 @@ proc getStateOnlyMutableValidators(
proc getState( proc getState(
db: BeaconChainDBV0, db: BeaconChainDBV0,
immutableValidators: openArray[ImmutableValidatorData2], immutableValidators: openArray[ImmutableValidatorData2],
key: Eth2Digest, output: var BeaconState, key: Eth2Digest, output: var phase0.BeaconState,
rollback: RollbackProc): bool = rollback: RollbackProc): bool =
# Nimbus 1.0 reads and writes writes genesis BeaconState to `backend` # Nimbus 1.0 reads and writes writes genesis BeaconState to `backend`
# Nimbus 1.1 writes a genesis BeaconStateNoImmutableValidators to `backend` and # Nimbus 1.1 writes a genesis BeaconStateNoImmutableValidators to `backend` and
@ -615,7 +618,7 @@ proc getState(
subkey(BeaconStateNoImmutableValidators, key), output, rollback): subkey(BeaconStateNoImmutableValidators, key), output, rollback):
return true return true
case db.backend.getSnappySSZ(subkey(BeaconState, key), output) case db.backend.getSnappySSZ(subkey(phase0.BeaconState, key), output)
of GetResult.found: of GetResult.found:
true true
of GetResult.notFound: of GetResult.notFound:
@ -625,7 +628,7 @@ proc getState(
false false
proc getState*( proc getState*(
db: BeaconChainDB, key: Eth2Digest, output: var BeaconState, db: BeaconChainDB, key: Eth2Digest, output: var phase0.BeaconState,
rollback: RollbackProc): bool = rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid ## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible ## re-allocating it if possible
@ -692,7 +695,7 @@ proc getEth2FinalizedTo*(db: BeaconChainDB): Opt[DepositContractSnapshot] =
if r != found: return db.v0.getEth2FinalizedTo() if r != found: return db.v0.getEth2FinalizedTo()
proc containsBlock*(db: BeaconChainDBV0, key: Eth2Digest): bool = proc containsBlock*(db: BeaconChainDBV0, key: Eth2Digest): bool =
db.backend.contains(subkey(SignedBeaconBlock, key)).expectDb() db.backend.contains(subkey(phase0.SignedBeaconBlock, key)).expectDb()
proc containsBlock*(db: BeaconChainDB, key: Eth2Digest): bool = proc containsBlock*(db: BeaconChainDB, key: Eth2Digest): bool =
db.blocks.contains(key.data).expectDb() or db.v0.containsBlock(key) db.blocks.contains(key.data).expectDb() or db.v0.containsBlock(key)
@ -701,25 +704,25 @@ proc containsState*(db: BeaconChainDBV0, key: Eth2Digest): bool =
let sk = subkey(BeaconStateNoImmutableValidators, key) let sk = subkey(BeaconStateNoImmutableValidators, key)
db.stateStore.contains(sk).expectDb() or db.stateStore.contains(sk).expectDb() or
db.backend.contains(sk).expectDb() or db.backend.contains(sk).expectDb() or
db.backend.contains(subkey(BeaconState, key)).expectDb() db.backend.contains(subkey(phase0.BeaconState, key)).expectDb()
proc containsState*(db: BeaconChainDB, key: Eth2Digest, legacy: bool = true): bool = proc containsState*(db: BeaconChainDB, key: Eth2Digest, legacy: bool = true): bool =
db.statesNoVal.contains(key.data).expectDb or db.statesNoVal.contains(key.data).expectDb or
(legacy and db.v0.containsState(key)) (legacy and db.v0.containsState(key))
iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest): iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
TrustedSignedBeaconBlock = phase0.TrustedSignedBeaconBlock =
## Load a chain of ancestors for blck - returns a list of blocks with the ## Load a chain of ancestors for blck - returns a list of blocks with the
## oldest block last (blck will be at result[0]). ## oldest block last (blck will be at result[0]).
## ##
## The search will go on until the ancestor cannot be found. ## The search will go on until the ancestor cannot be found.
var var
res: TrustedSignedBeaconBlock res: phase0.TrustedSignedBeaconBlock
root = root root = root
while db.blocks.getSnappySSZ(root.data, res) == GetResult.found or while db.blocks.getSnappySSZ(root.data, res) == GetResult.found or
db.v0.backend.getSnappySSZ( db.v0.backend.getSnappySSZ(
subkey(SignedBeaconBlock, root), res) == GetResult.found: subkey(phase0.SignedBeaconBlock, root), res) == GetResult.found:
res.root = root res.root = root
yield res yield res
root = res.message.parent_root root = res.message.parent_root
@ -757,7 +760,7 @@ iterator getAncestorSummaries*(db: BeaconChainDB, root: Eth2Digest):
var var
summaries = db.loadSummaries() summaries = db.loadSummaries()
res: RootedSummary res: RootedSummary
blck: TrustedSignedBeaconBlock blck: phase0.TrustedSignedBeaconBlock
newSummaries: seq[RootedSummary] newSummaries: seq[RootedSummary]
res.root = root res.root = root
@ -790,7 +793,8 @@ iterator getAncestorSummaries*(db: BeaconChainDB, root: Eth2Digest):
do: # Summary was not found in summary table, look elsewhere do: # Summary was not found in summary table, look elsewhere
if db.v0.backend.getSnappySSZ(subkey(BeaconBlockSummary, res.root), res.summary) == GetResult.found: if db.v0.backend.getSnappySSZ(subkey(BeaconBlockSummary, res.root), res.summary) == GetResult.found:
yield res yield res
elif db.v0.backend.getSnappySSZ(subkey(SignedBeaconBlock, res.root), blck) == GetResult.found: elif db.v0.backend.getSnappySSZ(
subkey(phase0.SignedBeaconBlock, res.root), blck) == GetResult.found:
res.summary = blck.message.toBeaconBlockSummary() res.summary = blck.message.toBeaconBlockSummary()
yield res yield res
else: else:

View File

@ -14,9 +14,11 @@ import
metrics, metrics,
chronicles, stew/byteutils, json_serialization/std/sets as jsonSets, chronicles, stew/byteutils, json_serialization/std/sets as jsonSets,
# Internal # Internal
../spec/[beaconstate, datatypes, crypto, digest], ../spec/[
beaconstate, datatypes, crypto, digest, forkedbeaconstate_helpers,
validator],
../ssz/merkleization, ../ssz/merkleization,
"."/[spec_cache, blockchain_dag, block_quarantine, statedata_helpers], "."/[spec_cache, blockchain_dag, block_quarantine],
".."/[beacon_clock, beacon_node_types, extras], ".."/[beacon_clock, beacon_node_types, extras],
../fork_choice/fork_choice ../fork_choice/fork_choice
@ -83,9 +85,9 @@ proc init*(T: type AttestationPool, dag: ChainDAGRef, quarantine: QuarantineRef)
info "Fork choice initialized", info "Fork choice initialized",
justified_epoch = getStateField( justified_epoch = getStateField(
dag.headState, current_justified_checkpoint).epoch, dag.headState.data, current_justified_checkpoint).epoch,
finalized_epoch = getStateField( finalized_epoch = getStateField(
dag.headState, finalized_checkpoint).epoch, dag.headState.data, finalized_checkpoint).epoch,
finalized_root = shortlog(dag.finalizedHead.blck.root) finalized_root = shortlog(dag.finalizedHead.blck.root)
T( T(
@ -370,16 +372,16 @@ func add(
do: do:
attCache[key] = aggregation_bits attCache[key] = aggregation_bits
func init(T: type AttestationCache, state: StateData): T = func init(T: type AttestationCache, state: HashedBeaconState): T =
# Load attestations that are scheduled for being given rewards for # Load attestations that are scheduled for being given rewards for
for i in 0..<getStateField(state, previous_epoch_attestations).len(): for i in 0..<state.data.previous_epoch_attestations.len():
result.add( result.add(
getStateField(state, previous_epoch_attestations)[i].data, state.data.previous_epoch_attestations[i].data,
getStateField(state, previous_epoch_attestations)[i].aggregation_bits) state.data.previous_epoch_attestations[i].aggregation_bits)
for i in 0..<getStateField(state, current_epoch_attestations).len(): for i in 0..<state.data.current_epoch_attestations.len():
result.add( result.add(
getStateField(state, current_epoch_attestations)[i].data, state.data.current_epoch_attestations[i].data,
getStateField(state, current_epoch_attestations)[i].aggregation_bits) state.data.current_epoch_attestations[i].aggregation_bits)
proc score( proc score(
attCache: var AttestationCache, data: AttestationData, attCache: var AttestationCache, data: AttestationData,
@ -403,12 +405,12 @@ proc score(
bitsScore bitsScore
proc getAttestationsForBlock*(pool: var AttestationPool, proc getAttestationsForBlock*(pool: var AttestationPool,
state: StateData, state: HashedBeaconState,
cache: var StateCache): seq[Attestation] = cache: var StateCache): seq[Attestation] =
## Retrieve attestations that may be added to a new block at the slot of the ## Retrieve attestations that may be added to a new block at the slot of the
## given state ## given state
## https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#attestations ## https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#attestations
let newBlockSlot = getStateField(state, slot).uint64 let newBlockSlot = state.data.slot.uint64
if newBlockSlot < MIN_ATTESTATION_INCLUSION_DELAY: if newBlockSlot < MIN_ATTESTATION_INCLUSION_DELAY:
return # Too close to genesis return # Too close to genesis
@ -448,7 +450,7 @@ proc getAttestationsForBlock*(pool: var AttestationPool,
# attestation to - there might have been a fork between when we first # attestation to - there might have been a fork between when we first
# saw the attestation and the time that we added it # saw the attestation and the time that we added it
if not check_attestation( if not check_attestation(
state.data.data, attestation, {skipBlsValidation}, cache).isOk(): state.data, attestation, {skipBlsValidation}, cache).isOk():
continue continue
let score = attCache.score( let score = attCache.score(
@ -472,10 +474,10 @@ proc getAttestationsForBlock*(pool: var AttestationPool,
# #
# A possible improvement here would be to use a maximum cover algorithm. # A possible improvement here would be to use a maximum cover algorithm.
var var
prevEpoch = state.get_previous_epoch() prevEpoch = state.data.get_previous_epoch()
prevEpochSpace = prevEpochSpace =
getStateField(state, previous_epoch_attestations).maxLen - state.data.previous_epoch_attestations.maxLen -
getStateField(state, previous_epoch_attestations).len() state.data.previous_epoch_attestations.len()
var res: seq[Attestation] var res: seq[Attestation]
let totalCandidates = candidates.len() let totalCandidates = candidates.len()

View File

@ -13,7 +13,9 @@ import
stew/[assign2, results], stew/[assign2, results],
eth/keys, eth/keys,
../extras, ../beacon_clock, ../extras, ../beacon_clock,
../spec/[crypto, datatypes, digest, helpers, signatures, signatures_batch, state_transition], ../spec/[
crypto, datatypes, digest, forkedbeaconstate_helpers, helpers, signatures,
signatures_batch, state_transition],
./block_pools_types, ./blockchain_dag, ./block_quarantine ./block_pools_types, ./blockchain_dag, ./block_quarantine
from libp2p/protocols/pubsub/pubsub import ValidationResult from libp2p/protocols/pubsub/pubsub import ValidationResult
@ -80,7 +82,7 @@ proc addResolvedBlock(
stateVerifyDur: Duration stateVerifyDur: Duration
) = ) =
# TODO move quarantine processing out of here # TODO move quarantine processing out of here
doAssert getStateField(state, slot) == trustedBlock.message.slot, doAssert getStateField(state.data, slot) == trustedBlock.message.slot,
"state must match block" "state must match block"
doAssert state.blck.root == trustedBlock.message.parent_root, doAssert state.blck.root == trustedBlock.message.parent_root,
"the StateData passed into the addResolved function not yet updated!" "the StateData passed into the addResolved function not yet updated!"
@ -116,7 +118,7 @@ proc addResolvedBlock(
# as soon as we import a block, we'll also update the shared public key # as soon as we import a block, we'll also update the shared public key
# cache # cache
dag.updateValidatorKeys(getStateField(state, validators).asSeq()) dag.updateValidatorKeys(getStateField(state.data, validators).asSeq())
# Getting epochRef with the state will potentially create a new EpochRef # Getting epochRef with the state will potentially create a new EpochRef
let let
@ -134,7 +136,7 @@ proc addResolvedBlock(
# Notify others of the new block before processing the quarantine, such that # Notify others of the new block before processing the quarantine, such that
# notifications for parents happens before those of the children # notifications for parents happens before those of the children
if onBlockAdded != nil: if onBlockAdded != nil:
onBlockAdded(blockRef, trustedBlock, epochRef, state.data) onBlockAdded(blockRef, trustedBlock, epochRef, state.data.hbsPhase0)
# Now that we have the new block, we should see if any of the previously # Now that we have the new block, we should see if any of the previously
# unresolved blocks magically become resolved # unresolved blocks magically become resolved
@ -161,7 +163,7 @@ proc checkStateTransition(
dag: ChainDAGRef, signedBlock: SomeSignedBeaconBlock, dag: ChainDAGRef, signedBlock: SomeSignedBeaconBlock,
cache: var StateCache): (ValidationResult, BlockError) = cache: var StateCache): (ValidationResult, BlockError) =
## Ensure block can be applied on a state ## Ensure block can be applied on a state
func restore(v: var HashedBeaconState) = func restore(v: var ForkedHashedBeaconState) =
# TODO address this ugly workaround - there should probably be a # TODO address this ugly workaround - there should probably be a
# `state_transition` that takes a `StateData` instead and updates # `state_transition` that takes a `StateData` instead and updates
# the block as well # the block as well
@ -172,9 +174,12 @@ proc checkStateTransition(
blck = shortLog(signedBlock.message) blck = shortLog(signedBlock.message)
blockRoot = shortLog(signedBlock.root) blockRoot = shortLog(signedBlock.root)
# TODO this won't transition because FAR_FUTURE_SLOT, so it's
# fine, for now, but in general, blockchain_dag.addBlock must
# match the transition here.
if not state_transition_block( if not state_transition_block(
dag.runtimePreset, dag.clearanceState.data, signedBlock, dag.runtimePreset, dag.clearanceState.data, signedBlock,
cache, dag.updateFlags, restore): cache, dag.updateFlags, restore, FAR_FUTURE_SLOT):
info "Invalid block" info "Invalid block"
return (ValidationResult.Reject, Invalid) return (ValidationResult.Reject, Invalid)
@ -187,7 +192,7 @@ proc advanceClearanceState*(dag: ChainDagRef) =
# epoch transition ahead of time. # epoch transition ahead of time.
# Notably, we use the clearance state here because that's where the block will # Notably, we use the clearance state here because that's where the block will
# first be seen - later, this state will be copied to the head state! # first be seen - later, this state will be copied to the head state!
if dag.clearanceState.blck.slot == getStateField(dag.clearanceState, slot): if dag.clearanceState.blck.slot == getStateField(dag.clearanceState.data, slot):
let next = let next =
dag.clearanceState.blck.atSlot(dag.clearanceState.blck.slot + 1) dag.clearanceState.blck.atSlot(dag.clearanceState.blck.slot + 1)
@ -247,10 +252,9 @@ proc addRawBlockKnownParent(
# First, batch-verify all signatures in block # First, batch-verify all signatures in block
if skipBLSValidation notin dag.updateFlags: if skipBLSValidation notin dag.updateFlags:
# TODO: remove skipBLSValidation # TODO: remove skipBLSValidation
var sigs: seq[SignatureSet] var sigs: seq[SignatureSet]
if sigs.collectSignatureSets( if sigs.collectSignatureSets(
signedBlock, dag.db.immutableValidators, dag.clearanceState, cache).isErr(): signedBlock, dag.db.immutableValidators, dag.clearanceState.data, cache).isErr():
# A PublicKey or Signature isn't on the BLS12-381 curve # A PublicKey or Signature isn't on the BLS12-381 curve
return err((ValidationResult.Reject, Invalid)) return err((ValidationResult.Reject, Invalid))
if not quarantine.batchVerify(sigs): if not quarantine.batchVerify(sigs):

View File

@ -14,7 +14,8 @@ import
stew/[endians2], chronicles, stew/[endians2], chronicles,
eth/keys, eth/keys,
# Internals # Internals
../spec/[datatypes, crypto, digest, signatures_batch], ../spec/[
datatypes, crypto, digest, signatures_batch, forkedbeaconstate_helpers],
../beacon_chain_db, ../extras ../beacon_chain_db, ../extras
export sets, tables export sets, tables
@ -182,12 +183,31 @@ type
# balances, as used in fork choice # balances, as used in fork choice
effective_balances_bytes*: seq[byte] effective_balances_bytes*: seq[byte]
BlockRef* = ref object
## Node in object graph guaranteed to lead back to tail block, and to have
## a corresponding entry in database.
## Block graph should form a tree - in particular, there are no cycles.
root*: Eth2Digest ##\
## Root that can be used to retrieve block data from database
parent*: BlockRef ##\
## Not nil, except for the tail
slot*: Slot # could calculate this by walking to root, but..
BlockData* = object BlockData* = object
## Body and graph in one ## Body and graph in one
data*: TrustedSignedBeaconBlock # We trust all blocks we have a ref for data*: TrustedSignedBeaconBlock # We trust all blocks we have a ref for
refs*: BlockRef refs*: BlockRef
StateData* = object
data*: ForkedHashedBeaconState
blck*: BlockRef ##\
## The block associated with the state found in data
BlockSlot* = object BlockSlot* = object
## Unique identifier for a particular fork and time in the block chain - ## Unique identifier for a particular fork and time in the block chain -
## normally, there's a block for every slot, but in the case a block is not ## normally, there's a block for every slot, but in the case a block is not

View File

@ -14,10 +14,10 @@ import
../ssz/[ssz_serialization, merkleization], ../beacon_chain_db, ../extras, ../ssz/[ssz_serialization, merkleization], ../beacon_chain_db, ../extras,
../spec/[ ../spec/[
crypto, digest, helpers, validator, state_transition, crypto, digest, helpers, validator, state_transition,
beaconstate], beaconstate, forkedbeaconstate_helpers],
../spec/datatypes/[phase0, altair], ../spec/datatypes/[phase0, altair],
../beacon_clock, ../beacon_clock,
"."/[block_pools_types, block_quarantine, statedata_helpers] "."/[block_pools_types, block_quarantine]
export block_pools_types, helpers, phase0 export block_pools_types, helpers, phase0
@ -57,10 +57,8 @@ template withStateVars*(
## Inject a few more descriptive names for the members of `stateData` - ## Inject a few more descriptive names for the members of `stateData` -
## the stateData instance may get mutated through these names as well ## the stateData instance may get mutated through these names as well
template stateData(): StateData {.inject, used.} = stateDataInternal template stateData(): StateData {.inject, used.} = stateDataInternal
template hashedState(): HashedBeaconState {.inject, used.} =
stateDataInternal.data
template stateRoot(): Eth2Digest {.inject, used.} = template stateRoot(): Eth2Digest {.inject, used.} =
stateDataInternal.data.root getStateRoot(stateDataInternal.data)
template blck(): BlockRef {.inject, used.} = stateDataInternal.blck template blck(): BlockRef {.inject, used.} = stateDataInternal.blck
template root(): Eth2Digest {.inject, used.} = stateDataInternal.data.root template root(): Eth2Digest {.inject, used.} = stateDataInternal.data.root
@ -140,20 +138,20 @@ func init*(
T: type EpochRef, dag: ChainDAGRef, state: StateData, T: type EpochRef, dag: ChainDAGRef, state: StateData,
cache: var StateCache): T = cache: var StateCache): T =
let let
epoch = state.get_current_epoch() epoch = state.data.get_current_epoch()
epochRef = EpochRef( epochRef = EpochRef(
dag: dag, # This gives access to the validator pubkeys through an EpochRef dag: dag, # This gives access to the validator pubkeys through an EpochRef
key: state.blck.epochAncestor(epoch), key: state.blck.epochAncestor(epoch),
eth1_data: getStateField(state, eth1_data), eth1_data: getStateField(state.data, eth1_data),
eth1_deposit_index: getStateField(state, eth1_deposit_index), eth1_deposit_index: getStateField(state.data, eth1_deposit_index),
current_justified_checkpoint: current_justified_checkpoint:
getStateField(state, current_justified_checkpoint), getStateField(state.data, current_justified_checkpoint),
finalized_checkpoint: getStateField(state, finalized_checkpoint), finalized_checkpoint: getStateField(state.data, finalized_checkpoint),
shuffled_active_validator_indices: shuffled_active_validator_indices:
cache.get_shuffled_active_validator_indices(state, epoch)) cache.get_shuffled_active_validator_indices(state.data, epoch))
for i in 0'u64..<SLOTS_PER_EPOCH: for i in 0'u64..<SLOTS_PER_EPOCH:
epochRef.beacon_proposers[i] = get_beacon_proposer_index( epochRef.beacon_proposers[i] = get_beacon_proposer_index(
state.data.data, cache, epoch.compute_start_slot_at_epoch() + i) state.data, cache, epoch.compute_start_slot_at_epoch() + i)
# When fork choice runs, it will need the effective balance of the justified # When fork choice runs, it will need the effective balance of the justified
# checkpoint - we pre-load the balances here to avoid rewinding the justified # checkpoint - we pre-load the balances here to avoid rewinding the justified
@ -168,7 +166,8 @@ func init*(
epochRef.effective_balances_bytes = epochRef.effective_balances_bytes =
snappyEncode(SSZ.encode( snappyEncode(SSZ.encode(
List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT](get_effective_balances( List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT](get_effective_balances(
getStateField(state, validators).asSeq, get_current_epoch(state))))) getStateField(state.data, validators).asSeq,
get_current_epoch(state.data)))))
epochRef epochRef
@ -391,8 +390,8 @@ proc init*(T: type ChainDAGRef,
if cur.isStateCheckpoint(): if cur.isStateCheckpoint():
let root = db.getStateRoot(cur.blck.root, cur.slot) let root = db.getStateRoot(cur.blck.root, cur.slot)
if root.isSome(): if root.isSome():
if db.getState(root.get(), tmpState.data.data, noRollback): if db.getState(root.get(), tmpState.data.hbsPhase0.data, noRollback):
tmpState.data.root = root.get() tmpState.data.hbsPhase0.root = root.get()
tmpState.blck = cur.blck tmpState.blck = cur.blck
break break
@ -431,7 +430,7 @@ proc init*(T: type ChainDAGRef,
# When we start from a snapshot state, the `finalized_checkpoint` in the # When we start from a snapshot state, the `finalized_checkpoint` in the
# snapshot will point to an even older state, but we trust the tail state # snapshot will point to an even older state, but we trust the tail state
# (the snapshot) to be finalized, hence the `max` expression below. # (the snapshot) to be finalized, hence the `max` expression below.
let finalizedEpoch = max(getStateField(dag.headState, finalized_checkpoint).epoch, let finalizedEpoch = max(getStateField(dag.headState.data, finalized_checkpoint).epoch,
tailRef.slot.epoch) tailRef.slot.epoch)
dag.finalizedHead = headRef.atEpochStart(finalizedEpoch) dag.finalizedHead = headRef.atEpochStart(finalizedEpoch)
@ -452,7 +451,7 @@ func getEpochRef*(
dag: ChainDAGRef, state: StateData, cache: var StateCache): EpochRef = dag: ChainDAGRef, state: StateData, cache: var StateCache): EpochRef =
let let
blck = state.blck blck = state.blck
epoch = state.get_current_epoch() epoch = state.data.get_current_epoch()
var epochRef = dag.findEpochRef(blck, epoch) var epochRef = dag.findEpochRef(blck, epoch)
if epochRef == nil: if epochRef == nil:
@ -509,13 +508,13 @@ proc getState(
unsafeAddr dag.headState unsafeAddr dag.headState
func restore(v: var phase0.BeaconState) = func restore(v: var phase0.BeaconState) =
assign(v, restoreAddr[].data.data) assign(v, restoreAddr[].data.hbsPhase0.data)
if not dag.db.getState(stateRoot, state.data.data, restore): if not dag.db.getState(stateRoot, state.data.hbsPhase0.data, restore):
return false return false
state.blck = blck state.blck = blck
state.data.root = stateRoot state.data.hbsPhase0.root = stateRoot
true true
@ -543,25 +542,25 @@ proc putState(dag: ChainDAGRef, state: var StateData) =
# Store a state and its root # Store a state and its root
logScope: logScope:
blck = shortLog(state.blck) blck = shortLog(state.blck)
stateSlot = shortLog(getStateField(state, slot)) stateSlot = shortLog(getStateField(state.data, slot))
stateRoot = shortLog(state.data.root) stateRoot = shortLog(getStateRoot(state.data))
if not isStateCheckpoint(state.blck.atSlot(getStateField(state, slot))): if not isStateCheckpoint(state.blck.atSlot(getStateField(state.data, slot))):
return return
# Don't consider legacy tables here, they are slow to read so we'll want to # Don't consider legacy tables here, they are slow to read so we'll want to
# rewrite things in the new database anyway. # rewrite things in the new database anyway.
if dag.db.containsState(state.data.root, legacy = false): if dag.db.containsState(getStateRoot(state.data), legacy = false):
return return
let startTick = Moment.now() let startTick = Moment.now()
# Ideally we would save the state and the root lookup cache in a single # Ideally we would save the state and the root lookup cache in a single
# transaction to prevent database inconsistencies, but the state loading code # transaction to prevent database inconsistencies, but the state loading code
# is resilient against one or the other going missing # is resilient against one or the other going missing
dag.db.putState(state.data.root, state.data.data) dag.db.putState(getStateRoot(state.data), state.data.hbsPhase0.data)
dag.db.putStateRoot( dag.db.putStateRoot(
state.blck.root, getStateField(state, slot), state.data.root) state.blck.root, getStateField(state.data, slot), getStateRoot(state.data))
debug "Stored state", putStateDur = Moment.now() - startTick debug "Stored state", putStateDur = Moment.now() - startTick
@ -659,13 +658,13 @@ proc advanceSlots(
# Given a state, advance it zero or more slots by applying empty slot # Given a state, advance it zero or more slots by applying empty slot
# processing - the state must be positions at a slot before or equal to the # processing - the state must be positions at a slot before or equal to the
# target # target
doAssert getStateField(state, slot) <= slot doAssert getStateField(state.data, slot) <= slot
while getStateField(state, slot) < slot: while getStateField(state.data, slot) < slot:
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch) loadStateCache(dag, cache, state.blck, getStateField(state.data, slot).epoch)
doAssert process_slots( doAssert process_slots(
state.data, getStateField(state, slot) + 1, cache, rewards, state.data, getStateField(state.data, slot) + 1, cache, rewards,
dag.updateFlags), dag.updateFlags, FAR_FUTURE_SLOT),
"process_slots shouldn't fail when state slot is correct" "process_slots shouldn't fail when state slot is correct"
if save: if save:
dag.putState(state) dag.putState(state)
@ -680,11 +679,12 @@ proc applyBlock(
doAssert state.blck == blck.refs.parent doAssert state.blck == blck.refs.parent
var statePtr = unsafeAddr state # safe because `restore` is locally scoped var statePtr = unsafeAddr state # safe because `restore` is locally scoped
func restore(v: var phase0.HashedBeaconState) = func restore(v: var ForkedHashedBeaconState) =
doAssert (addr(statePtr.data) == addr v) doAssert (addr(statePtr.data) == addr v)
# TODO the block_clearance version uses assign() here
statePtr[] = dag.headState statePtr[] = dag.headState
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch) loadStateCache(dag, cache, state.blck, getStateField(state.data, slot).epoch)
let ok = state_transition( let ok = state_transition(
dag.runtimePreset, state.data, blck.data, dag.runtimePreset, state.data, blck.data,
@ -718,12 +718,12 @@ proc updateStateData*(
template exactMatch(state: StateData, bs: BlockSlot): bool = template exactMatch(state: StateData, bs: BlockSlot): bool =
# The block is the same and we're at an early enough slot - the state can # The block is the same and we're at an early enough slot - the state can
# be used to arrive at the desired blockslot # be used to arrive at the desired blockslot
state.blck == bs.blck and getStateField(state, slot) == bs.slot state.blck == bs.blck and getStateField(state.data, slot) == bs.slot
template canAdvance(state: StateData, bs: BlockSlot): bool = template canAdvance(state: StateData, bs: BlockSlot): bool =
# The block is the same and we're at an early enough slot - the state can # The block is the same and we're at an early enough slot - the state can
# be used to arrive at the desired blockslot # be used to arrive at the desired blockslot
state.blck == bs.blck and getStateField(state, slot) <= bs.slot state.blck == bs.blck and getStateField(state.data, slot) <= bs.slot
# Fast path: check all caches for an exact match - this is faster than # Fast path: check all caches for an exact match - this is faster than
# advancing a state where there's epoch processing to do, by a wide margin - # advancing a state where there's epoch processing to do, by a wide margin -
@ -781,7 +781,7 @@ proc updateStateData*(
if not found: if not found:
debug "UpdateStateData cache miss", debug "UpdateStateData cache miss",
bs, stateBlock = state.blck, stateSlot = getStateField(state, slot) bs, stateBlock = state.blck, stateSlot = getStateField(state.data, slot)
# Either the state is too new or was created by applying a different block. # Either the state is too new or was created by applying a different block.
# We'll now resort to loading the state from the database then reapplying # We'll now resort to loading the state from the database then reapplying
@ -817,8 +817,8 @@ proc updateStateData*(
# Starting state has been assigned, either from memory or database # Starting state has been assigned, either from memory or database
let let
assignTick = Moment.now() assignTick = Moment.now()
startSlot {.used.} = getStateField(state, slot) # used in logs below startSlot {.used.} = getStateField(state.data, slot) # used in logs below
startRoot {.used.} = state.data.root startRoot {.used.} = getStateRoot(state.data)
var rewards: RewardInfo var rewards: RewardInfo
# Time to replay all the blocks between then and now # Time to replay all the blocks between then and now
for i in countdown(ancestors.len - 1, 0): for i in countdown(ancestors.len - 1, 0):
@ -834,7 +834,7 @@ proc updateStateData*(
dag.advanceSlots(state, bs.slot, save, cache, rewards) dag.advanceSlots(state, bs.slot, save, cache, rewards)
# ...and make sure to load the state cache, if it exists # ...and make sure to load the state cache, if it exists
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch) loadStateCache(dag, cache, state.blck, getStateField(state.data, slot).epoch)
let let
assignDur = assignTick - startTick assignDur = assignTick - startTick
@ -842,9 +842,9 @@ proc updateStateData*(
logScope: logScope:
blocks = ancestors.len blocks = ancestors.len
slots = getStateField(state, slot) - startSlot slots = getStateField(state.data, slot) - startSlot
stateRoot = shortLog(state.data.root) stateRoot = shortLog(getStateRoot(state.data))
stateSlot = getStateField(state, slot) stateSlot = getStateField(state.data, slot)
startRoot = shortLog(startRoot) startRoot = shortLog(startRoot)
startSlot startSlot
blck = shortLog(bs) blck = shortLog(bs)
@ -993,7 +993,7 @@ proc updateHead*(
let let
finalizedHead = newHead.atEpochStart( finalizedHead = newHead.atEpochStart(
getStateField(dag.headState, finalized_checkpoint).epoch) getStateField(dag.headState.data, finalized_checkpoint).epoch)
doAssert (not finalizedHead.blck.isNil), doAssert (not finalizedHead.blck.isNil),
"Block graph should always lead to a finalized block" "Block graph should always lead to a finalized block"
@ -1002,33 +1002,34 @@ proc updateHead*(
notice "Updated head block with chain reorg", notice "Updated head block with chain reorg",
lastHead = shortLog(lastHead), lastHead = shortLog(lastHead),
headParent = shortLog(newHead.parent), headParent = shortLog(newHead.parent),
stateRoot = shortLog(dag.headState.data.root), stateRoot = shortLog(getStateRoot(dag.headState.data)),
headBlock = shortLog(dag.headState.blck), headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(getStateField(dag.headState, slot)), stateSlot = shortLog(getStateField(dag.headState.data, slot)),
justified = justified = shortLog(getStateField(
shortLog(getStateField(dag.headState, current_justified_checkpoint)), dag.headState.data, current_justified_checkpoint)),
finalized = shortLog(getStateField(dag.headState, finalized_checkpoint)) finalized = shortLog(getStateField(
dag.headState.data, finalized_checkpoint))
# A reasonable criterion for "reorganizations of the chain" # A reasonable criterion for "reorganizations of the chain"
quarantine.clearQuarantine() quarantine.clearQuarantine()
beacon_reorgs_total.inc() beacon_reorgs_total.inc()
else: else:
debug "Updated head block", debug "Updated head block",
stateRoot = shortLog(dag.headState.data.root), stateRoot = shortLog(getStateRoot(dag.headState.data)),
headBlock = shortLog(dag.headState.blck), headBlock = shortLog(dag.headState.blck),
stateSlot = shortLog(getStateField(dag.headState, slot)), stateSlot = shortLog(getStateField(dag.headState.data, slot)),
justified = shortLog(getStateField( justified = shortLog(getStateField(
dag.headState, current_justified_checkpoint)), dag.headState.data, current_justified_checkpoint)),
finalized = shortLog(getStateField( finalized = shortLog(getStateField(
dag.headState, finalized_checkpoint)) dag.headState.data, finalized_checkpoint))
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics # https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#additional-metrics
# both non-negative, so difference can't overflow or underflow int64 # both non-negative, so difference can't overflow or underflow int64
beacon_pending_deposits.set( beacon_pending_deposits.set(
getStateField(dag.headState, eth1_data).deposit_count.toGaugeValue - getStateField(dag.headState.data, eth1_data).deposit_count.toGaugeValue -
getStateField(dag.headState, eth1_deposit_index).toGaugeValue) getStateField(dag.headState.data, eth1_deposit_index).toGaugeValue)
beacon_processed_deposits_total.set( beacon_processed_deposits_total.set(
getStateField(dag.headState, eth1_deposit_index).toGaugeValue) getStateField(dag.headState.data, eth1_deposit_index).toGaugeValue)
beacon_head_root.set newHead.root.toGaugeValue beacon_head_root.set newHead.root.toGaugeValue
beacon_head_slot.set newHead.slot.toGaugeValue beacon_head_slot.set newHead.slot.toGaugeValue
@ -1039,16 +1040,16 @@ proc updateHead*(
# updating them until a block confirms the change # updating them until a block confirms the change
beacon_current_justified_epoch.set( beacon_current_justified_epoch.set(
getStateField( getStateField(
dag.headState, current_justified_checkpoint).epoch.toGaugeValue) dag.headState.data, current_justified_checkpoint).epoch.toGaugeValue)
beacon_current_justified_root.set( beacon_current_justified_root.set(
getStateField( getStateField(
dag.headState, current_justified_checkpoint).root.toGaugeValue) dag.headState.data, current_justified_checkpoint).root.toGaugeValue)
beacon_previous_justified_epoch.set( beacon_previous_justified_epoch.set(
getStateField( getStateField(
dag.headState, previous_justified_checkpoint).epoch.toGaugeValue) dag.headState.data, previous_justified_checkpoint).epoch.toGaugeValue)
beacon_previous_justified_root.set( beacon_previous_justified_root.set(
getStateField( getStateField(
dag.headState, previous_justified_checkpoint).root.toGaugeValue) dag.headState.data, previous_justified_checkpoint).root.toGaugeValue)
let epochRef = getEpochRef(dag, newHead, newHead.slot.epoch) let epochRef = getEpochRef(dag, newHead, newHead.slot.epoch)
beacon_active_validators.set( beacon_active_validators.set(
@ -1061,10 +1062,10 @@ proc updateHead*(
dag.finalizedHead = finalizedHead dag.finalizedHead = finalizedHead
beacon_finalized_epoch.set( beacon_finalized_epoch.set(getStateField(
getStateField(dag.headState, finalized_checkpoint).epoch.toGaugeValue) dag.headState.data, finalized_checkpoint).epoch.toGaugeValue)
beacon_finalized_root.set( beacon_finalized_root.set(getStateField(
getStateField(dag.headState, finalized_checkpoint).root.toGaugeValue) dag.headState.data, finalized_checkpoint).root.toGaugeValue)
# Pruning the block dag is required every time the finalized head changes # Pruning the block dag is required every time the finalized head changes
# in order to clear out blocks that are no longer viable and should # in order to clear out blocks that are no longer viable and should

View File

@ -13,7 +13,7 @@ import
# Status libraries # Status libraries
chronicles, chronicles,
# Internal # Internal
../spec/[crypto, datatypes, helpers], ../spec/[crypto, datatypes, forkedbeaconstate_helpers, helpers],
"."/[blockchain_dag, block_quarantine], "."/[blockchain_dag, block_quarantine],
../beacon_node_types ../beacon_node_types
@ -111,7 +111,7 @@ func getExitMessagesForBlock[T](
if allIt( if allIt(
getValidatorIndices(exit_message), getValidatorIndices(exit_message),
getStateField(pool.dag.headState, validators)[it].exit_epoch != getStateField(pool.dag.headState.data, validators)[it].exit_epoch !=
FAR_FUTURE_EPOCH): FAR_FUTURE_EPOCH):
# A beacon block exit message already targeted all these validators # A beacon block exit message already targeted all these validators
continue continue

View File

@ -1,61 +0,0 @@
# beacon_chain
# Copyright (c) 2021 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.push raises: [Defect].}
import
../spec/[beaconstate, datatypes, digest, helpers, presets, validator]
# State-related functionality based on StateData instead of BeaconState
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(stateData: StateData): Epoch =
## Return the current epoch.
getStateField(stateData, slot).epoch
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_previous_epoch
func get_previous_epoch*(stateData: StateData): Epoch =
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
let current_epoch = get_current_epoch(stateData)
if current_epoch == GENESIS_EPOCH:
GENESIS_EPOCH
else:
current_epoch - 1
# Dispatch functions
func get_beacon_committee*(
state: StateData, slot: Slot, index: CommitteeIndex,
cache: var StateCache): seq[ValidatorIndex] =
# This one is used by tests/, ncli/, and a couple of places in RPC
# TODO use the iterator version alone, to remove the risk of using
# diverging get_beacon_committee() in tests and beacon_chain/ by a
# wrapper approach (e.g., toSeq). This is a perf tradeoff for test
# correctness/consistency.
get_beacon_committee(state.data.data, slot, index, cache)
func get_committee_count_per_slot*(state: StateData,
epoch: Epoch,
cache: var StateCache): uint64 =
# Return the number of committees at ``epoch``.
get_committee_count_per_slot(state.data.data, epoch, cache)
template hash_tree_root*(stateData: StateData): Eth2Digest =
# Dispatch here based on type/fork of state. Since StateData is a ref object
# type, if Nim chooses the wrong overload, it will simply fail to compile.
stateData.data.root
func get_shuffled_active_validator_indices*(
cache: var StateCache, state: StateData, epoch: Epoch):
var seq[ValidatorIndex] =
cache.get_shuffled_active_validator_indices(state.data.data, epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: StateData,
slot: Slot): Eth2Digest =
## Return the block root at a recent ``slot``.
get_block_root_at_slot(state.data.data, slot)

View File

@ -15,7 +15,7 @@ import
web3, web3/ethtypes as web3Types, web3/ethhexstrings, eth/common/eth_types, web3, web3/ethtypes as web3Types, web3/ethhexstrings, eth/common/eth_types,
eth/async_utils, stew/byteutils, eth/async_utils, stew/byteutils,
# Local modules: # Local modules:
../spec/[datatypes, digest, crypto, helpers], ../spec/[datatypes, digest, crypto, forkedbeaconstate_helpers, helpers],
../networking/network_metadata, ../networking/network_metadata,
../consensus_object_pools/block_pools_types, ../consensus_object_pools/block_pools_types,
../ssz, ../ssz,
@ -281,15 +281,16 @@ template toGaugeValue(x: Quantity): int64 =
# "Invalid configuration: GENESIS_DELAY is set too low" # "Invalid configuration: GENESIS_DELAY is set too low"
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data
func compute_time_at_slot(state: StateData, slot: Slot): uint64 = func compute_time_at_slot(genesis_time: uint64, slot: Slot): uint64 =
getStateField(state, genesis_time) + slot * SECONDS_PER_SLOT genesis_time + slot * SECONDS_PER_SLOT
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data
func voting_period_start_time*(state: StateData): uint64 = func voting_period_start_time*(state: ForkedHashedBeaconState): uint64 =
let eth1_voting_period_start_slot = let eth1_voting_period_start_slot =
getStateField(state, slot) - getStateField(state, slot) mod getStateField(state, slot) - getStateField(state, slot) mod
SLOTS_PER_ETH1_VOTING_PERIOD.uint64 SLOTS_PER_ETH1_VOTING_PERIOD.uint64
compute_time_at_slot(state, eth1_voting_period_start_slot) compute_time_at_slot(
getStateField(state, genesis_time), eth1_voting_period_start_slot)
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data
func is_candidate_block(preset: RuntimePreset, func is_candidate_block(preset: RuntimePreset,
@ -696,7 +697,7 @@ template trackFinalizedState*(m: Eth1Monitor,
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#get_eth1_data
proc getBlockProposalData*(chain: var Eth1Chain, proc getBlockProposalData*(chain: var Eth1Chain,
state: StateData, state: ForkedHashedBeaconState,
finalizedEth1Data: Eth1Data, finalizedEth1Data: Eth1Data,
finalizedStateDepositIndex: uint64): BlockProposalEth1Data = finalizedStateDepositIndex: uint64): BlockProposalEth1Data =
let let
@ -764,7 +765,7 @@ proc getBlockProposalData*(chain: var Eth1Chain,
result.hasMissingDeposits = true result.hasMissingDeposits = true
template getBlockProposalData*(m: Eth1Monitor, template getBlockProposalData*(m: Eth1Monitor,
state: StateData, state: ForkedHashedBeaconState,
finalizedEth1Data: Eth1Data, finalizedEth1Data: Eth1Data,
finalizedStateDepositIndex: uint64): BlockProposalEth1Data = finalizedStateDepositIndex: uint64): BlockProposalEth1Data =
getBlockProposalData(m.eth1Chain, state, finalizedEth1Data, finalizedStateDepositIndex) getBlockProposalData(m.eth1Chain, state, finalizedEth1Data, finalizedStateDepositIndex)

View File

@ -30,5 +30,9 @@ type
slotProcessed ##\ slotProcessed ##\
## Allow blocks to be applied to states with the same slot number as the ## Allow blocks to be applied to states with the same slot number as the
## block which is what happens when `process_block` is called separately ## block which is what happens when `process_block` is called separately
skipLastStateRootCalculation ##\
## When process_slots() is being called as part of a state_transition(),
## the hash_tree_root() from the block will fill in the state.root so it
## should skip calculating that last state root.
UpdateFlags* = set[UpdateFlag] UpdateFlags* = set[UpdateFlag]

View File

@ -16,7 +16,8 @@ import
# Internals # Internals
../spec/[ ../spec/[
beaconstate, state_transition_block, beaconstate, state_transition_block,
datatypes, crypto, digest, helpers, network, signatures], datatypes, crypto, digest, forkedbeaconstate_helpers, helpers, network,
signatures],
../consensus_object_pools/[ ../consensus_object_pools/[
spec_cache, blockchain_dag, block_quarantine, spec_cache, spec_cache, blockchain_dag, block_quarantine, spec_cache,
attestation_pool, exit_pool attestation_pool, exit_pool
@ -249,9 +250,9 @@ proc validateAttestation*(
"validateAttestation: number of aggregation bits and committee size mismatch"))) "validateAttestation: number of aggregation bits and committee size mismatch")))
let let
fork = getStateField(pool.dag.headState, fork) fork = getStateField(pool.dag.headState.data, fork)
genesis_validators_root = genesis_validators_root =
getStateField(pool.dag.headState, genesis_validators_root) getStateField(pool.dag.headState.data, genesis_validators_root)
attesting_index = get_attesting_indices_one( attesting_index = get_attesting_indices_one(
epochRef, attestation.data, attestation.aggregation_bits) epochRef, attestation.data, attestation.aggregation_bits)
@ -428,9 +429,9 @@ proc validateAggregate*(
# 3. [REJECT] The signature of aggregate is valid. # 3. [REJECT] The signature of aggregate is valid.
let let
fork = getStateField(pool.dag.headState, fork) fork = getStateField(pool.dag.headState.data, fork)
genesis_validators_root = genesis_validators_root =
getStateField(pool.dag.headState, genesis_validators_root) getStateField(pool.dag.headState.data, genesis_validators_root)
let deferredCrypto = batchCrypto let deferredCrypto = batchCrypto
.scheduleAggregateChecks( .scheduleAggregateChecks(
@ -593,7 +594,8 @@ proc isValidBeaconBlock*(
# compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) == # compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) ==
# store.finalized_checkpoint.root # store.finalized_checkpoint.root
let let
finalized_checkpoint = getStateField(dag.headState, finalized_checkpoint) finalized_checkpoint = getStateField(
dag.headState.data, finalized_checkpoint)
ancestor = get_ancestor( ancestor = get_ancestor(
parent_ref, compute_start_slot_at_epoch(finalized_checkpoint.epoch)) parent_ref, compute_start_slot_at_epoch(finalized_checkpoint.epoch))
@ -626,8 +628,8 @@ proc isValidBeaconBlock*(
# [REJECT] The proposer signature, signed_beacon_block.signature, is valid # [REJECT] The proposer signature, signed_beacon_block.signature, is valid
# with respect to the proposer_index pubkey. # with respect to the proposer_index pubkey.
if not verify_block_signature( if not verify_block_signature(
getStateField(dag.headState, fork), getStateField(dag.headState.data, fork),
getStateField(dag.headState, genesis_validators_root), getStateField(dag.headState.data, genesis_validators_root),
signed_beacon_block.message.slot, signed_beacon_block.message.slot,
signed_beacon_block.message, signed_beacon_block.message,
dag.validatorKey(proposer.get()).get(), dag.validatorKey(proposer.get()).get(),
@ -666,8 +668,7 @@ proc validateAttesterSlashing*(
# [REJECT] All of the conditions within process_attester_slashing pass # [REJECT] All of the conditions within process_attester_slashing pass
# validation. # validation.
let attester_slashing_validity = let attester_slashing_validity =
check_attester_slashing( check_attester_slashing(pool.dag.headState.data, attester_slashing, {})
pool.dag.headState.data.data, attester_slashing, {})
if attester_slashing_validity.isErr: if attester_slashing_validity.isErr:
return err((ValidationResult.Reject, attester_slashing_validity.error)) return err((ValidationResult.Reject, attester_slashing_validity.error))
@ -696,8 +697,7 @@ proc validateProposerSlashing*(
# [REJECT] All of the conditions within process_proposer_slashing pass validation. # [REJECT] All of the conditions within process_proposer_slashing pass validation.
let proposer_slashing_validity = let proposer_slashing_validity =
check_proposer_slashing( check_proposer_slashing(pool.dag.headState.data, proposer_slashing, {})
pool.dag.headState.data.data, proposer_slashing, {})
if proposer_slashing_validity.isErr: if proposer_slashing_validity.isErr:
return err((ValidationResult.Reject, proposer_slashing_validity.error)) return err((ValidationResult.Reject, proposer_slashing_validity.error))
@ -715,7 +715,7 @@ proc validateVoluntaryExit*(
# [IGNORE] The voluntary exit is the first valid voluntary exit received for # [IGNORE] The voluntary exit is the first valid voluntary exit received for
# the validator with index signed_voluntary_exit.message.validator_index. # the validator with index signed_voluntary_exit.message.validator_index.
if signed_voluntary_exit.message.validator_index >= if signed_voluntary_exit.message.validator_index >=
getStateField(pool.dag.headState, validators).lenu64: getStateField(pool.dag.headState.data, validators).lenu64:
return err((ValidationResult.Ignore, cstring( return err((ValidationResult.Ignore, cstring(
"validateVoluntaryExit: validator index too high"))) "validateVoluntaryExit: validator index too high")))
@ -730,8 +730,7 @@ proc validateVoluntaryExit*(
# [REJECT] All of the conditions within process_voluntary_exit pass # [REJECT] All of the conditions within process_voluntary_exit pass
# validation. # validation.
let voluntary_exit_validity = let voluntary_exit_validity =
check_voluntary_exit( check_voluntary_exit(pool.dag.headState.data, signed_voluntary_exit, {})
pool.dag.headState.data.data, signed_voluntary_exit, {})
if voluntary_exit_validity.isErr: if voluntary_exit_validity.isErr:
return err((ValidationResult.Reject, voluntary_exit_validity.error)) return err((ValidationResult.Reject, voluntary_exit_validity.error))

View File

@ -40,8 +40,9 @@ import
./rpc/[beacon_api, config_api, debug_api, event_api, nimbus_api, node_api, ./rpc/[beacon_api, config_api, debug_api, event_api, nimbus_api, node_api,
validator_api], validator_api],
./spec/[ ./spec/[
datatypes, digest, crypto, beaconstate, eth2_apis/beacon_rpc_client, datatypes, digest, crypto, forkedbeaconstate_helpers, beaconstate,
helpers, network, presets, weak_subjectivity, signatures], eth2_apis/beacon_rpc_client, helpers, network, presets, weak_subjectivity,
signatures],
./consensus_object_pools/[ ./consensus_object_pools/[
blockchain_dag, block_quarantine, block_clearance, block_pools_types, blockchain_dag, block_quarantine, block_clearance, block_pools_types,
attestation_pool, exit_pool, spec_cache], attestation_pool, exit_pool, spec_cache],
@ -245,10 +246,10 @@ proc init*(T: type BeaconNode,
else: {} else: {}
dag = ChainDAGRef.init(runtimePreset, db, chainDagFlags) dag = ChainDAGRef.init(runtimePreset, db, chainDagFlags)
beaconClock = beaconClock =
BeaconClock.init(getStateField(dag.headState, genesis_time)) BeaconClock.init(getStateField(dag.headState.data, genesis_time))
quarantine = QuarantineRef.init(rng) quarantine = QuarantineRef.init(rng)
databaseGenesisValidatorsRoot = databaseGenesisValidatorsRoot =
getStateField(dag.headState, genesis_validators_root) getStateField(dag.headState.data, genesis_validators_root)
if genesisStateContents.len != 0: if genesisStateContents.len != 0:
let let
@ -266,14 +267,14 @@ proc init*(T: type BeaconNode,
currentSlot = beaconClock.now.slotOrZero currentSlot = beaconClock.now.slotOrZero
isCheckpointStale = not is_within_weak_subjectivity_period( isCheckpointStale = not is_within_weak_subjectivity_period(
currentSlot, currentSlot,
dag.headState, dag.headState.data,
config.weakSubjectivityCheckpoint.get) config.weakSubjectivityCheckpoint.get)
if isCheckpointStale: if isCheckpointStale:
error "Weak subjectivity checkpoint is stale", error "Weak subjectivity checkpoint is stale",
currentSlot, currentSlot,
checkpoint = config.weakSubjectivityCheckpoint.get, checkpoint = config.weakSubjectivityCheckpoint.get,
headStateSlot = getStateField(dag.headState, slot) headStateSlot = getStateField(dag.headState.data, slot)
quit 1 quit 1
if checkpointState != nil: if checkpointState != nil:
@ -314,8 +315,8 @@ proc init*(T: type BeaconNode,
nickname = if config.nodeName == "auto": shortForm(netKeys) nickname = if config.nodeName == "auto": shortForm(netKeys)
else: config.nodeName else: config.nodeName
enrForkId = getENRForkID( enrForkId = getENRForkID(
getStateField(dag.headState, fork), getStateField(dag.headState.data, fork),
getStateField(dag.headState, genesis_validators_root)) getStateField(dag.headState.data, genesis_validators_root))
topicBeaconBlocks = getBeaconBlocksTopic(enrForkId.fork_digest) topicBeaconBlocks = getBeaconBlocksTopic(enrForkId.fork_digest)
topicAggregateAndProofs = getAggregateAndProofsTopic(enrForkId.fork_digest) topicAggregateAndProofs = getAggregateAndProofsTopic(enrForkId.fork_digest)
network = createEth2Node(rng, config, netKeys, enrForkId) network = createEth2Node(rng, config, netKeys, enrForkId)
@ -337,7 +338,7 @@ proc init*(T: type BeaconNode,
let let
slashingProtectionDB = slashingProtectionDB =
SlashingProtectionDB.init( SlashingProtectionDB.init(
getStateField(dag.headState, genesis_validators_root), getStateField(dag.headState.data, genesis_validators_root),
config.validatorsDir(), SlashingDbName) config.validatorsDir(), SlashingDbName)
validatorPool = newClone(ValidatorPool.init(slashingProtectionDB)) validatorPool = newClone(ValidatorPool.init(slashingProtectionDB))
@ -442,9 +443,9 @@ func toBitArray(stabilitySubnets: auto): BitArray[ATTESTATION_SUBNET_COUNT] =
proc getAttachedValidators(node: BeaconNode): proc getAttachedValidators(node: BeaconNode):
Table[ValidatorIndex, AttachedValidator] = Table[ValidatorIndex, AttachedValidator] =
for validatorIndex in 0 ..< for validatorIndex in 0 ..<
getStateField(node.dag.headState, validators).len: getStateField(node.dag.headState.data, validators).len:
let attachedValidator = node.getAttachedValidator( let attachedValidator = node.getAttachedValidator(
getStateField(node.dag.headState, validators), getStateField(node.dag.headState.data, validators),
validatorIndex.ValidatorIndex) validatorIndex.ValidatorIndex)
if attachedValidator.isNil: if attachedValidator.isNil:
continue continue
@ -476,9 +477,9 @@ proc updateSubscriptionSchedule(node: BeaconNode, epoch: Epoch) {.async.} =
is_aggregator( is_aggregator(
committeeLen, committeeLen,
await attachedValidators[it.ValidatorIndex].getSlotSig( await attachedValidators[it.ValidatorIndex].getSlotSig(
getStateField(node.dag.headState, fork), getStateField(node.dag.headState.data, fork),
getStateField( getStateField(
node.dag.headState, genesis_validators_root), slot))) node.dag.headState.data, genesis_validators_root), slot)))
node.attestationSubnets.lastCalculatedEpoch = epoch node.attestationSubnets.lastCalculatedEpoch = epoch
node.attestationSubnets.attestingSlots[epoch mod 2] = 0 node.attestationSubnets.attestingSlots[epoch mod 2] = 0
@ -557,10 +558,10 @@ proc cycleAttestationSubnetsPerEpoch(
# wallSlot, it would have to look more than MIN_SEED_LOOKAHEAD epochs # wallSlot, it would have to look more than MIN_SEED_LOOKAHEAD epochs
# ahead to compute the shuffling determining the beacon committees. # ahead to compute the shuffling determining the beacon committees.
static: doAssert MIN_SEED_LOOKAHEAD == 1 static: doAssert MIN_SEED_LOOKAHEAD == 1
if getStateField(node.dag.headState, slot).epoch != wallSlot.epoch: if getStateField(node.dag.headState.data, slot).epoch != wallSlot.epoch:
debug "Requested attestation subnets too far in advance", debug "Requested attestation subnets too far in advance",
wallSlot, wallSlot,
stateSlot = getStateField(node.dag.headState, slot) stateSlot = getStateField(node.dag.headState.data, slot)
return prevStabilitySubnets return prevStabilitySubnets
# This works so long as at least one block in an epoch provides a basis for # This works so long as at least one block in an epoch provides a basis for
@ -1365,7 +1366,8 @@ proc initStatusBar(node: BeaconNode) {.raises: [Defect, ValueError].} =
proc dataResolver(expr: string): string {.raises: [Defect].} = proc dataResolver(expr: string): string {.raises: [Defect].} =
template justified: untyped = node.dag.head.atEpochStart( template justified: untyped = node.dag.head.atEpochStart(
getStateField(node.dag.headState, current_justified_checkpoint).epoch) getStateField(
node.dag.headState.data, current_justified_checkpoint).epoch)
# TODO: # TODO:
# We should introduce a general API for resolving dot expressions # We should introduce a general API for resolving dot expressions
# such as `db.latest_block.slot` or `metrics.connected_peers`. # such as `db.latest_block.slot` or `metrics.connected_peers`.

View File

@ -17,8 +17,8 @@ import
../networking/eth2_network, ../networking/eth2_network,
../validators/validator_duties, ../validators/validator_duties,
../gossip_processing/gossip_validation, ../gossip_processing/gossip_validation,
../consensus_object_pools/[blockchain_dag, statedata_helpers], ../consensus_object_pools/blockchain_dag,
../spec/[crypto, digest, datatypes, network], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers, network],
../spec/eth2_apis/callsigs_types, ../spec/eth2_apis/callsigs_types,
../ssz/merkleization, ../ssz/merkleization,
./rpc_utils, ./eth2_json_rpc_serialization ./rpc_utils, ./eth2_json_rpc_serialization
@ -182,9 +182,9 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_beacon_genesis") do () -> BeaconGenesisTuple: rpcServer.rpc("get_v1_beacon_genesis") do () -> BeaconGenesisTuple:
return ( return (
genesis_time: getStateField(node.dag.headState, genesis_time), genesis_time: getStateField(node.dag.headState.data, genesis_time),
genesis_validators_root: genesis_validators_root:
getStateField(node.dag.headState, genesis_validators_root), getStateField(node.dag.headState.data, genesis_validators_root),
genesis_fork_version: node.runtimePreset.GENESIS_FORK_VERSION genesis_fork_version: node.runtimePreset.GENESIS_FORK_VERSION
) )
@ -194,23 +194,23 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_beacon_states_fork") do (stateId: string) -> Fork: rpcServer.rpc("get_v1_beacon_states_fork") do (stateId: string) -> Fork:
withStateForStateId(stateId): withStateForStateId(stateId):
return getStateField(stateData, fork) return getStateField(stateData.data, fork)
rpcServer.rpc("get_v1_beacon_states_finality_checkpoints") do ( rpcServer.rpc("get_v1_beacon_states_finality_checkpoints") do (
stateId: string) -> BeaconStatesFinalityCheckpointsTuple: stateId: string) -> BeaconStatesFinalityCheckpointsTuple:
withStateForStateId(stateId): withStateForStateId(stateId):
return (previous_justified: return (previous_justified:
getStateField(stateData, previous_justified_checkpoint), getStateField(stateData.data, previous_justified_checkpoint),
current_justified: current_justified:
getStateField(stateData, current_justified_checkpoint), getStateField(stateData.data, current_justified_checkpoint),
finalized: getStateField(stateData, finalized_checkpoint)) finalized: getStateField(stateData.data, finalized_checkpoint))
rpcServer.rpc("get_v1_beacon_states_stateId_validators") do ( rpcServer.rpc("get_v1_beacon_states_stateId_validators") do (
stateId: string, validatorIds: Option[seq[string]], stateId: string, validatorIds: Option[seq[string]],
status: Option[seq[string]]) -> seq[BeaconStatesValidatorsTuple]: status: Option[seq[string]]) -> seq[BeaconStatesValidatorsTuple]:
var vquery: ValidatorQuery var vquery: ValidatorQuery
var squery: StatusQuery var squery: StatusQuery
let current_epoch = getStateField(node.dag.headState, slot).epoch let current_epoch = getStateField(node.dag.headState.data, slot).epoch
template statusCheck(status, statusQuery, vstatus, current_epoch): bool = template statusCheck(status, statusQuery, vstatus, current_epoch): bool =
if status.isNone(): if status.isNone():
@ -237,7 +237,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
vquery = vqres.get() vquery = vqres.get()
if validatorIds.isNone(): if validatorIds.isNone():
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk: if sres.isOk:
let vstatus = sres.get() let vstatus = sres.get()
@ -247,11 +247,11 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
res.add((validator: validator, res.add((validator: validator,
index: uint64(index), index: uint64(index),
status: vstatus, status: vstatus,
balance: getStateField(stateData, balances)[index])) balance: getStateField(stateData.data, balances)[index]))
else: else:
for index in vquery.ids: for index in vquery.ids:
if index < lenu64(getStateField(stateData, validators)): if index < lenu64(getStateField(stateData.data, validators)):
let validator = getStateField(stateData, validators)[index] let validator = getStateField(stateData.data, validators)[index]
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk: if sres.isOk:
let vstatus = sres.get() let vstatus = sres.get()
@ -262,9 +262,9 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
res.add((validator: validator, res.add((validator: validator,
index: uint64(index), index: uint64(index),
status: vstatus, status: vstatus,
balance: getStateField(stateData, balances)[index])) balance: getStateField(stateData.data, balances)[index]))
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
if validator.pubkey in vquery.keyset: if validator.pubkey in vquery.keyset:
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk: if sres.isOk:
@ -275,12 +275,12 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
res.add((validator: validator, res.add((validator: validator,
index: uint64(index), index: uint64(index),
status: vstatus, status: vstatus,
balance: getStateField(stateData, balances)[index])) balance: getStateField(stateData.data, balances)[index]))
return res return res
rpcServer.rpc("get_v1_beacon_states_stateId_validators_validatorId") do ( rpcServer.rpc("get_v1_beacon_states_stateId_validators_validatorId") do (
stateId: string, validatorId: string) -> BeaconStatesValidatorsTuple: stateId: string, validatorId: string) -> BeaconStatesValidatorsTuple:
let current_epoch = getStateField(node.dag.headState, slot).epoch let current_epoch = getStateField(node.dag.headState.data, slot).epoch
let vqres = createIdQuery([validatorId]) let vqres = createIdQuery([validatorId])
if vqres.isErr: if vqres.isErr:
raise newException(CatchableError, vqres.error) raise newException(CatchableError, vqres.error)
@ -289,23 +289,23 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
withStateForStateId(stateId): withStateForStateId(stateId):
if len(vquery.ids) > 0: if len(vquery.ids) > 0:
let index = vquery.ids[0] let index = vquery.ids[0]
if index < lenu64(getStateField(stateData, validators)): if index < lenu64(getStateField(stateData.data, validators)):
let validator = getStateField(stateData, validators)[index] let validator = getStateField(stateData.data, validators)[index]
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk: if sres.isOk:
return (validator: validator, index: uint64(index), return (validator: validator, index: uint64(index),
status: sres.get(), status: sres.get(),
balance: getStateField(stateData, balances)[index]) balance: getStateField(stateData.data, balances)[index])
else: else:
raise newException(CatchableError, "Incorrect validator's state") raise newException(CatchableError, "Incorrect validator's state")
else: else:
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
if validator.pubkey in vquery.keyset: if validator.pubkey in vquery.keyset:
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk: if sres.isOk:
return (validator: validator, index: uint64(index), return (validator: validator, index: uint64(index),
status: sres.get(), status: sres.get(),
balance: getStateField(stateData, balances)[index]) balance: getStateField(stateData.data, balances)[index])
else: else:
raise newException(CatchableError, "Incorrect validator's state") raise newException(CatchableError, "Incorrect validator's state")
@ -315,7 +315,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
var res: seq[BalanceTuple] var res: seq[BalanceTuple]
withStateForStateId(stateId): withStateForStateId(stateId):
if validatorsId.isNone(): if validatorsId.isNone():
for index, value in getStateField(stateData, balances).pairs(): for index, value in getStateField(stateData.data, balances).pairs():
let balance = (index: uint64(index), balance: value) let balance = (index: uint64(index), balance: value)
res.add(balance) res.add(balance)
else: else:
@ -325,17 +325,17 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
var vquery = vqres.get() var vquery = vqres.get()
for index in vquery.ids: for index in vquery.ids:
if index < lenu64(getStateField(stateData, validators)): if index < lenu64(getStateField(stateData.data, validators)):
let validator = getStateField(stateData, validators)[index] let validator = getStateField(stateData.data, validators)[index]
vquery.keyset.excl(validator.pubkey) vquery.keyset.excl(validator.pubkey)
let balance = (index: uint64(index), let balance = (index: uint64(index),
balance: getStateField(stateData, balances)[index]) balance: getStateField(stateData.data, balances)[index])
res.add(balance) res.add(balance)
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
if validator.pubkey in vquery.keyset: if validator.pubkey in vquery.keyset:
let balance = (index: uint64(index), let balance = (index: uint64(index),
balance: getStateField(stateData, balances)[index]) balance: getStateField(stateData.data, balances)[index])
res.add(balance) res.add(balance)
return res return res
@ -346,12 +346,12 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
proc getCommittee(slot: Slot, proc getCommittee(slot: Slot,
index: CommitteeIndex): BeaconStatesCommitteesTuple = index: CommitteeIndex): BeaconStatesCommitteesTuple =
let vals = get_beacon_committee( let vals = get_beacon_committee(
stateData, slot, index, cache).mapIt(it.uint64) stateData.data, slot, index, cache).mapIt(it.uint64)
return (index: index.uint64, slot: slot.uint64, validators: vals) return (index: index.uint64, slot: slot.uint64, validators: vals)
proc forSlot(slot: Slot, res: var seq[BeaconStatesCommitteesTuple]) = proc forSlot(slot: Slot, res: var seq[BeaconStatesCommitteesTuple]) =
let committees_per_slot = let committees_per_slot =
get_committee_count_per_slot(stateData, slot.epoch, cache) get_committee_count_per_slot(stateData.data, slot.epoch, cache)
if index.isNone: if index.isNone:
for committee_index in 0'u64..<committees_per_slot: for committee_index in 0'u64..<committees_per_slot:
@ -364,7 +364,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
let qepoch = let qepoch =
if epoch.isNone: if epoch.isNone:
compute_epoch_at_slot(getStateField(stateData, slot)) compute_epoch_at_slot(getStateField(stateData.data, slot))
else: else:
Epoch(epoch.get()) Epoch(epoch.get())

View File

@ -9,10 +9,10 @@ import
chronicles, chronicles,
nimcrypto/utils as ncrutils, nimcrypto/utils as ncrutils,
../beacon_node_common, ../networking/eth2_network, ../beacon_node_common, ../networking/eth2_network,
../consensus_object_pools/[blockchain_dag, exit_pool, statedata_helpers], ../consensus_object_pools/[blockchain_dag, exit_pool],
../gossip_processing/gossip_validation, ../gossip_processing/gossip_validation,
../validators/validator_duties, ../validators/validator_duties,
../spec/[crypto, digest, datatypes, network], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers, network],
../ssz/merkleization, ../ssz/merkleization,
./eth2_json_rest_serialization, ./rest_utils ./eth2_json_rest_serialization, ./rest_utils
@ -127,9 +127,9 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
router.api(MethodGet, "/api/eth/v1/beacon/genesis") do () -> RestApiResponse: router.api(MethodGet, "/api/eth/v1/beacon/genesis") do () -> RestApiResponse:
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
( (
genesis_time: getStateField(node.dag.headState, genesis_time), genesis_time: getStateField(node.dag.headState.data, genesis_time),
genesis_validators_root: genesis_validators_root:
getStateField(node.dag.headState, genesis_validators_root), getStateField(node.dag.headState.data, genesis_validators_root),
genesis_fork_version: node.runtimePreset.GENESIS_FORK_VERSION genesis_fork_version: node.runtimePreset.GENESIS_FORK_VERSION
) )
) )
@ -167,9 +167,9 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
( (
previous_version: getStateField(stateData, fork).previous_version, previous_version: getStateField(stateData.data, fork).previous_version,
current_version: getStateField(stateData, fork).current_version, current_version: getStateField(stateData.data, fork).current_version,
epoch: getStateField(stateData, fork).epoch epoch: getStateField(stateData.data, fork).epoch
) )
) )
return RestApiResponse.jsonError(Http500, InternalServerError) return RestApiResponse.jsonError(Http500, InternalServerError)
@ -192,10 +192,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
( (
previous_justified: previous_justified:
getStateField(stateData, previous_justified_checkpoint), getStateField(stateData.data, previous_justified_checkpoint),
current_justified: current_justified:
getStateField(stateData, current_justified_checkpoint), getStateField(stateData.data, current_justified_checkpoint),
finalized: getStateField(stateData, finalized_checkpoint) finalized: getStateField(stateData.data, finalized_checkpoint)
) )
) )
return RestApiResponse.jsonError(Http500, InternalServerError) return RestApiResponse.jsonError(Http500, InternalServerError)
@ -268,9 +268,9 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
(res1, res2) (res1, res2)
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
let current_epoch = get_current_epoch(node.dag.headState) let current_epoch = get_current_epoch(node.dag.headState.data)
var res: seq[RestValidator] var res: seq[RestValidator]
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
let includeFlag = let includeFlag =
(len(keySet) == 0) and (len(indexSet) == 0) or (len(keySet) == 0) and (len(indexSet) == 0) or
(len(indexSet) > 0 and (ValidatorIndex(index) in indexSet)) or (len(indexSet) > 0 and (ValidatorIndex(index) in indexSet)) or
@ -283,7 +283,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
res.add(RestValidator( res.add(RestValidator(
index: ValidatorIndex(index), index: ValidatorIndex(index),
balance: balance:
Base10.toString(getStateField(stateData, balances)[index]), Base10.toString(getStateField(stateData.data, balances)[index]),
status: toString(vstatus), status: toString(vstatus),
validator: validator validator: validator
)) ))
@ -309,11 +309,11 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, InvalidValidatorIdValueError, return RestApiResponse.jsonError(Http400, InvalidValidatorIdValueError,
$validator_id.error()) $validator_id.error())
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
let current_epoch = get_current_epoch(node.dag.headState) let current_epoch = get_current_epoch(node.dag.headState.data)
let vid = validator_id.get() let vid = validator_id.get()
case vid.kind case vid.kind
of ValidatorQueryKind.Key: of ValidatorQueryKind.Key:
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
if validator.pubkey == vid.key: if validator.pubkey == vid.key:
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk(): if sres.isOk():
@ -321,7 +321,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
( (
index: ValidatorIndex(index), index: ValidatorIndex(index),
balance: balance:
Base10.toString(getStateField(stateData, balances)[index]), Base10.toString(getStateField(stateData.data, balances)[index]),
status: toString(sres.get()), status: toString(sres.get()),
validator: validator validator: validator
) )
@ -344,15 +344,15 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
UnsupportedValidatorIndexValueError) UnsupportedValidatorIndexValueError)
vres.get() vres.get()
if uint64(vindex) >= uint64(len(getStateField(stateData, validators))): if uint64(vindex) >= uint64(len(getStateField(stateData.data, validators))):
return RestApiResponse.jsonError(Http404, ValidatorNotFoundError) return RestApiResponse.jsonError(Http404, ValidatorNotFoundError)
let validator = getStateField(stateData, validators)[vindex] let validator = getStateField(stateData.data, validators)[vindex]
let sres = validator.getStatus(current_epoch) let sres = validator.getStatus(current_epoch)
if sres.isOk(): if sres.isOk():
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
( (
index: vindex, index: vindex,
balance: Base10.toString(getStateField(stateData, balances)[vindex]), balance: Base10.toString(getStateField(stateData.data, balances)[vindex]),
status: toString(sres.get()), status: toString(sres.get()),
validator: validator validator: validator
) )
@ -416,9 +416,9 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
res2.incl(vitem) res2.incl(vitem)
(res1, res2) (res1, res2)
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
let current_epoch = get_current_epoch(node.dag.headState) let current_epoch = get_current_epoch(node.dag.headState.data)
var res: seq[RestValidatorBalance] var res: seq[RestValidatorBalance]
for index, validator in getStateField(stateData, validators).pairs(): for index, validator in getStateField(stateData.data, validators).pairs():
let includeFlag = let includeFlag =
(len(keySet) == 0) and (len(indexSet) == 0) or (len(keySet) == 0) and (len(indexSet) == 0) or
(len(indexSet) > 0 and (ValidatorIndex(index) in indexSet)) or (len(indexSet) > 0 and (ValidatorIndex(index) in indexSet)) or
@ -430,7 +430,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
res.add(RestValidatorBalance( res.add(RestValidatorBalance(
index: ValidatorIndex(index), index: ValidatorIndex(index),
balance: balance:
Base10.toString(getStateField(stateData, balances)[index]), Base10.toString(getStateField(stateData.data, balances)[index]),
)) ))
return RestApiResponse.jsonResponse(res) return RestApiResponse.jsonResponse(res)
@ -485,7 +485,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
proc getCommittee(slot: Slot, proc getCommittee(slot: Slot,
index: CommitteeIndex): RestBeaconStatesCommittees = index: CommitteeIndex): RestBeaconStatesCommittees =
let validators = get_beacon_committee(stateData, slot, index, let validators = get_beacon_committee(stateData.data, slot, index,
cache).mapIt(it) cache).mapIt(it)
RestBeaconStatesCommittees(index: index, slot: slot, RestBeaconStatesCommittees(index: index, slot: slot,
validators: validators) validators: validators)
@ -493,7 +493,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
proc forSlot(slot: Slot, cindex: Option[CommitteeIndex], proc forSlot(slot: Slot, cindex: Option[CommitteeIndex],
res: var seq[RestBeaconStatesCommittees]) = res: var seq[RestBeaconStatesCommittees]) =
let committees_per_slot = let committees_per_slot =
get_committee_count_per_slot(stateData, Epoch(slot), cache) get_committee_count_per_slot(stateData.data, Epoch(slot), cache)
if cindex.isNone: if cindex.isNone:
for committee_index in 0'u64 ..< committees_per_slot: for committee_index in 0'u64 ..< committees_per_slot:
@ -506,7 +506,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
var res: seq[RestBeaconStatesCommittees] var res: seq[RestBeaconStatesCommittees]
let qepoch = let qepoch =
if vepoch.isNone: if vepoch.isNone:
compute_epoch_at_slot(getStateField(stateData, slot)) compute_epoch_at_slot(getStateField(stateData.data, slot))
else: else:
vepoch.get() vepoch.get()

View File

@ -14,7 +14,7 @@ import
nimcrypto/utils as ncrutils, nimcrypto/utils as ncrutils,
../beacon_node_common, ../beacon_node_common,
../eth1/eth1_monitor, ../eth1/eth1_monitor,
../spec/[datatypes, digest, presets] ../spec/[datatypes, digest, forkedbeaconstate_helpers, presets]
logScope: topics = "configapi" logScope: topics = "configapi"
@ -33,7 +33,7 @@ func getDepositAddress(node: BeaconNode): string =
proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {. proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_config_fork_schedule") do () -> seq[Fork]: rpcServer.rpc("get_v1_config_fork_schedule") do () -> seq[Fork]:
return @[getStateField(node.dag.headState, fork)] return @[getStateField(node.dag.headState.data, fork)]
rpcServer.rpc("get_v1_config_spec") do () -> JsonNode: rpcServer.rpc("get_v1_config_spec") do () -> JsonNode:
return %*{ return %*{

View File

@ -11,7 +11,7 @@ import
chronicles, chronicles,
nimcrypto/utils as ncrutils, nimcrypto/utils as ncrutils,
../beacon_node_common, ../eth1/eth1_monitor, ../beacon_node_common, ../eth1/eth1_monitor,
../spec/[datatypes, digest, presets], ../spec/[datatypes, digest, forkedbeaconstate_helpers, presets],
./eth2_json_rest_serialization, ./rest_utils ./eth2_json_rest_serialization, ./rest_utils
logScope: topics = "rest_config" logScope: topics = "rest_config"
@ -28,7 +28,7 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
# TODO: Implemenation needs a fix, when forks infrastructure will be # TODO: Implemenation needs a fix, when forks infrastructure will be
# established. # established.
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
[getStateField(node.dag.headState, fork)] [getStateField(node.dag.headState.data, fork)]
) )
router.api(MethodGet, router.api(MethodGet,

View File

@ -26,7 +26,7 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_debug_beacon_states_stateId") do ( rpcServer.rpc("get_v1_debug_beacon_states_stateId") do (
stateId: string) -> BeaconState: stateId: string) -> BeaconState:
withStateForStateId(stateId): withStateForStateId(stateId):
return stateData.data.data return stateData.data.hbsPhase0.data
rpcServer.rpc("get_v1_debug_beacon_heads") do () -> seq[tuple[root: Eth2Digest, slot: Slot]]: rpcServer.rpc("get_v1_debug_beacon_heads") do () -> seq[tuple[root: Eth2Digest, slot: Slot]]:
return node.dag.heads.mapIt((it.root, it.slot)) return node.dag.heads.mapIt((it.root, it.slot))

View File

@ -23,7 +23,7 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
$bres.error()) $bres.error())
bres.get() bres.get()
node.withStateForBlockSlot(bslot): node.withStateForBlockSlot(bslot):
return RestApiResponse.jsonResponse(stateData.data.data) return RestApiResponse.jsonResponse(stateData.data.hbsPhase0.data)
return RestApiResponse.jsonError(Http500, InternalServerError) return RestApiResponse.jsonError(Http500, InternalServerError)
router.api(MethodGet, router.api(MethodGet,

View File

@ -18,7 +18,7 @@ import
".."/[ ".."/[
beacon_node_common, nimbus_binary_common, networking/eth2_network, beacon_node_common, nimbus_binary_common, networking/eth2_network,
eth1/eth1_monitor, validators/validator_duties], eth1/eth1_monitor, validators/validator_duties],
../spec/[digest, datatypes, presets] ../spec/[digest, datatypes, forkedbeaconstate_helpers, presets]
logScope: topics = "nimbusapi" logScope: topics = "nimbusapi"
@ -43,9 +43,9 @@ proc installNimbusApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("getChainHead") do () -> JsonNode: rpcServer.rpc("getChainHead") do () -> JsonNode:
let let
head = node.dag.head head = node.dag.head
finalized = getStateField(node.dag.headState, finalized_checkpoint) finalized = getStateField(node.dag.headState.data, finalized_checkpoint)
justified = justified =
getStateField(node.dag.headState, current_justified_checkpoint) getStateField(node.dag.headState.data, current_justified_checkpoint)
return %* { return %* {
"head_slot": head.slot, "head_slot": head.slot,
"head_block_root": head.root.data.toHex(), "head_block_root": head.root.data.toHex(),
@ -105,7 +105,7 @@ proc installNimbusApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
let proposalState = assignClone(node.dag.headState) let proposalState = assignClone(node.dag.headState)
node.dag.withState(proposalState[], head.atSlot(wallSlot)): node.dag.withState(proposalState[], head.atSlot(wallSlot)):
return node.getBlockProposalEth1Data(stateData) return node.getBlockProposalEth1Data(stateData.data)
rpcServer.rpc("debug_getChronosFutures") do () -> seq[FutureInfo]: rpcServer.rpc("debug_getChronosFutures") do () -> seq[FutureInfo]:
when defined(chronosFutureTracking): when defined(chronosFutureTracking):

View File

@ -14,6 +14,7 @@ import
./eth2_json_rest_serialization, ./rest_utils, ./eth2_json_rest_serialization, ./rest_utils,
../eth1/eth1_monitor, ../eth1/eth1_monitor,
../validators/validator_duties, ../validators/validator_duties,
../spec/forkedbeaconstate_helpers,
../beacon_node_common, ../nimbus_binary_common ../beacon_node_common, ../nimbus_binary_common
logScope: topics = "rest_nimbusapi" logScope: topics = "rest_nimbusapi"
@ -112,9 +113,9 @@ proc installNimbusApiHandlers*(router: var RestRouter, node: BeaconNode) =
router.api(MethodGet, "/api/nimbus/v1/chain/head") do() -> RestApiResponse: router.api(MethodGet, "/api/nimbus/v1/chain/head") do() -> RestApiResponse:
let let
head = node.dag.head head = node.dag.head
finalized = getStateField(node.dag.headState, finalized_checkpoint) finalized = getStateField(node.dag.headState.data, finalized_checkpoint)
justified = justified =
getStateField(node.dag.headState, current_justified_checkpoint) getStateField(node.dag.headState.data, current_justified_checkpoint)
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
( (
head_slot: head.slot, head_slot: head.slot,
@ -205,7 +206,7 @@ proc installNimbusApiHandlers*(router: var RestRouter, node: BeaconNode) =
let proposalState = assignClone(node.dag.headState) let proposalState = assignClone(node.dag.headState)
node.dag.withState(proposalState[], head.atSlot(wallSlot)): node.dag.withState(proposalState[], head.atSlot(wallSlot)):
return RestApiResponse.jsonResponse( return RestApiResponse.jsonResponse(
node.getBlockProposalEth1Data(stateData)) node.getBlockProposalEth1Data(stateData.data))
router.api(MethodGet, "/api/nimbus/v1/debug/chronos/futures") do ( router.api(MethodGet, "/api/nimbus/v1/debug/chronos/futures") do (
) -> RestApiResponse: ) -> RestApiResponse:

View File

@ -4,7 +4,7 @@ import presto,
faststreams/[outputs], faststreams/[outputs],
serialization, json_serialization, serialization, json_serialization,
nimcrypto/utils as ncrutils, nimcrypto/utils as ncrutils,
../spec/[crypto, digest, datatypes], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers],
../beacon_node_common, ../beacon_node_common,
../consensus_object_pools/[block_pools_types, blockchain_dag] ../consensus_object_pools/[block_pools_types, blockchain_dag]
export blockchain_dag, presto export blockchain_dag, presto
@ -508,8 +508,8 @@ proc getBlockSlot*(node: BeaconNode,
of StateIdentType.Finalized: of StateIdentType.Finalized:
ok(node.dag.finalizedHead) ok(node.dag.finalizedHead)
of StateIdentType.Justified: of StateIdentType.Justified:
ok(node.dag.head.atEpochStart( ok(node.dag.head.atEpochStart(getStateField(
getStateField(node.dag.headState, current_justified_checkpoint).epoch)) node.dag.headState.data, current_justified_checkpoint).epoch))
proc getBlockDataFromBlockIdent*(node: BeaconNode, proc getBlockDataFromBlockIdent*(node: BeaconNode,
id: BlockIdent): Result[BlockData, cstring] = id: BlockIdent): Result[BlockData, cstring] =
@ -537,7 +537,7 @@ proc getBlockDataFromBlockIdent*(node: BeaconNode,
template withStateForBlockSlot*(node: BeaconNode, template withStateForBlockSlot*(node: BeaconNode,
blockSlot: BlockSlot, body: untyped): untyped = blockSlot: BlockSlot, body: untyped): untyped =
template isState(state: StateData): bool = template isState(state: StateData): bool =
state.blck.atSlot(getStateField(state, slot)) == blockSlot state.blck.atSlot(getStateField(state.data, slot)) == blockSlot
if isState(node.dag.headState): if isState(node.dag.headState):
withStateVars(node.dag.headState): withStateVars(node.dag.headState):

View File

@ -12,7 +12,7 @@ import
stew/byteutils, stew/byteutils,
../beacon_node_common, ../validators/validator_duties, ../beacon_node_common, ../validators/validator_duties,
../consensus_object_pools/[block_pools_types, blockchain_dag], ../consensus_object_pools/[block_pools_types, blockchain_dag],
../spec/[datatypes, digest, helpers] ../spec/[datatypes, digest, forkedbeaconstate_helpers, helpers]
export blockchain_dag export blockchain_dag
@ -21,7 +21,7 @@ template withStateForStateId*(stateId: string, body: untyped): untyped =
bs = node.stateIdToBlockSlot(stateId) bs = node.stateIdToBlockSlot(stateId)
template isState(state: StateData): bool = template isState(state: StateData): bool =
state.blck.atSlot(getStateField(state, slot)) == bs state.blck.atSlot(getStateField(state.data, slot)) == bs
if isState(node.dag.headState): if isState(node.dag.headState):
withStateVars(node.dag.headState): withStateVars(node.dag.headState):
@ -75,7 +75,7 @@ proc stateIdToBlockSlot*(node: BeaconNode, stateId: string): BlockSlot {.raises:
node.dag.finalizedHead node.dag.finalizedHead
of "justified": of "justified":
node.dag.head.atEpochStart( node.dag.head.atEpochStart(
getStateField(node.dag.headState, current_justified_checkpoint).epoch) getStateField(node.dag.headState.data, current_justified_checkpoint).epoch)
else: else:
if stateId.startsWith("0x"): if stateId.startsWith("0x"):
let blckRoot = parseRoot(stateId) let blckRoot = parseRoot(stateId)

View File

@ -17,7 +17,7 @@ import
chronicles, chronicles,
# Local modules # Local modules
../spec/[datatypes, digest, crypto, helpers, network, signatures], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers, helpers, network, signatures],
../spec/eth2_apis/callsigs_types, ../spec/eth2_apis/callsigs_types,
../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool], ../ssz/merkleization, ../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool], ../ssz/merkleization,
../beacon_node_common, ../beacon_node_types, ../beacon_node_common, ../beacon_node_types,
@ -141,8 +141,8 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
"Slot requested not in current or next wall-slot epoch") "Slot requested not in current or next wall-slot epoch")
if not verify_slot_signature( if not verify_slot_signature(
getStateField(node.dag.headState, fork), getStateField(node.dag.headState.data, fork),
getStateField(node.dag.headState, genesis_validators_root), getStateField(node.dag.headState.data, genesis_validators_root),
slot, validator_pubkey, slot_signature): slot, validator_pubkey, slot_signature):
raise newException(CatchableError, raise newException(CatchableError,
"Invalid slot signature") "Invalid slot signature")

View File

@ -12,7 +12,7 @@ import
../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool], ../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool],
../gossip_processing/gossip_validation, ../gossip_processing/gossip_validation,
../validators/validator_duties, ../validators/validator_duties,
../spec/[crypto, digest, datatypes, network], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers, network],
../ssz/merkleization, ../ssz/merkleization,
./eth2_json_rest_serialization, ./rest_utils ./eth2_json_rest_serialization, ./rest_utils
@ -342,10 +342,10 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
block: block:
let idx = request.validator_index let idx = request.validator_index
if uint64(idx) >= if uint64(idx) >=
lenu64(getStateField(node.dag.headState, validators)): lenu64(getStateField(node.dag.headState.data, validators)):
return RestApiResponse.jsonError(Http400, return RestApiResponse.jsonError(Http400,
InvalidValidatorIndexValueError) InvalidValidatorIndexValueError)
getStateField(node.dag.headState, validators)[idx].pubkey getStateField(node.dag.headState.data, validators)[idx].pubkey
let wallSlot = node.beaconClock.now.slotOrZero let wallSlot = node.beaconClock.now.slotOrZero
if wallSlot > request.slot + 1: if wallSlot > request.slot + 1:

View File

@ -513,11 +513,14 @@ proc is_valid_indexed_attestation*(
ok() ok()
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attesting_indices # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attesting_indices
iterator get_attesting_indices*(state: SomeBeaconState, func get_attesting_indices*(state: SomeBeaconState,
data: AttestationData, data: AttestationData,
bits: CommitteeValidatorsBits, bits: CommitteeValidatorsBits,
cache: var StateCache): ValidatorIndex = cache: var StateCache): seq[ValidatorIndex] =
## Return the set of attesting indices corresponding to ``data`` and ``bits``. ## Return the set of attesting indices corresponding to ``data`` and ``bits``.
var res: seq[ValidatorIndex]
# Can't be an iterator due to https://github.com/nim-lang/Nim/issues/18188
if bits.lenu64 != get_beacon_committee_len( if bits.lenu64 != get_beacon_committee_len(
state, data.slot, data.index.CommitteeIndex, cache): state, data.slot, data.index.CommitteeIndex, cache):
trace "get_attesting_indices: inconsistent aggregation and committee length" trace "get_attesting_indices: inconsistent aggregation and committee length"
@ -526,9 +529,11 @@ iterator get_attesting_indices*(state: SomeBeaconState,
for index in get_beacon_committee( for index in get_beacon_committee(
state, data.slot, data.index.CommitteeIndex, cache): state, data.slot, data.index.CommitteeIndex, cache):
if bits[i]: if bits[i]:
yield index res.add index
inc i inc i
res
proc is_valid_indexed_attestation*( proc is_valid_indexed_attestation*(
state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags, state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] = cache: var StateCache): Result[void, cstring] =
@ -702,6 +707,10 @@ proc process_attestation*(
# In the spec, attestation validation is mixed with state mutation, so here # In the spec, attestation validation is mixed with state mutation, so here
# we've split it into two functions so that the validation logic can be # we've split it into two functions so that the validation logic can be
# reused when looking for suitable blocks to include in attestations. # reused when looking for suitable blocks to include in attestations.
#
# TODO this should be two separate functions, but
# https://github.com/nim-lang/Nim/issues/18202 means that this being called
# by process_operations() in state_transition_block fails that way.
let proposer_index = get_beacon_proposer_index(state, cache) let proposer_index = get_beacon_proposer_index(state, cache)
if proposer_index.isNone: if proposer_index.isNone:
@ -709,10 +718,6 @@ proc process_attestation*(
? check_attestation(state, attestation, flags, cache) ? check_attestation(state, attestation, flags, cache)
# TODO this should be split between two functions, but causes type errors
# in state_transition_block.process_operations()
# TODO investigate and, if real, file Nim bug
# For phase0 # For phase0
template addPendingAttestation(attestations: typed) = template addPendingAttestation(attestations: typed) =
# The genericSeqAssign generated by the compiler to copy the attestation # The genericSeqAssign generated by the compiler to copy the attestation

View File

@ -255,8 +255,7 @@ type
# phase 0 version of symbols; anywhere which specially handles it will # phase 0 version of symbols; anywhere which specially handles it will
# have to do so itself. # have to do so itself.
SomeBeaconState* = BeaconState | phase0.BeaconState SomeBeaconState* = BeaconState | phase0.BeaconState
SomeHashedBeaconState* = HashedBeaconState | phase0.HashedBeaconState # probably not useful long-term, SomeHashedBeaconState* = HashedBeaconState | phase0.HashedBeaconState
## since process_slots will need to be StateData
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblock # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object BeaconBlock* = object

View File

@ -922,9 +922,6 @@ proc readValue*(r: var JsonReader, T: type GraffitiBytes): T
except ValueError as err: except ValueError as err:
r.raiseUnexpectedValue err.msg r.raiseUnexpectedValue err.msg
template getStateField*(stateData, fieldName: untyped): untyped =
stateData.data.data.fieldName
proc load*( proc load*(
validators: openArray[ImmutableValidatorData2], validators: openArray[ImmutableValidatorData2],
index: ValidatorIndex | uint64): Option[CookedPubKey] = index: ValidatorIndex | uint64): Option[CookedPubKey] =

View File

@ -97,25 +97,6 @@ type
data*: BeaconState data*: BeaconState
root*: Eth2Digest # hash_tree_root(data) root*: Eth2Digest # hash_tree_root(data)
BlockRef* = ref object
## Node in object graph guaranteed to lead back to tail block, and to have
## a corresponding entry in database.
## Block graph should form a tree - in particular, there are no cycles.
root*: Eth2Digest ##\
## Root that can be used to retrieve block data from database
parent*: BlockRef ##\
## Not nil, except for the tail
slot*: Slot # could calculate this by walking to root, but..
StateData* = object
data*: HashedBeaconState
blck*: BlockRef ##\
## The block associated with the state found in data
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblock # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose ## For each slot, a proposer is chosen from the validator pool to propose

View File

@ -0,0 +1,171 @@
# beacon_chain
# Copyright (c) 2021 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.push raises: [Defect].}
import
std/macros,
chronicles,
stew/[assign2, results],
../extras,
../spec/[
beaconstate, digest, helpers, presets, state_transition_block, validator],
./datatypes/[phase0, altair]
type
BeaconStateFork* = enum
forkPhase0,
forkAltair
ForkedHashedBeaconState* = object
case beaconStateFork*: BeaconStateFork
of forkPhase0: hbsPhase0*: phase0.HashedBeaconState
of forkAltair: hbsAltair*: altair.HashedBeaconState
# State-related functionality based on ForkedHashedBeaconState instead of BeaconState
# Dispatch functions
func assign*(tgt: var ForkedHashedBeaconState, src: ForkedHashedBeaconState) =
if tgt.beaconStateFork == src.beaconStateFork:
if tgt.beaconStateFork == forkPhase0:
assign(tgt.hbsPhase0, src.hbsPhase0):
elif tgt.beaconStateFork == forkAltair:
assign(tgt.hbsAltair, src.hbsAltair):
else:
doAssert false
else:
# Ensure case object and discriminator get updated simultaneously, even
# with nimOldCaseObjects. This is infrequent.
tgt = src
macro getStateField*(s, y: untyped): untyped =
result = quote do:
(if `s`.beaconStateFork == forkPhase0:
unsafeAddr (`s`.hbsPhase0.data.`y`) else:
unsafeAddr (`s`.hbsAltair.data.`y`))[]
template getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork:
of forkPhase0: x.hbsPhase0.root
of forkAltair: x.hbsAltair.root
template hash_tree_root*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork:
of forkPhase0: hash_tree_root(x.hbsPhase0.data)
of forkAltair: hash_tree_root(x.hbsAltair.data)
func get_beacon_committee*(
state: ForkedHashedBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): seq[ValidatorIndex] =
# This one is used by tests/, ncli/, and a couple of places in RPC
# TODO use the iterator version alone, to remove the risk of using
# diverging get_beacon_committee() in tests and beacon_chain/ by a
# wrapper approach (e.g., toSeq). This is a perf tradeoff for test
# correctness/consistency.
case state.beaconStateFork:
of forkPhase0: get_beacon_committee(state.hbsPhase0.data, slot, index, cache)
of forkAltair: get_beacon_committee(state.hbsAltair.data, slot, index, cache)
func get_committee_count_per_slot*(state: ForkedHashedBeaconState,
epoch: Epoch,
cache: var StateCache): uint64 =
## Return the number of committees at ``epoch``.
case state.beaconStateFork:
of forkPhase0: get_committee_count_per_slot(state.hbsPhase0.data, epoch, cache)
of forkAltair: get_committee_count_per_slot(state.hbsAltair.data, epoch, cache)
func get_beacon_proposer_index*(state: ForkedHashedBeaconState,
cache: var StateCache, slot: Slot):
Option[ValidatorIndex] =
case state.beaconStateFork:
of forkPhase0: get_beacon_proposer_index(state.hbsPhase0.data, cache, slot)
of forkAltair: get_beacon_proposer_index(state.hbsAltair.data, cache, slot)
func get_shuffled_active_validator_indices*(
cache: var StateCache, state: ForkedHashedBeaconState, epoch: Epoch):
seq[ValidatorIndex] =
case state.beaconStateFork:
of forkPhase0:
cache.get_shuffled_active_validator_indices(state.hbsPhase0.data, epoch)
of forkAltair:
cache.get_shuffled_active_validator_indices(state.hbsAltair.data, epoch)
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: ForkedHashedBeaconState,
slot: Slot): Eth2Digest =
## Return the block root at a recent ``slot``.
case state.beaconStateFork:
of forkPhase0: get_block_root_at_slot(state.hbsPhase0.data, slot)
of forkAltair: get_block_root_at_slot(state.hbsAltair.data, slot)
proc get_attesting_indices*(state: ForkedHashedBeaconState;
data: AttestationData;
bits: CommitteeValidatorsBits;
cache: var StateCache): seq[ValidatorIndex] =
# TODO when https://github.com/nim-lang/Nim/issues/18188 fixed, use an
# iterator
var idxBuf: seq[ValidatorIndex]
doAssert state.beaconStateFork == forkPhase0
for vidx in state.hbsPhase0.data.get_attesting_indices(data, bits, cache):
idxBuf.add vidx
if true: return idxBuf
if state.beaconStateFork == forkPhase0:
for vidx in state.hbsPhase0.data.get_attesting_indices(data, bits, cache):
idxBuf.add vidx
elif state.beaconStateFork == forkAltair:
for vidx in state.hbsAltair.data.get_attesting_indices(data, bits, cache):
idxBuf.add vidx
else:
doAssert false
idxBuf
proc check_attester_slashing*(
state: var ForkedHashedBeaconState; attester_slashing: SomeAttesterSlashing;
flags: UpdateFlags): Result[seq[ValidatorIndex], cstring] =
case state.beaconStateFork:
of forkPhase0:
check_attester_slashing(state.hbsPhase0.data, attester_slashing, flags)
of forkAltair:
check_attester_slashing(state.hbsAltair.data, attester_slashing, flags)
proc check_proposer_slashing*(
state: var ForkedHashedBeaconState; proposer_slashing: SomeProposerSlashing;
flags: UpdateFlags): Result[void, cstring] =
case state.beaconStateFork:
of forkPhase0:
check_proposer_slashing(state.hbsPhase0.data, proposer_slashing, flags)
of forkAltair:
check_proposer_slashing(state.hbsAltair.data, proposer_slashing, flags)
proc check_voluntary_exit*(
state: ForkedHashedBeaconState; signed_voluntary_exit: SomeSignedVoluntaryExit;
flags: UpdateFlags): Result[void, cstring] =
case state.beaconStateFork:
of forkPhase0:
check_voluntary_exit(state.hbsPhase0.data, signed_voluntary_exit, flags)
of forkAltair:
check_voluntary_exit(state.hbsAltair.data, signed_voluntary_exit, flags)
# Derived utilities
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(stateData: ForkedHashedBeaconState): Epoch =
## Return the current epoch.
getStateField(stateData, slot).epoch
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_previous_epoch
func get_previous_epoch*(stateData: ForkedHashedBeaconState): Epoch =
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
let current_epoch = get_current_epoch(stateData)
if current_epoch == GENESIS_EPOCH:
GENESIS_EPOCH
else:
current_epoch - 1

View File

@ -13,7 +13,9 @@ import
stew/[byteutils, results], stew/[byteutils, results],
# Internal # Internal
../ssz/merkleization, ../ssz/merkleization,
"."/[crypto, datatypes, helpers, presets, beaconstate, digest] "."/[
crypto, datatypes, helpers, presets, beaconstate, digest,
forkedbeaconstate_helpers]
# Otherwise, error. # Otherwise, error.
import chronicles import chronicles
@ -99,7 +101,7 @@ proc addIndexedAttestation(
sigs: var seq[SignatureSet], sigs: var seq[SignatureSet],
attestation: IndexedAttestation, attestation: IndexedAttestation,
validatorKeys: auto, validatorKeys: auto,
state: StateData, state: ForkedHashedBeaconState,
): Result[void, cstring] = ): Result[void, cstring] =
## Add an indexed attestation for batched BLS verification ## Add an indexed attestation for batched BLS verification
## purposes ## purposes
@ -124,12 +126,13 @@ proc addAttestation(
sigs: var seq[SignatureSet], sigs: var seq[SignatureSet],
attestation: Attestation, attestation: Attestation,
validatorKeys: auto, validatorKeys: auto,
state: StateData, state: ForkedHashedBeaconState,
cache: var StateCache cache: var StateCache
): Result[void, cstring] = ): Result[void, cstring] =
var inited = false var inited = false
var attestersAgg{.noInit.}: AggregatePublicKey var attestersAgg{.noInit.}: AggregatePublicKey
for valIndex in state.data.data.get_attesting_indices( for valIndex in state.get_attesting_indices(
attestation.data, attestation.data,
attestation.aggregation_bits, attestation.aggregation_bits,
cache cache
@ -251,7 +254,7 @@ proc collectSignatureSets*(
sigs: var seq[SignatureSet], sigs: var seq[SignatureSet],
signed_block: SignedBeaconBlock, signed_block: SignedBeaconBlock,
validatorKeys: auto, validatorKeys: auto,
state: StateData, state: ForkedHashedBeaconState,
cache: var StateCache): Result[void, cstring] = cache: var StateCache): Result[void, cstring] =
## Collect all signatures in a single signed block. ## Collect all signatures in a single signed block.
## This includes ## This includes

View File

@ -46,7 +46,7 @@ import
stew/results, stew/results,
../extras, ../ssz/merkleization, metrics, ../extras, ../ssz/merkleization, metrics,
./datatypes/[phase0, altair], ./crypto, ./digest, ./helpers, ./signatures, ./validator, ./beaconstate, ./datatypes/[phase0, altair], ./crypto, ./digest, ./helpers, ./signatures, ./validator, ./beaconstate,
./state_transition_block, ./state_transition_epoch, ./state_transition_block, ./state_transition_epoch, forkedbeaconstate_helpers,
../../nbench/bench_lab ../../nbench/bench_lab
# TODO why need anything except the first two? # TODO why need anything except the first two?
@ -163,174 +163,73 @@ proc advance_slot(
state.slot += 1 state.slot += 1
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc process_slots*(state: var SomeHashedBeaconState, slot: Slot,
cache: var StateCache, rewards: var RewardInfo,
flags: UpdateFlags = {}): bool {.nbench.} =
## Process one or more slot transitions without blocks - if the slot transtion
## passes an epoch boundary, epoch processing will run and `rewards` will be
## updated, else it will be cleared
if not (state.data.slot < slot):
if slotProcessed notin flags or state.data.slot != slot:
notice(
"Unusual request for a slot in the past",
state_root = shortLog(state.root),
current_slot = state.data.slot,
target_slot = slot
)
return false
# Catch up to the target slot
while state.data.slot < slot:
advance_slot(state.data, state.root, flags, cache, rewards)
# The root must be updated on every slot update, or the next `process_slot`
# will be incorrect
state.root = hash_tree_root(state.data)
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/fork.md#upgrading-the-state
# says to put upgrading here too, TODO. It may not work in state reply
# otherwise, since updateStateData() uses this function.
true
func noRollback*(state: var phase0.HashedBeaconState) = func noRollback*(state: var phase0.HashedBeaconState) =
trace "Skipping rollback of broken state" trace "Skipping rollback of broken state"
type
BeaconStateFork* = enum
forkPhase0,
forkAltair
ForkedHashedBeaconState* = object
case beaconStateFork*: BeaconStateFork
of forkPhase0: hbsPhase0*: phase0.HashedBeaconState
of forkAltair: hbsAltair*: altair.HashedBeaconState
# Dispatch functions
template getStateField*(x: ForkedHashedBeaconState, y: untyped): untyped =
case x.beaconStateFork:
of forkPhase0: x.hbsPhase0.data.y
of forkAltair: x.hbsAltair.data.y
template getStateField*(x: var ForkedHashedBeaconState, y: untyped): untyped =
case x.beaconStateFork:
of forkPhase0: x.hbsPhase0.data.y
of forkAltair: x.hbsAltair.data.y
template getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork:
of forkPhase0: x.hbsPhase0.root
of forkAltair: x.hbsAltair.root
template hash_tree_root*(x: ForkedHashedBeaconState): Eth2Digest =
case x.beaconStateFork:
of forkPhase0: hash_tree_root(x.hbsPhase0.data)
of forkAltair: hash_tree_root(x.hbsAltair.data)
template callWithBS*(op: untyped, y: ForkedHashedBeaconState): untyped =
let bs {.inject.} =
case y.beaconStateFork:
of forkPhase0: y.hbsPhase0.data
of forkAltair: y.hbsAltair.data
op
proc maybeUpgradeStateToAltair( proc maybeUpgradeStateToAltair(
state: var ForkedHashedBeaconState, altairForkSlot: Slot) = state: var ForkedHashedBeaconState, altairForkSlot: Slot) =
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/fork.md#upgrading-the-state # https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/fork.md#upgrading-the-state
# Both state_transition_slots() and state_transition_block() call this, so # Both process_slots() and state_transition_block() call this, so only run it
# only run it once by checking for existing fork. # once by checking for existing fork.
if getStateField(state, slot) == altairForkSlot and if getStateField(state, slot) == altairForkSlot and
state.beaconStateFork == forkPhase0: state.beaconStateFork == forkPhase0:
var newState = upgrade_to_altair(state.hbsPhase0.data) var newState = upgrade_to_altair(state.hbsPhase0.data)
state = ForkedHashedBeaconState( state = (ref ForkedHashedBeaconState)(
beaconStateFork: forkAltair, beaconStateFork: forkAltair,
hbsAltair: altair.HashedBeaconState( hbsAltair: altair.HashedBeaconState(
root: hash_tree_root(newState[]), data: newState[])) root: hash_tree_root(newState[]), data: newState[]))[]
proc state_transition_slots( proc process_slots*(
preset: RuntimePreset, state: var ForkedHashedBeaconState, slot: Slot,
state: var ForkedHashedBeaconState,
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags, cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
altairForkSlot: Slot): bool {.nbench.} = altairForkSlot: Slot): bool {.nbench.} =
let slot = signedBlock.message.slot 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
# Update the state so its slot matches that of the block # Update the state so its slot matches that of the block
while getStateField(state, slot) < slot: while getStateField(state, slot) < slot:
case state.beaconStateFork: case state.beaconStateFork:
of forkPhase0: of forkPhase0:
advance_slot( advance_slot(
state.hbsPhase0.data, state.hbsPhase0.root, flags, cache, rewards) state.hbsPhase0.data, getStateRoot(state), flags, cache, rewards)
if state.hbsPhase0.data.slot < slot: if skipLastStateRootCalculation notin flags or
# Don't update state root for the slot of the block getStateField(state, slot) < slot:
state.hbsPhase0.root = hash_tree_root(state.hbsPhase0.data) # Don't update state root for the slot of the block if going to process
# block after
state.hbsPhase0.root = hash_tree_root(state)
of forkAltair: of forkAltair:
advance_slot( advance_slot(
state.hbsAltair.data, state.hbsAltair.root, flags, cache, rewards) state.hbsAltair.data, state.hbsAltair.root, flags, cache, rewards)
if getStateField(state, slot) < slot: if skipLastStateRootCalculation notin flags or
# Don't update state root for the slot of the block getStateField(state, slot) < slot:
state.hbsAltair.root = hash_tree_root(state.hbsAltair.data) # Don't update state root for the slot of the block if going to process
# block after
state.hbsAltair.root = hash_tree_root(state)
maybeUpgradeStateToAltair(state, altairForkSlot) maybeUpgradeStateToAltair(state, altairForkSlot)
true true
proc state_transition_slots( proc state_transition_block_aux(
preset: RuntimePreset, preset: RuntimePreset,
state: var SomeHashedBeaconState, state: var SomeHashedBeaconState,
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock, phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags): cache: var StateCache, flags: UpdateFlags): bool {.nbench.} =
bool {.nbench.} =
# TODO remove when the HashedBeaconState state_transition is removed; it's
# to avoid requiring a wrapped/memory-copied version
let slot = signedBlock.message.slot
if not (state.data.slot < slot):
if slotProcessed notin flags or state.data.slot != slot:
notice "State must precede block",
state_root = shortLog(state.root),
current_slot = state.data.slot,
blck = shortLog(signedBlock)
return false
# Update the state so its slot matches that of the block
while state.data.slot < slot:
advance_slot(state.data, state.root, flags, cache, rewards)
if state.data.slot < slot:
# Don't update state root for the slot of the block
state.root = hash_tree_root(state.data)
true
proc state_transition_block*(
preset: RuntimePreset,
state: var SomeHashedBeaconState,
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
cache: var StateCache, flags: UpdateFlags, rollback: RollbackHashedProc):
bool {.nbench.} =
## `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
## object should be rolled back to a consistent state. If the transition fails
## before the state has been updated, `rollback` will not be called.
# Block updates - these happen when there's a new block being suggested # 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 # 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 # according to the contents of this block - but first they will validate
# that the block is sane. # that the block is sane.
doAssert not rollback.isNil, "use noRollback if it's ok to mess up state"
if not (skipBLSValidation in flags or if not (skipBLSValidation in flags or
verify_block_signature(state.data, signedBlock)): verify_block_signature(state.data, signedBlock)):
when not (state is altair.HashedBeaconState):
# TODO re-enable in Altair
rollback(state)
return false return false
trace "state_transition: processing block, signature passed", trace "state_transition: processing block, signature passed",
@ -346,16 +245,10 @@ proc state_transition_block*(
eth1_deposit_index = state.data.eth1_deposit_index, eth1_deposit_index = state.data.eth1_deposit_index,
deposit_root = shortLog(state.data.eth1_data.deposit_root), deposit_root = shortLog(state.data.eth1_data.deposit_root),
error = res.error error = res.error
when not (state is altair.HashedBeaconState):
# TODO re-enable in Altair
rollback(state)
return false return false
if not (skipStateRootValidation in flags or if not (skipStateRootValidation in flags or
verifyStateRoot(state.data, signedBlock.message)): verifyStateRoot(state.data, signedBlock.message)):
when not (state is altair.HashedBeaconState):
# TODO re-enable in Altair
rollback(state)
return false return false
# only blocks currently being produced have an empty state root - we use a # only blocks currently being produced have an empty state root - we use a
@ -366,6 +259,13 @@ proc state_transition_block*(
true true
type
RollbackForkedHashedProc* =
proc(state: var ForkedHashedBeaconState) {.gcsafe, raises: [Defect].}
func noRollback*(state: var ForkedHashedBeaconState) =
trace "Skipping rollback of broken state"
proc state_transition_block*( proc state_transition_block*(
preset: RuntimePreset, preset: RuntimePreset,
state: var ForkedHashedBeaconState, state: var ForkedHashedBeaconState,
@ -373,21 +273,28 @@ proc state_transition_block*(
phase0.TrustedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock |
altair.SignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock, altair.SignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock,
cache: var StateCache, flags: UpdateFlags, cache: var StateCache, flags: UpdateFlags,
rollback: RollbackHashedProc, altairForkSlot: Slot): bool {.nbench.} = rollback: RollbackForkedHashedProc, altairForkSlot: Slot): bool {.nbench.} =
## `rollback` is called if the transition fails and the given state has been ## `rollback` is called if the transition fails and the given state has been
## partially changed. If a temporary state was given to `state_transition`, ## partially changed. If a temporary state was given to `state_transition`,
## it is safe to use `noRollback` and leave it broken, else the state ## 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 ## object should be rolled back to a consistent state. If the transition fails
## before the state has been updated, `rollback` will not be called. ## before the state has been updated, `rollback` will not be called.
doAssert not rollback.isNil, "use noRollback if it's ok to mess up state"
# Ensure state_transition_block()-only callers trigger this # Ensure state_transition_block()-only callers trigger this
maybeUpgradeStateToAltair(state, altairForkSlot) maybeUpgradeStateToAltair(state, altairForkSlot)
case state.beaconStateFork: let success = case state.beaconStateFork:
of forkPhase0: state_transition_block( of forkPhase0: state_transition_block_aux(
preset, state.hbsPhase0, signedBlock, cache, flags, rollback) preset, state.hbsPhase0, signedBlock, cache, flags)
of forkAltair: state_transition_block( of forkAltair: state_transition_block_aux(
preset, state.hbsAltair, signedBlock, cache, flags, rollback) preset, state.hbsAltair, signedBlock, cache, flags)
if not success:
rollback(state)
return false
true
proc state_transition*( proc state_transition*(
preset: RuntimePreset, preset: RuntimePreset,
@ -395,8 +302,8 @@ proc state_transition*(
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock, phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags, cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
rollback: RollbackHashedProc, rollback: RollbackForkedHashedProc,
altairForkEpoch: Epoch = FAR_FUTURE_EPOCH): bool {.nbench.} = altairForkSlot: Slot = FAR_FUTURE_SLOT): bool {.nbench.} =
## Apply a block to the state, advancing the slot counter as necessary. The ## 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 ## 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 ## is set, can be the slot state of the same slot as the block (where the
@ -412,46 +319,12 @@ proc state_transition*(
## it is safe to use `noRollback` and leave it broken, else the state ## 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 ## object should be rolled back to a consistent state. If the transition fails
## before the state has been updated, `rollback` will not be called. ## before the state has been updated, `rollback` will not be called.
let slot = signedBlock.message.slot if not process_slots(
if not (getStateField(state, slot) < slot): state, signedBlock.message.slot, cache, rewards,
if slotProcessed notin flags or getStateField(state, slot) != slot: flags + {skipLastStateRootCalculation}, altairForkSlot):
notice "State must precede block",
state_root = shortLog(getStateRoot(state)),
current_slot = getStateField(state, slot),
blck = shortLog(signedBlock)
return false
if not state_transition_slots(
preset, state, signedBlock, cache, rewards, flags,
altairForkEpoch.compute_start_slot_at_epoch):
return false return false
state_transition_block( state_transition_block(
preset, state, signedBlock, cache, flags, rollback, preset, state, signedBlock, cache, flags, rollback, altairForkSlot)
altairForkEpoch.compute_start_slot_at_epoch)
proc state_transition*(
preset: RuntimePreset,
state: var SomeHashedBeaconState,
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
rollback: RollbackHashedProc): bool =
# Does not follow hard forks; suitable only where that's irrelevant.
# TODO remove when callers gone
let slot = signedBlock.message.slot
if not (state.data.slot < slot):
if slotProcessed notin flags or state.data.slot != slot:
notice "State must precede block",
state_root = shortLog(state.root),
current_slot = state.data.slot,
blck = shortLog(signedBlock)
return false
if not state_transition_slots(
preset, state, signedBlock, cache, rewards, flags):
return false
state_transition_block(
preset, state, signedBlock, cache, flags, rollback)
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#preparing-for-a-beaconblock # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#preparing-for-a-beaconblock
proc makeBeaconBlock*( proc makeBeaconBlock*(

View File

@ -8,17 +8,16 @@
{.push raises: [Defect].} {.push raises: [Defect].}
import import
./datatypes, ./digest, ./helpers, ./datatypes, ./digest, ./forkedbeaconstate_helpers, ./helpers
../consensus_object_pools/statedata_helpers
const const
SAFETY_DECAY* = 10'u64 SAFETY_DECAY* = 10'u64
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/weak-subjectivity.md#calculating-the-weak-subjectivity-period # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/weak-subjectivity.md#calculating-the-weak-subjectivity-period
func compute_weak_subjectivity_period(state: StateData): uint64 = func compute_weak_subjectivity_period(state: ForkedHashedBeaconState): uint64 =
var weak_subjectivity_period = MIN_VALIDATOR_WITHDRAWABILITY_DELAY var weak_subjectivity_period = MIN_VALIDATOR_WITHDRAWABILITY_DELAY
let validator_count = let validator_count =
get_active_validator_indices_len(state.data.data, get_current_epoch(state)) get_active_validator_indices_len(state.hbsPhase0.data, get_current_epoch(state))
if validator_count >= MIN_PER_EPOCH_CHURN_LIMIT * CHURN_LIMIT_QUOTIENT: if validator_count >= MIN_PER_EPOCH_CHURN_LIMIT * CHURN_LIMIT_QUOTIENT:
weak_subjectivity_period += SAFETY_DECAY * CHURN_LIMIT_QUOTIENT div (2 * 100) weak_subjectivity_period += SAFETY_DECAY * CHURN_LIMIT_QUOTIENT div (2 * 100)
else: else:
@ -27,7 +26,7 @@ func compute_weak_subjectivity_period(state: StateData): uint64 =
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/weak-subjectivity.md#checking-for-stale-weak-subjectivity-checkpoint # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/weak-subjectivity.md#checking-for-stale-weak-subjectivity-checkpoint
func is_within_weak_subjectivity_period*(current_slot: Slot, func is_within_weak_subjectivity_period*(current_slot: Slot,
ws_state: StateData, ws_state: ForkedHashedBeaconState,
ws_checkpoint: Checkpoint): bool = ws_checkpoint: Checkpoint): bool =
# Clients may choose to validate the input state against the input Weak Subjectivity Checkpoint # Clients may choose to validate the input state against the input Weak Subjectivity Checkpoint
doAssert getStateField(ws_state, latest_block_header).state_root == doAssert getStateField(ws_state, latest_block_header).state_root ==

View File

@ -10,7 +10,8 @@
import import
os, strformat, chronicles, os, strformat, chronicles,
./ssz_serialization, ./ssz_serialization,
../spec/[crypto, datatypes, digest] ../spec/[crypto, datatypes, digest],
../consensus_object_pools/block_pools_types
# Dump errors are generally not fatal where used currently - the code calling # Dump errors are generally not fatal where used currently - the code calling
# these functions, like most code, is not exception safe # these functions, like most code, is not exception safe

View File

@ -10,7 +10,7 @@
import import
options, tables, sets, macros, options, tables, sets, macros,
chronicles, chronos, stew/ranges/bitranges, libp2p/switch, chronicles, chronos, stew/ranges/bitranges, libp2p/switch,
../spec/[datatypes, network, crypto, digest], ../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers, network],
../beacon_node_types, ../beacon_node_types,
../networking/eth2_network, ../networking/eth2_network,
../consensus_object_pools/blockchain_dag ../consensus_object_pools/blockchain_dag
@ -85,9 +85,9 @@ proc getCurrentStatus*(state: BeaconSyncNetworkState): StatusMsg {.gcsafe.} =
StatusMsg( StatusMsg(
forkDigest: state.forkDigest, forkDigest: state.forkDigest,
finalizedRoot: finalizedRoot:
getStateField(dag.headState, finalized_checkpoint).root, getStateField(dag.headState.data, finalized_checkpoint).root,
finalizedEpoch: finalizedEpoch:
getStateField(dag.headState, finalized_checkpoint).epoch, getStateField(dag.headState.data, finalized_checkpoint).epoch,
headRoot: headBlock.root, headRoot: headBlock.root,
headSlot: headBlock.slot) headSlot: headBlock.slot)

View File

@ -21,7 +21,8 @@ import
# Local modules # Local modules
../spec/[ ../spec/[
datatypes, digest, crypto, helpers, network, signatures, state_transition], datatypes, digest, crypto, forkedbeaconstate_helpers, helpers, network,
signatures, state_transition],
../conf, ../beacon_clock, ../conf, ../beacon_clock,
../consensus_object_pools/[ ../consensus_object_pools/[
spec_cache, blockchain_dag, block_clearance, spec_cache, blockchain_dag, block_clearance,
@ -56,7 +57,7 @@ logScope: topics = "beacval"
proc findValidator(validators: auto, pubKey: ValidatorPubKey): proc findValidator(validators: auto, pubKey: ValidatorPubKey):
Option[ValidatorIndex] = Option[ValidatorIndex] =
let idx = validators.asSeq.findIt(it.pubKey == pubKey) let idx = validators.findIt(it.pubKey == pubKey)
if idx == -1: if idx == -1:
# We allow adding a validator even if its key is not in the state registry: # We allow adding a validator even if its key is not in the state registry:
# it might be that the deposit for this validator has not yet been processed # it might be that the deposit for this validator has not yet been processed
@ -66,16 +67,17 @@ proc findValidator(validators: auto, pubKey: ValidatorPubKey):
some(idx.ValidatorIndex) some(idx.ValidatorIndex)
proc addLocalValidator(node: BeaconNode, proc addLocalValidator(node: BeaconNode,
stateData: StateData, validators: openArray[Validator],
privKey: ValidatorPrivKey) = privKey: ValidatorPrivKey) =
let pubKey = privKey.toPubKey() let pubKey = privKey.toPubKey()
node.attachedValidators[].addLocalValidator( node.attachedValidators[].addLocalValidator(
pubKey, privKey, pubKey, privKey,
findValidator(getStateField(stateData, validators), pubKey.toPubKey())) findValidator(validators, pubKey.toPubKey()))
proc addLocalValidators*(node: BeaconNode) = proc addLocalValidators*(node: BeaconNode) =
for validatorKey in node.config.validatorKeys: for validatorKey in node.config.validatorKeys:
node.addLocalValidator node.dag.headState, validatorKey node.addLocalValidator(
getStateField(node.dag.headState.data, validators).asSeq, validatorKey)
proc addRemoteValidators*(node: BeaconNode) {.raises: [Defect, OSError, IOError].} = proc addRemoteValidators*(node: BeaconNode) {.raises: [Defect, OSError, IOError].} =
# load all the validators from the child process - loop until `end` # load all the validators from the child process - loop until `end`
@ -85,7 +87,7 @@ proc addRemoteValidators*(node: BeaconNode) {.raises: [Defect, OSError, IOError]
let let
key = ValidatorPubKey.fromHex(line).get() key = ValidatorPubKey.fromHex(line).get()
index = findValidator( index = findValidator(
getStateField(node.dag.headState, validators), key) getStateField(node.dag.headState.data, validators).asSeq, key)
pk = key.load() pk = key.load()
if pk.isSome(): if pk.isSome():
let v = AttachedValidator(pubKey: pk.get(), let v = AttachedValidator(pubKey: pk.get(),
@ -254,19 +256,20 @@ proc createAndSendAttestation(node: BeaconNode,
notice "Error sending attestation", err = exc.msg notice "Error sending attestation", err = exc.msg
proc getBlockProposalEth1Data*(node: BeaconNode, proc getBlockProposalEth1Data*(node: BeaconNode,
stateData: StateData): BlockProposalEth1Data = state: ForkedHashedBeaconState):
BlockProposalEth1Data =
if node.eth1Monitor.isNil: if node.eth1Monitor.isNil:
var pendingDepositsCount = var pendingDepositsCount =
getStateField(stateData, eth1_data).deposit_count - getStateField(state, eth1_data).deposit_count -
getStateField(stateData, eth1_deposit_index) getStateField(state, eth1_deposit_index)
if pendingDepositsCount > 0: if pendingDepositsCount > 0:
result.hasMissingDeposits = true result.hasMissingDeposits = true
else: else:
result.vote = getStateField(stateData, eth1_data) result.vote = getStateField(state, eth1_data)
else: else:
let finalizedEpochRef = node.dag.getFinalizedEpochRef() let finalizedEpochRef = node.dag.getFinalizedEpochRef()
result = node.eth1Monitor.getBlockProposalData( result = node.eth1Monitor.getBlockProposalData(
stateData, finalizedEpochRef.eth1_data, state, finalizedEpochRef.eth1_data,
finalizedEpochRef.eth1_deposit_index) finalizedEpochRef.eth1_deposit_index)
func getOpaqueTransaction(s: string): OpaqueTransaction = func getOpaqueTransaction(s: string): OpaqueTransaction =
@ -302,7 +305,7 @@ proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
node.dag.withState(proposalState[], head.atSlot(slot)): node.dag.withState(proposalState[], head.atSlot(slot)):
let let
eth1Proposal = node.getBlockProposalEth1Data(stateData) eth1Proposal = node.getBlockProposalEth1Data(stateData.data)
poolPtr = unsafeAddr node.dag # safe because restore is short-lived poolPtr = unsafeAddr node.dag # safe because restore is short-lived
if eth1Proposal.hasMissingDeposits: if eth1Proposal.hasMissingDeposits:
@ -318,13 +321,14 @@ proc makeBeaconBlockForHeadAndSlot*(node: BeaconNode,
return makeBeaconBlock( return makeBeaconBlock(
node.runtimePreset, node.runtimePreset,
hashedState, stateData.data.hbsPhase0,
validator_index, validator_index,
head.root, head.root,
randao_reveal, randao_reveal,
eth1Proposal.vote, eth1Proposal.vote,
graffiti, graffiti,
node.attestationPool[].getAttestationsForBlock(stateData, cache), node.attestationPool[].getAttestationsForBlock(
stateData.data.hbsPhase0, cache),
eth1Proposal.deposits, eth1Proposal.deposits,
node.exitPool[].getProposerSlashingsForBlock(), node.exitPool[].getProposerSlashingsForBlock(),
node.exitPool[].getAttesterSlashingsForBlock(), node.exitPool[].getAttesterSlashingsForBlock(),
@ -381,9 +385,9 @@ proc proposeBlock(node: BeaconNode,
return head return head
let let
fork = getStateField(node.dag.headState, fork) fork = getStateField(node.dag.headState.data, fork)
genesis_validators_root = genesis_validators_root =
getStateField(node.dag.headState, genesis_validators_root) getStateField(node.dag.headState.data, genesis_validators_root)
randao = await validator.genRandaoReveal( randao = await validator.genRandaoReveal(
fork, genesis_validators_root, slot) fork, genesis_validators_root, slot)
message = await makeBeaconBlockForHeadAndSlot( message = await makeBeaconBlockForHeadAndSlot(
@ -455,9 +459,9 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
epochRef = node.dag.getEpochRef( epochRef = node.dag.getEpochRef(
attestationHead.blck, slot.compute_epoch_at_slot()) attestationHead.blck, slot.compute_epoch_at_slot())
committees_per_slot = get_committee_count_per_slot(epochRef) committees_per_slot = get_committee_count_per_slot(epochRef)
fork = getStateField(node.dag.headState, fork) fork = getStateField(node.dag.headState.data, fork)
genesis_validators_root = genesis_validators_root =
getStateField(node.dag.headState, genesis_validators_root) getStateField(node.dag.headState.data, genesis_validators_root)
for committee_index in get_committee_indices(epochRef): for committee_index in get_committee_indices(epochRef):
let committee = get_beacon_committee(epochRef, slot, committee_index) let committee = get_beacon_committee(epochRef, slot, committee_index)
@ -528,9 +532,9 @@ proc broadcastAggregatedAttestations(
let let
epochRef = node.dag.getEpochRef(aggregationHead, aggregationSlot.epoch) epochRef = node.dag.getEpochRef(aggregationHead, aggregationSlot.epoch)
fork = getStateField(node.dag.headState, fork) fork = getStateField(node.dag.headState.data, fork)
genesis_validators_root = genesis_validators_root =
getStateField(node.dag.headState, genesis_validators_root) getStateField(node.dag.headState.data, genesis_validators_root)
committees_per_slot = get_committee_count_per_slot(epochRef) committees_per_slot = get_committee_count_per_slot(epochRef)
var var
@ -589,14 +593,14 @@ proc updateValidatorMetrics*(node: BeaconNode) =
if v.index.isNone(): if v.index.isNone():
0.Gwei 0.Gwei
elif v.index.get().uint64 >= elif v.index.get().uint64 >=
getStateField(node.dag.headState, balances).lenu64: getStateField(node.dag.headState.data, balances).lenu64:
debug "Cannot get validator balance, index out of bounds", debug "Cannot get validator balance, index out of bounds",
pubkey = shortLog(v.pubkey), index = v.index.get(), pubkey = shortLog(v.pubkey), index = v.index.get(),
balances = getStateField(node.dag.headState, balances).len, balances = getStateField(node.dag.headState.data, balances).len,
stateRoot = node.dag.headState.data.root stateRoot = getStateRoot(node.dag.headState.data)
0.Gwei 0.Gwei
else: else:
getStateField(node.dag.headState, balances)[v.index.get()] getStateField(node.dag.headState.data, balances)[v.index.get()]
if i < 64: if i < 64:
attached_validator_balance.set( attached_validator_balance.set(

View File

@ -12,8 +12,8 @@ import
confutils/defs, serialization, chronicles, confutils/defs, serialization, chronicles,
# Beacon-chain # Beacon-chain
../beacon_chain/spec/[ ../beacon_chain/spec/[
datatypes, crypto, helpers, beaconstate, helpers, beaconstate, crypto, datatypes, forkedbeaconstate_helpers, helpers,
state_transition_block, state_transition_epoch, state_transition], state_transition, state_transition_block],
../beacon_chain/extras, ../beacon_chain/extras,
../beacon_chain/ssz/[merkleization, ssz_serialization], ../beacon_chain/ssz/[merkleization, ssz_serialization],
../tests/official/fixtures_utils ../tests/official/fixtures_utils
@ -149,10 +149,11 @@ proc runFullTransition*(dir, preState, blocksPrefix: string, blocksQty: int, ski
rewards = RewardInfo() rewards = RewardInfo()
echo "Running: ", prePath echo "Running: ", prePath
let state = (ref HashedBeaconState)( let state = (ref ForkedHashedBeaconState)(
data: parseSSZ(prePath, BeaconState) hbsPhase0: HashedBeaconState(data: parseSSZ(prePath, BeaconState)),
beaconStateFork: forkPhase0
) )
state.root = hash_tree_root(state.data) state.hbsPhase0.root = hash_tree_root(state[])
for i in 0 ..< blocksQty: for i in 0 ..< blocksQty:
let blockPath = dir / blocksPrefix & $i & ".ssz" let blockPath = dir / blocksPrefix & $i & ".ssz"
@ -173,13 +174,15 @@ proc runProcessSlots*(dir, preState: string, numSlots: uint64) =
let prePath = dir / preState & ".ssz" let prePath = dir / preState & ".ssz"
echo "Running: ", prePath echo "Running: ", prePath
let state = (ref HashedBeaconState)( let state = (ref ForkedHashedBeaconState)(
data: parseSSZ(prePath, BeaconState) hbsPhase0: HashedBeaconState(data: parseSSZ(prePath, BeaconState)),
) beaconStateFork: forkPhase0)
state.root = hash_tree_root(state.data) state.hbsPhase0.root = hash_tree_root(state[])
# Shouldn't necessarily assert, because nbench can run test suite # Shouldn't necessarily assert, because nbench can run test suite
discard process_slots(state[], state.data.slot + numSlots, cache, rewards) discard process_slots(
state[], getStateField(state[], slot) + numSlots, cache, rewards, {},
FAR_FUTURE_SLOT)
template processEpochScenarioImpl( template processEpochScenarioImpl(
dir, preState: string, dir, preState: string,

View File

@ -3,7 +3,8 @@ import
confutils, chronicles, json_serialization, confutils, chronicles, json_serialization,
stew/byteutils, stew/byteutils,
../research/simutils, ../research/simutils,
../beacon_chain/spec/[crypto, datatypes, digest, helpers, state_transition], ../beacon_chain/spec/[
crypto, datatypes, digest, forkedbeaconstate_helpers, helpers, state_transition],
../beacon_chain/extras, ../beacon_chain/extras,
../beacon_chain/networking/network_metadata, ../beacon_chain/networking/network_metadata,
../beacon_chain/ssz/[merkleization, ssz_serialization] ../beacon_chain/ssz/[merkleization, ssz_serialization]
@ -75,13 +76,15 @@ type
proc doTransition(conf: NcliConf) = proc doTransition(conf: NcliConf) =
let let
stateY = (ref HashedBeaconState)( stateY = (ref ForkedHashedBeaconState)(
data: SSZ.loadFile(conf.preState, BeaconState), hbsPhase0: HashedBeaconState(
data: SSZ.loadFile(conf.preState, BeaconState)),
beaconStateFork: forkPhase0
) )
blckX = SSZ.loadFile(conf.blck, SignedBeaconBlock) blckX = SSZ.loadFile(conf.blck, SignedBeaconBlock)
flags = if not conf.verifyStateRoot: {skipStateRootValidation} else: {} flags = if not conf.verifyStateRoot: {skipStateRootValidation} else: {}
stateY.root = hash_tree_root(stateY.data) stateY.hbsPhase0.root = hash_tree_root(stateY[])
var var
cache = StateCache() cache = StateCache()
@ -91,7 +94,7 @@ proc doTransition(conf: NcliConf) =
error "State transition failed" error "State transition failed"
quit 1 quit 1
else: else:
SSZ.saveFile(conf.postState, stateY.data) SSZ.saveFile(conf.postState, stateY.hbsPhase0.data)
proc doSlots(conf: NcliConf) = proc doSlots(conf: NcliConf) =
type type
@ -103,22 +106,26 @@ proc doSlots(conf: NcliConf) =
var timers: array[Timers, RunningStat] var timers: array[Timers, RunningStat]
let let
stateY = withTimerRet(timers[tLoadState]): (ref HashedBeaconState)( stateY = withTimerRet(timers[tLoadState]): (ref ForkedHashedBeaconState)(
data: SSZ.loadFile(conf.preState2, BeaconState), hbsPhase0: HashedBeaconState(
data: SSZ.loadFile(conf.preState2, BeaconState)),
beaconStateFork: forkPhase0
) )
stateY.root = hash_tree_root(stateY.data) stateY.hbsPhase0.root = hash_tree_root(stateY[])
var var
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
for i in 0'u64..<conf.slot: for i in 0'u64..<conf.slot:
let isEpoch = (stateY[].data.slot + 1).isEpoch let isEpoch = (getStateField(stateY[], slot) + 1).isEpoch
withTimer(timers[if isEpoch: tApplyEpochSlot else: tApplySlot]): withTimer(timers[if isEpoch: tApplyEpochSlot else: tApplySlot]):
doAssert process_slots(stateY[], stateY[].data.slot + 1, cache, rewards) doAssert process_slots(
stateY[], getStateField(stateY[], slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
withTimer(timers[tSaveState]): withTimer(timers[tSaveState]):
SSZ.saveFile(conf.postState, stateY.data) SSZ.saveFile(conf.postState, stateY.hbsPhase0.data)
printTimers(false, timers) printTimers(false, timers)

View File

@ -3,9 +3,10 @@ import
chronicles, confutils, stew/byteutils, eth/db/kvstore_sqlite3, chronicles, confutils, stew/byteutils, eth/db/kvstore_sqlite3,
../beacon_chain/networking/network_metadata, ../beacon_chain/networking/network_metadata,
../beacon_chain/[beacon_chain_db, extras], ../beacon_chain/[beacon_chain_db, extras],
../beacon_chain/consensus_object_pools/[blockchain_dag, statedata_helpers], ../beacon_chain/consensus_object_pools/blockchain_dag,
../beacon_chain/spec/[crypto, datatypes, digest, helpers, state_transition, ../beacon_chain/spec/[crypto, datatypes, digest, forkedbeaconstate_helpers,
state_transition_epoch, presets], helpers, state_transition, state_transition_epoch,
presets],
../beacon_chain/ssz, ../beacon_chain/ssz/sszdump, ../beacon_chain/ssz, ../beacon_chain/ssz/sszdump,
../research/simutils, ./e2store ../research/simutils, ./e2store
@ -196,11 +197,12 @@ proc cmdBench(conf: DbConf, runtimePreset: RuntimePreset) =
state[], blockRefs[^1].atSlot(blockRefs[^1].slot - 1), false, cache) state[], blockRefs[^1].atSlot(blockRefs[^1].slot - 1), false, cache)
for b in blocks.mitems(): for b in blocks.mitems():
while getStateField(state[], slot) < b.message.slot: while getStateField(state[].data, slot) < b.message.slot:
let isEpoch = (getStateField(state[], slot) + 1).isEpoch() let isEpoch = (getStateField(state[].data, slot) + 1).isEpoch()
withTimer(timers[if isEpoch: tAdvanceEpoch else: tAdvanceSlot]): withTimer(timers[if isEpoch: tAdvanceEpoch else: tAdvanceSlot]):
let ok = process_slots( let ok = process_slots(
state[].data, getStateField(state[], slot) + 1, cache, rewards, {}) state[].data, getStateField(state[].data, slot) + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
doAssert ok, "Slot processing can't fail with correct inputs" doAssert ok, "Slot processing can't fail with correct inputs"
var start = Moment.now() var start = Moment.now()
@ -208,7 +210,7 @@ proc cmdBench(conf: DbConf, runtimePreset: RuntimePreset) =
if conf.resetCache: if conf.resetCache:
cache = StateCache() cache = StateCache()
if not state_transition_block( if not state_transition_block(
runtimePreset, state[].data, b, cache, {}, noRollback): runtimePreset, state[].data, b, cache, {}, noRollback, FAR_FUTURE_SLOT):
dump("./", b) dump("./", b)
echo "State transition failed (!)" echo "State transition failed (!)"
quit 1 quit 1
@ -218,20 +220,20 @@ proc cmdBench(conf: DbConf, runtimePreset: RuntimePreset) =
withTimer(timers[tDbStore]): withTimer(timers[tDbStore]):
dbBenchmark.putBlock(b) dbBenchmark.putBlock(b)
if getStateField(state[], slot).isEpoch and conf.storeStates: if getStateField(state[].data, slot).isEpoch and conf.storeStates:
if getStateField(state[], slot).epoch < 2: if getStateField(state[].data, slot).epoch < 2:
dbBenchmark.putState(state[].data.root, state[].data.data) dbBenchmark.putState(getStateRoot(state[].data), state[].data.hbsPhase0.data)
dbBenchmark.checkpoint() dbBenchmark.checkpoint()
else: else:
withTimer(timers[tDbStore]): withTimer(timers[tDbStore]):
dbBenchmark.putState(state[].data.root, state[].data.data) dbBenchmark.putState(getStateRoot(state[].data), state[].data.hbsPhase0.data)
dbBenchmark.checkpoint() dbBenchmark.checkpoint()
withTimer(timers[tDbLoad]): withTimer(timers[tDbLoad]):
doAssert dbBenchmark.getState(state[].data.root, loadedState[], noRollback) doAssert dbBenchmark.getState(getStateRoot(state[].data), loadedState[], noRollback)
if getStateField(state[], slot).epoch mod 16 == 0: if getStateField(state[].data, slot).epoch mod 16 == 0:
doAssert hash_tree_root(state[]) == hash_tree_root(loadedState[]) doAssert hash_tree_root(state[].data) == hash_tree_root(loadedState[])
printTimers(false, timers) printTimers(false, timers)
@ -368,7 +370,7 @@ proc cmdRewindState(conf: DbConf, preset: RuntimePreset) =
let tmpState = assignClone(dag.headState) let tmpState = assignClone(dag.headState)
dag.withState(tmpState[], blckRef.atSlot(Slot(conf.slot))): dag.withState(tmpState[], blckRef.atSlot(Slot(conf.slot))):
echo "Writing state..." echo "Writing state..."
dump("./", hashedState, blck) dump("./", stateData.data.hbsPhase0, blck)
proc atCanonicalSlot(blck: BlockRef, slot: Slot): BlockSlot = proc atCanonicalSlot(blck: BlockRef, slot: Slot): BlockSlot =
if slot == 0: if slot == 0:
@ -406,7 +408,7 @@ proc cmdExportEra(conf: DbConf, preset: RuntimePreset) =
defer: e2s.close() defer: e2s.close()
dag.withState(tmpState[], canonical): dag.withState(tmpState[], canonical):
e2s.appendRecord(stateData.data.data).get() e2s.appendRecord(stateData.data.hbsPhase0.data).get()
var var
ancestors: seq[BlockRef] ancestors: seq[BlockRef]
@ -455,7 +457,7 @@ proc cmdValidatorPerf(conf: DbConf, runtimePreset: RuntimePreset) =
(start, ends) = dag.getSlotRange(conf.perfSlot, conf.perfSlots) (start, ends) = dag.getSlotRange(conf.perfSlot, conf.perfSlots)
blockRefs = dag.getBlockRange(start, ends) blockRefs = dag.getBlockRange(start, ends)
perfs = newSeq[ValidatorPerformance]( perfs = newSeq[ValidatorPerformance](
getStateField(dag.headState, validators).len()) getStateField(dag.headState.data, validators).len())
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
blck: TrustedSignedBeaconBlock blck: TrustedSignedBeaconBlock
@ -472,20 +474,20 @@ proc cmdValidatorPerf(conf: DbConf, runtimePreset: RuntimePreset) =
proc processEpoch() = proc processEpoch() =
let let
prev_epoch_target_slot = prev_epoch_target_slot =
state[].get_previous_epoch().compute_start_slot_at_epoch() state[].data.get_previous_epoch().compute_start_slot_at_epoch()
penultimate_epoch_end_slot = penultimate_epoch_end_slot =
if prev_epoch_target_slot == 0: Slot(0) if prev_epoch_target_slot == 0: Slot(0)
else: prev_epoch_target_slot - 1 else: prev_epoch_target_slot - 1
first_slot_empty = first_slot_empty =
state[].get_block_root_at_slot(prev_epoch_target_slot) == state[].data.get_block_root_at_slot(prev_epoch_target_slot) ==
state[].get_block_root_at_slot(penultimate_epoch_end_slot) state[].data.get_block_root_at_slot(penultimate_epoch_end_slot)
let first_slot_attesters = block: let first_slot_attesters = block:
let committee_count = state[].get_committee_count_per_slot( let committee_count = state[].data.get_committee_count_per_slot(
prev_epoch_target_slot.epoch, cache) prev_epoch_target_slot.epoch, cache)
var indices = HashSet[ValidatorIndex]() var indices = HashSet[ValidatorIndex]()
for committee_index in 0..<committee_count: for committee_index in 0..<committee_count:
for validator_index in state[].get_beacon_committee( for validator_index in state[].data.get_beacon_committee(
prev_epoch_target_slot, committee_index.CommitteeIndex, cache): prev_epoch_target_slot, committee_index.CommitteeIndex, cache):
indices.incl(validator_index) indices.incl(validator_index)
indices indices
@ -521,26 +523,28 @@ proc cmdValidatorPerf(conf: DbConf, runtimePreset: RuntimePreset) =
for bi in 0..<blockRefs.len: for bi in 0..<blockRefs.len:
blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get() blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get()
while getStateField(state[], slot) < blck.message.slot: while getStateField(state[].data, slot) < blck.message.slot:
let ok = process_slots( let ok = process_slots(
state[].data, getStateField(state[], slot) + 1, cache, rewards, {}) state[].data, getStateField(state[].data, slot) + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
doAssert ok, "Slot processing can't fail with correct inputs" doAssert ok, "Slot processing can't fail with correct inputs"
if getStateField(state[], slot).isEpoch(): if getStateField(state[].data, slot).isEpoch():
processEpoch() processEpoch()
if not state_transition_block( if not state_transition_block(
runtimePreset, state[].data, blck, cache, {}, noRollback): runtimePreset, state[].data, blck, cache, {}, noRollback, FAR_FUTURE_SLOT):
echo "State transition failed (!)" echo "State transition failed (!)"
quit 1 quit 1
# Capture rewards of empty slots as well # Capture rewards of empty slots as well
while getStateField(state[], slot) < ends: while getStateField(state[].data, slot) < ends:
let ok = process_slots( let ok = process_slots(
state[].data, getStateField(state[], slot) + 1, cache, rewards, {}) state[].data, getStateField(state[].data, slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
doAssert ok, "Slot processing can't fail with correct inputs" doAssert ok, "Slot processing can't fail with correct inputs"
if getStateField(state[], slot).isEpoch(): if getStateField(state[].data, slot).isEpoch():
processEpoch() processEpoch()
echo "validator_index,attestation_hits,attestation_misses,head_attestation_hits,head_attestation_misses,target_attestation_hits,target_attestation_misses,delay_avg,first_slot_head_attester_when_first_slot_empty,first_slot_head_attester_when_first_slot_not_empty" echo "validator_index,attestation_hits,attestation_misses,head_attestation_hits,head_attestation_misses,target_attestation_hits,target_attestation_misses,delay_avg,first_slot_head_attester_when_first_slot_empty,first_slot_head_attester_when_first_slot_not_empty"
@ -666,11 +670,11 @@ proc cmdValidatorDb(conf: DbConf, runtimePreset: RuntimePreset) =
outDb.exec("BEGIN TRANSACTION;").expect("DB") outDb.exec("BEGIN TRANSACTION;").expect("DB")
for i in vals..<getStateField(dag.headState, validators).len(): for i in vals..<getStateField(dag.headState.data, validators).len():
insertValidator.exec(( insertValidator.exec((
i, i,
getStateField(dag.headState, validators).data[i].pubkey.toRaw(), getStateField(dag.headState.data, validators).data[i].pubkey.toRaw(),
getStateField(dag.headState, validators).data[i].withdrawal_credentials.data)).expect("DB") getStateField(dag.headState.data, validators).data[i].withdrawal_credentials.data)).expect("DB")
outDb.exec("COMMIT;").expect("DB") outDb.exec("COMMIT;").expect("DB")
@ -702,10 +706,10 @@ proc cmdValidatorDb(conf: DbConf, runtimePreset: RuntimePreset) =
false, cache) false, cache)
proc processEpoch() = proc processEpoch() =
echo getStateField(state[], slot).epoch echo getStateField(state[].data, slot).epoch
outDb.exec("BEGIN TRANSACTION;").expect("DB") outDb.exec("BEGIN TRANSACTION;").expect("DB")
insertEpochInfo.exec( insertEpochInfo.exec(
(getStateField(state[], slot).epoch.int64, (getStateField(state[].data, slot).epoch.int64,
rewards.total_balances.current_epoch_raw.int64, rewards.total_balances.current_epoch_raw.int64,
rewards.total_balances.previous_epoch_raw.int64, rewards.total_balances.previous_epoch_raw.int64,
rewards.total_balances.current_epoch_attesters_raw.int64, rewards.total_balances.current_epoch_attesters_raw.int64,
@ -737,7 +741,7 @@ proc cmdValidatorDb(conf: DbConf, runtimePreset: RuntimePreset) =
delay.isSome() and delay.get() == 1): delay.isSome() and delay.get() == 1):
insertValidatorInfo.exec( insertValidatorInfo.exec(
(index.int64, (index.int64,
getStateField(state[], slot).epoch.int64, getStateField(state[].data, slot).epoch.int64,
status.delta.rewards.int64, status.delta.rewards.int64,
status.delta.penalties.int64, status.delta.penalties.int64,
int64(source_attester), # Source delta int64(source_attester), # Source delta
@ -748,27 +752,29 @@ proc cmdValidatorDb(conf: DbConf, runtimePreset: RuntimePreset) =
for bi in 0..<blockRefs.len: for bi in 0..<blockRefs.len:
blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get() blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get()
while getStateField(state[], slot) < blck.message.slot: while getStateField(state[].data, slot) < blck.message.slot:
let ok = process_slots( let ok = process_slots(
state[].data, getStateField(state[], slot) + 1, cache, rewards, {}) state[].data, getStateField(state[].data, slot) + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
doAssert ok, "Slot processing can't fail with correct inputs" doAssert ok, "Slot processing can't fail with correct inputs"
if getStateField(state[], slot).isEpoch(): if getStateField(state[].data, slot).isEpoch():
processEpoch() processEpoch()
if not state_transition_block( if not state_transition_block(
runtimePreset, state[].data, blck, cache, {}, noRollback): runtimePreset, state[].data, blck, cache, {}, noRollback, FAR_FUTURE_SLOT):
echo "State transition failed (!)" echo "State transition failed (!)"
quit 1 quit 1
# Capture rewards of empty slots as well, including the epoch that got # Capture rewards of empty slots as well, including the epoch that got
# finalized # finalized
while getStateField(state[], slot) <= ends: while getStateField(state[].data, slot) <= ends:
let ok = process_slots( let ok = process_slots(
state[].data, getStateField(state[], slot) + 1, cache, rewards, {}) state[].data, getStateField(state[].data, slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
doAssert ok, "Slot processing can't fail with correct inputs" doAssert ok, "Slot processing can't fail with correct inputs"
if getStateField(state[], slot).isEpoch(): if getStateField(state[].data, slot).isEpoch():
processEpoch() processEpoch()
when isMainModule: when isMainModule:

View File

@ -4,8 +4,9 @@
import import
stew/ptrops, stew/ranges/ptr_arith, chronicles, stew/ptrops, stew/ranges/ptr_arith, chronicles,
../beacon_chain/extras, ../beacon_chain/extras,
../beacon_chain/spec/[crypto, datatypes, digest, validator, beaconstate, ../beacon_chain/spec/[
state_transition_block, state_transition, presets], beaconstate, crypto, datatypes, digest, forkedbeaconstate_helpers, presets,
validator, state_transition, state_transition_block],
../beacon_chain/ssz/[merkleization, ssz_serialization] ../beacon_chain/ssz/[merkleization, ssz_serialization]
type type
@ -110,17 +111,19 @@ proc nfuzz_block(input: openArray[byte], xoutput: ptr byte,
# and requiring HashedBeaconState (yet). So to keep consistent, puts wrapper # and requiring HashedBeaconState (yet). So to keep consistent, puts wrapper
# only in one function. # only in one function.
proc state_transition( proc state_transition(
preset: RuntimePreset, data: auto, blck: auto, flags: auto, rollback: RollbackHashedProc): preset: RuntimePreset, data: auto, blck: auto, flags: auto,
auto = rollback: RollbackForkedHashedProc): auto =
var var
hashedState = fhState = (ref ForkedHashedBeaconState)(
HashedBeaconState(data: data.state, root: hash_tree_root(data.state)) hbsPhase0: HashedBeaconState(
data: data.state, root: hash_tree_root(data.state)),
beaconStateFork: forkPhase0)
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
result = result =
state_transition( state_transition(
preset, hashedState, blck, cache, rewards, flags, rollback) preset, fhState[], blck, cache, rewards, flags, rollback)
data.state = hashedState.data data.state = fhState.hbsPhase0.data
decodeAndProcess(BlockInput): decodeAndProcess(BlockInput):
state_transition(defaultRuntimePreset, data, data.beaconBlock, flags, noRollback) state_transition(defaultRuntimePreset, data, data.beaconBlock, flags, noRollback)

View File

@ -19,15 +19,15 @@ import
options, random, tables, os, options, random, tables, os,
confutils, chronicles, eth/db/kvstore_sqlite3, confutils, chronicles, eth/db/kvstore_sqlite3,
eth/keys, eth/keys,
../tests/[testblockutil], ../tests/testblockutil,
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, presets, ../beacon_chain/spec/[beaconstate, crypto, datatypes, digest,
helpers, validator, signatures, state_transition], forkedbeaconstate_helpers, presets,
helpers, signatures, state_transition],
../beacon_chain/[beacon_node_types, beacon_chain_db, extras], ../beacon_chain/[beacon_node_types, beacon_chain_db, extras],
../beacon_chain/eth1/eth1_monitor, ../beacon_chain/eth1/eth1_monitor,
../beacon_chain/validators/validator_pool, ../beacon_chain/validators/validator_pool,
../beacon_chain/consensus_object_pools/[blockchain_dag, block_quarantine, ../beacon_chain/consensus_object_pools/[blockchain_dag, block_quarantine,
block_clearance, attestation_pool, block_clearance, attestation_pool],
statedata_helpers],
../beacon_chain/ssz/[merkleization, ssz_serialization], ../beacon_chain/ssz/[merkleization, ssz_serialization],
./simutils ./simutils
@ -97,22 +97,22 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
dag.withState(tmpState[], attestationHead): dag.withState(tmpState[], attestationHead):
let committees_per_slot = let committees_per_slot =
get_committee_count_per_slot(stateData, slot.epoch, cache) get_committee_count_per_slot(stateData.data, slot.epoch, cache)
for committee_index in 0'u64..<committees_per_slot: for committee_index in 0'u64..<committees_per_slot:
let committee = get_beacon_committee( let committee = get_beacon_committee(
stateData, slot, committee_index.CommitteeIndex, cache) stateData.data, slot, committee_index.CommitteeIndex, cache)
for index_in_committee, validatorIdx in committee: for index_in_committee, validatorIdx in committee:
if rand(r, 1.0) <= attesterRatio: if rand(r, 1.0) <= attesterRatio:
let let
data = makeAttestationData( data = makeAttestationData(
stateData, slot, committee_index.CommitteeIndex, blck.root) stateData.data, slot, committee_index.CommitteeIndex, blck.root)
sig = sig =
get_attestation_signature(getStateField(stateData, fork), get_attestation_signature(getStateField(stateData.data, fork),
getStateField(stateData, genesis_validators_root), getStateField(stateData.data, genesis_validators_root),
data, hackPrivKey( data, hackPrivKey(
getStateField(stateData, validators)[validatorIdx])) getStateField(stateData.data, validators)[validatorIdx]))
var aggregation_bits = CommitteeValidatorsBits.init(committee.len) var aggregation_bits = CommitteeValidatorsBits.init(committee.len)
aggregation_bits.setBit index_in_committee aggregation_bits.setBit index_in_committee
@ -134,25 +134,25 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
let let
finalizedEpochRef = dag.getFinalizedEpochRef() finalizedEpochRef = dag.getFinalizedEpochRef()
proposerIdx = get_beacon_proposer_index( proposerIdx = get_beacon_proposer_index(
stateData.data.data, cache).get() stateData.data, cache, getStateField(stateData.data, slot)).get()
privKey = hackPrivKey( privKey = hackPrivKey(
getStateField(stateData, validators)[proposerIdx]) getStateField(stateData.data, validators)[proposerIdx])
eth1ProposalData = eth1Chain.getBlockProposalData( eth1ProposalData = eth1Chain.getBlockProposalData(
stateData, stateData.data,
finalizedEpochRef.eth1_data, finalizedEpochRef.eth1_data,
finalizedEpochRef.eth1_deposit_index) finalizedEpochRef.eth1_deposit_index)
message = makeBeaconBlock( message = makeBeaconBlock(
runtimePreset, runtimePreset,
hashedState, stateData.data.hbsPhase0,
proposerIdx, proposerIdx,
head.root, head.root,
privKey.genRandaoReveal( privKey.genRandaoReveal(
getStateField(stateData, fork), getStateField(stateData.data, fork),
getStateField(stateData, genesis_validators_root), getStateField(stateData.data, genesis_validators_root),
slot).toValidatorSig(), slot).toValidatorSig(),
eth1ProposalData.vote, eth1ProposalData.vote,
default(GraffitiBytes), default(GraffitiBytes),
attPool.getAttestationsForBlock(stateData, cache), attPool.getAttestationsForTestBlock(stateData, cache),
eth1ProposalData.deposits, eth1ProposalData.deposits,
@[], @[],
@[], @[],
@ -172,8 +172,8 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
# Careful, state no longer valid after here because of the await.. # Careful, state no longer valid after here because of the await..
newBlock.signature = withTimerRet(timers[tSignBlock]): newBlock.signature = withTimerRet(timers[tSignBlock]):
get_block_signature( get_block_signature(
getStateField(stateData, fork), getStateField(stateData.data, fork),
getStateField(stateData, genesis_validators_root), getStateField(stateData.data, genesis_validators_root),
newBlock.message.slot, newBlock.message.slot,
blockRoot, privKey).toValidatorSig() blockRoot, privKey).toValidatorSig()
@ -235,7 +235,7 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
# TODO if attestation pool was smarter, it would include older attestations # TODO if attestation pool was smarter, it would include older attestations
# too! # too!
verifyConsensus(dag.headState, attesterRatio * blockRatio) verifyConsensus(dag.headState.data, attesterRatio * blockRatio)
if t == tEpoch: if t == tEpoch:
echo &". slot: {shortLog(slot)} ", echo &". slot: {shortLog(slot)} ",
@ -252,4 +252,4 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
echo "Done!" echo "Done!"
printTimers(dag.headState, attesters, true, timers) printTimers(dag.headState.data, attesters, true, timers)

View File

@ -3,9 +3,10 @@ import
../tests/testblockutil, ../tests/testblockutil,
../beacon_chain/[extras, beacon_chain_db], ../beacon_chain/[extras, beacon_chain_db],
../beacon_chain/ssz/[merkleization, ssz_serialization], ../beacon_chain/ssz/[merkleization, ssz_serialization],
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, presets], ../beacon_chain/spec/[
../beacon_chain/consensus_object_pools/[ beaconstate, crypto, datatypes, digest, forkedbeaconstate_helpers,
blockchain_dag, block_pools_types, statedata_helpers], helpers, presets],
../beacon_chain/consensus_object_pools/[blockchain_dag, block_pools_types],
../beacon_chain/eth1/eth1_monitor ../beacon_chain/eth1/eth1_monitor
template withTimer*(stats: var RunningStat, body: untyped) = template withTimer*(stats: var RunningStat, body: untyped) =
@ -43,7 +44,7 @@ func verifyConsensus*(state: BeaconState, attesterRatio: auto) =
if current_epoch >= 4: if current_epoch >= 4:
doAssert state.finalized_checkpoint.epoch + 2 >= current_epoch doAssert state.finalized_checkpoint.epoch + 2 >= current_epoch
func verifyConsensus*(state: StateData, attesterRatio: auto) = func verifyConsensus*(state: ForkedHashedBeaconState, attesterRatio: auto) =
if attesterRatio < 0.63: if attesterRatio < 0.63:
doAssert getStateField(state, current_justified_checkpoint).epoch == 0 doAssert getStateField(state, current_justified_checkpoint).epoch == 0
doAssert getStateField(state, finalized_checkpoint).epoch == 0 doAssert getStateField(state, finalized_checkpoint).epoch == 0
@ -144,7 +145,7 @@ proc printTimers*[Timers: enum](
printTimers(validate, timers) printTimers(validate, timers)
proc printTimers*[Timers: enum]( proc printTimers*[Timers: enum](
state: StateData, attesters: RunningStat, validate: bool, state: ForkedHashedBeaconState, attesters: RunningStat, validate: bool,
timers: array[Timers, RunningStat]) = timers: array[Timers, RunningStat]) =
echo "Validators: ", getStateField(state, validators).len, ", epoch length: ", SLOTS_PER_EPOCH echo "Validators: ", getStateField(state, validators).len, ", epoch length: ", SLOTS_PER_EPOCH
echo "Validators per attestation (mean): ", attesters.mean echo "Validators per attestation (mean): ", attesters.mean

View File

@ -13,7 +13,8 @@ import
strformat, strformat,
options, sequtils, random, tables, options, sequtils, random, tables,
../tests/testblockutil, ../tests/testblockutil,
../beacon_chain/spec/[beaconstate, crypto, datatypes, digest, helpers, validator], ../beacon_chain/spec/[
beaconstate, crypto, datatypes, digest, forkedbeaconstate_helpers, helpers],
../beacon_chain/extras, ../beacon_chain/extras,
../beacon_chain/ssz/[merkleization, ssz_serialization], ../beacon_chain/ssz/[merkleization, ssz_serialization],
./simutils ./simutils
@ -42,15 +43,16 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
validate = true): validate = true):
let let
flags = if validate: {} else: {skipBlsValidation} flags = if validate: {} else: {skipBlsValidation}
(state, _) = loadGenesis(validators, validate) (hashedState, _) = loadGenesis(validators, validate)
genesisBlock = get_initial_beacon_block(state.data) genesisBlock = get_initial_beacon_block(hashedState.data)
state = (ref ForkedHashedBeaconState)(
hbsPhase0: hashedState[], beaconStateFork: forkPhase0)
echo "Starting simulation..." echo "Starting simulation..."
var var
attestations = initTable[Slot, seq[Attestation]]() attestations = initTable[Slot, seq[Attestation]]()
latest_block_root = hash_tree_root(genesisBlock.message) latest_block_root = hash_tree_root(genesisBlock.message)
blockrefs = @[BlockRef(root: latest_block_root, slot: 0.Slot)]
timers: array[Timers, RunningStat] timers: array[Timers, RunningStat]
attesters: RunningStat attesters: RunningStat
r = initRand(1) r = initRand(1)
@ -59,16 +61,16 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
proc maybeWrite(last: bool) = proc maybeWrite(last: bool) =
if write_last_json: if write_last_json:
if state[].data.slot mod json_interval.uint64 == 0: if getStateField(state[], slot) mod json_interval.uint64 == 0:
write(stdout, ":") write(stdout, ":")
else: else:
write(stdout, ".") write(stdout, ".")
if last: if last:
writeJson("state.json", state[]) writeJson("state.json", state[].hbsPhase0)
else: else:
if state[].data.slot mod json_interval.uint64 == 0: if getStateField(state[], slot) mod json_interval.uint64 == 0:
writeJson(jsonName(prefix, state[].data.slot), state[].data) writeJson(jsonName(prefix, getStateField(state[], slot)), state[].hbsPhase0.data)
write(stdout, ":") write(stdout, ":")
else: else:
write(stdout, ".") write(stdout, ".")
@ -79,10 +81,10 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
for i in 0..<slots: for i in 0..<slots:
maybeWrite(false) maybeWrite(false)
verifyConsensus(state[].data, attesterRatio) verifyConsensus(state[].hbsPhase0.data, attesterRatio)
let let
attestations_idx = state[].data.slot attestations_idx = getStateField(state[], slot)
blockAttestations = attestations.getOrDefault(attestations_idx) blockAttestations = attestations.getOrDefault(attestations_idx)
attestations.del attestations_idx attestations.del attestations_idx
@ -90,8 +92,8 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
SLOTS_PER_EPOCH + MIN_ATTESTATION_INCLUSION_DELAY SLOTS_PER_EPOCH + MIN_ATTESTATION_INCLUSION_DELAY
let t = let t =
if (state[].data.slot > GENESIS_SLOT and if (getStateField(state[], slot) > GENESIS_SLOT and
(state[].data.slot + 1).isEpoch): tEpoch (getStateField(state[], slot) + 1).isEpoch): tEpoch
else: tBlock else: tBlock
withTimer(timers[t]): withTimer(timers[t]):
@ -107,20 +109,15 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
# work for every slot - we'll randomize it deterministically to give # work for every slot - we'll randomize it deterministically to give
# some variation # some variation
let let
target_slot = state[].data.slot + MIN_ATTESTATION_INCLUSION_DELAY - 1 target_slot = getStateField(state[], slot) + MIN_ATTESTATION_INCLUSION_DELAY - 1
committees_per_slot = committees_per_slot =
get_committee_count_per_slot(state[].data, target_slot.epoch, cache) get_committee_count_per_slot(state[], target_slot.epoch, cache)
blockrefs.add BlockRef(
root: latest_block_root, parent: blockrefs[^1], slot: target_slot)
let let
scass = withTimerRet(timers[tShuffle]): scass = withTimerRet(timers[tShuffle]):
mapIt( mapIt(
0 ..< committees_per_slot.int, 0 ..< committees_per_slot.int,
get_beacon_committee(state[].data, target_slot, it.CommitteeIndex, cache)) get_beacon_committee(state[], target_slot, it.CommitteeIndex, cache))
stateData = (ref StateData)(data: state[], blck: blockrefs[^1])
for i, scas in scass: for i, scas in scass:
var var
@ -135,13 +132,13 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
if (rand(r, high(int)).float * attesterRatio).int <= high(int): if (rand(r, high(int)).float * attesterRatio).int <= high(int):
if first: if first:
attestation = attestation =
makeAttestation(stateData[], latest_block_root, scas, target_slot, makeAttestation(state[], latest_block_root, scas, target_slot,
i.CommitteeIndex, v, cache, flags) i.CommitteeIndex, v, cache, flags)
agg.init(attestation.signature.load.get()) agg.init(attestation.signature.load.get())
first = false first = false
else: else:
let att2 = let att2 =
makeAttestation(stateData[], latest_block_root, scas, target_slot, makeAttestation(state[], latest_block_root, scas, target_slot,
i.CommitteeIndex, v, cache, flags) i.CommitteeIndex, v, cache, flags)
if not att2.aggregation_bits.overlaps(attestation.aggregation_bits): if not att2.aggregation_bits.overlaps(attestation.aggregation_bits):
attestation.aggregation_bits.incl(att2.aggregation_bits) attestation.aggregation_bits.incl(att2.aggregation_bits)
@ -164,13 +161,13 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
flushFile(stdout) flushFile(stdout)
if (state[].data.slot).isEpoch: if getStateField(state[], slot).isEpoch:
echo &" slot: {shortLog(state[].data.slot)} ", echo &" slot: {shortLog(getStateField(state[], slot))} ",
&"epoch: {shortLog(state[].data.get_current_epoch())}" &"epoch: {shortLog(state[].get_current_epoch())}"
maybeWrite(true) # catch that last state as well.. maybeWrite(true) # catch that last state as well..
echo "Done!" echo "Done!"
printTimers(state[].data, attesters, validate, timers) printTimers(state[].hbsPhase0.data, attesters, validate, timers)

View File

@ -1,5 +1,5 @@
# beacon_chain # beacon_chain
# Copyright (c) 2018-2020 Status Research & Development GmbH # Copyright (c) 2018-2021 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -10,21 +10,24 @@
import import
# Specs # Specs
../../beacon_chain/spec/[datatypes, state_transition] ../../beacon_chain/spec/[
datatypes, forkedbeaconstate_helpers, state_transition]
proc nextEpoch*(state: var HashedBeaconState) = proc nextEpoch*(state: var ForkedHashedBeaconState) =
## Transition to the start of the next epoch ## Transition to the start of the next epoch
var var
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
let slot = let slot =
state.data.slot + SLOTS_PER_EPOCH - (state.data.slot mod SLOTS_PER_EPOCH) getStateField(state, slot) + SLOTS_PER_EPOCH -
doAssert process_slots(state, slot, cache, rewards) (getStateField(state, slot) mod SLOTS_PER_EPOCH)
doAssert process_slots(state, slot, cache, rewards, {}, FAR_FUTURE_SLOT)
proc nextSlot*(state: var HashedBeaconState) = proc nextSlot*(state: var ForkedHashedBeaconState) =
## Transition to the next slot ## Transition to the next slot
var var
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
doAssert process_slots(state, state.data.slot + 1, cache, rewards) doAssert process_slots(
state, getStateField(state, slot) + 1, cache, rewards, {}, FAR_FUTURE_SLOT)

View File

@ -11,7 +11,8 @@ import
# Standard library # Standard library
os, sequtils, chronicles, os, sequtils, chronicles,
# Beacon chain internals # Beacon chain internals
../../../beacon_chain/spec/[crypto, state_transition, presets], ../../../beacon_chain/spec/[
crypto, forkedbeaconstate_helpers, presets, state_transition],
../../../beacon_chain/spec/datatypes/altair, ../../../beacon_chain/spec/datatypes/altair,
../../../beacon_chain/ssz, ../../../beacon_chain/ssz,
# Test utilities # Test utilities
@ -38,8 +39,8 @@ proc runTest(testName, testDir, unitTestName: string) =
test prefix & testName & " - " & unitTestName & preset(): test prefix & testName & " - " & unitTestName & preset():
var var
preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, BeaconState)) preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, BeaconState))
hashedPreState = (ref HashedBeaconState)( fhPreState = (ref ForkedHashedBeaconState)(hbsAltair: altair.HashedBeaconState(
data: preState[], root: hash_tree_root(preState[])) data: preState[], root: hash_tree_root(preState[])), beaconStateFork: forkAltair)
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
@ -51,12 +52,12 @@ proc runTest(testName, testDir, unitTestName: string) =
if hasPostState: if hasPostState:
let success = state_transition( let success = state_transition(
defaultRuntimePreset, hashedPreState[], blck, cache, rewards, flags = {}, defaultRuntimePreset, fhPreState[], blck, cache, rewards, flags = {},
noRollback) noRollback)
doAssert success, "Failure when applying block " & $i doAssert success, "Failure when applying block " & $i
else: else:
let success = state_transition( let success = state_transition(
defaultRuntimePreset, hashedPreState[], blck, cache, rewards, flags = {}, defaultRuntimePreset, fhPreState[], blck, cache, rewards, flags = {},
noRollback) noRollback)
doAssert (i + 1 < numBlocks) or not success, doAssert (i + 1 < numBlocks) or not success,
"We didn't expect these invalid blocks to be processed" "We didn't expect these invalid blocks to be processed"
@ -64,8 +65,8 @@ proc runTest(testName, testDir, unitTestName: string) =
if hasPostState: if hasPostState:
let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, BeaconState)) let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, BeaconState))
when false: when false:
reportDiff(hashedPreState.data, postState) reportDiff(fhPreState.hbsAltair.data, postState)
doAssert hashedPreState.root == postState[].hash_tree_root() doAssert getStateRoot(fhPreState[]) == postState[].hash_tree_root()
`testImpl _ blck _ testName`() `testImpl _ blck _ testName`()

View File

@ -12,7 +12,7 @@ import
# Standard library # Standard library
os, strutils, os, strutils,
# Beacon chain internals # Beacon chain internals
../../../beacon_chain/spec/state_transition, ../../../beacon_chain/spec/[forkedbeaconstate_helpers, state_transition],
../../../beacon_chain/spec/datatypes/altair, ../../../beacon_chain/spec/datatypes/altair,
# Test utilities # Test utilities
../../testutil, ../../testutil,
@ -30,18 +30,21 @@ proc runTest(identifier: string) =
test "Slots - " & identifier: test "Slots - " & identifier:
var var
preState = newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, BeaconState)) preState = newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, BeaconState))
hashedPreState = (ref HashedBeaconState)( fhPreState = (ref ForkedHashedBeaconState)(
data: preState[], root: hash_tree_root(preState[])) hbsAltair: altair.HashedBeaconState(
data: preState[], root: hash_tree_root(preState[])),
beaconStateFork: forkAltair)
cache = StateCache() cache = StateCache()
rewards: RewardInfo rewards: RewardInfo
let postState = newClone(parseTest(testDir/"post.ssz_snappy", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz_snappy", SSZ, BeaconState))
check: check:
process_slots( process_slots(
hashedPreState[], hashedPreState.data.slot + num_slots, cache, rewards) fhPreState[], getStateField(fhPreState[], slot) + num_slots, cache,
rewards, {}, FAR_FUTURE_SLOT)
hashedPreState.root == postState[].hash_tree_root() getStateRoot(fhPreState[]) == postState[].hash_tree_root()
let newPreState = newClone(hashedPreState.data) let newPreState = newClone(fhPreState.hbsAltair.data)
reportDiff(newPreState, postState) reportDiff(newPreState, postState)
`testImpl _ slots _ identifier`() `testImpl _ slots _ identifier`()

View File

@ -14,7 +14,8 @@ import
# Status internal # Status internal
faststreams, streams, faststreams, streams,
# Beacon chain internals # Beacon chain internals
../../../beacon_chain/spec/[crypto, state_transition, presets], ../../../beacon_chain/spec/[
crypto, state_transition, presets, forkedbeaconstate_helpers, helpers],
../../../beacon_chain/spec/datatypes/[phase0, altair], ../../../beacon_chain/spec/datatypes/[phase0, altair],
../../../beacon_chain/[extras, ssz], ../../../beacon_chain/[extras, ssz],
# Test utilities # Test utilities
@ -48,7 +49,7 @@ proc runTest(testName, testDir, unitTestName: string) =
test testName & " - " & unitTestName & preset(): test testName & " - " & unitTestName & preset():
var var
preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, phase0.BeaconState)) preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, phase0.BeaconState))
sdPreState = (ref ForkedHashedBeaconState)(hbsPhase0: phase0.HashedBeaconState( fhPreState = (ref ForkedHashedBeaconState)(hbsPhase0: phase0.HashedBeaconState(
data: preState[], root: hash_tree_root(preState[])), beaconStateFork: forkPhase0) data: preState[], root: hash_tree_root(preState[])), beaconStateFork: forkPhase0)
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
@ -62,25 +63,25 @@ proc runTest(testName, testDir, unitTestName: string) =
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, phase0.SignedBeaconBlock) let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, phase0.SignedBeaconBlock)
let success = state_transition( let success = state_transition(
defaultRuntimePreset, sdPreState[], blck, defaultRuntimePreset, fhPreState[], blck,
cache, rewards, cache, rewards,
flags = {skipStateRootValidation}, noRollback, flags = {skipStateRootValidation}, noRollback,
transitionEpoch.fork_epoch.Epoch) transitionEpoch.fork_epoch.Epoch.compute_start_slot_at_epoch)
doAssert success, "Failure when applying block " & $i doAssert success, "Failure when applying block " & $i
else: else:
let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, altair.SignedBeaconBlock) let blck = parseTest(testPath/"blocks_" & $i & ".ssz_snappy", SSZ, altair.SignedBeaconBlock)
let success = state_transition( let success = state_transition(
defaultRuntimePreset, sdPreState[], blck, defaultRuntimePreset, fhPreState[], blck,
cache, rewards, cache, rewards,
flags = {skipStateRootValidation}, noRollback, flags = {skipStateRootValidation}, noRollback,
transitionEpoch.fork_epoch.Epoch) transitionEpoch.fork_epoch.Epoch.compute_start_slot_at_epoch)
doAssert success, "Failure when applying block " & $i doAssert success, "Failure when applying block " & $i
let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, altair.BeaconState)) let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, altair.BeaconState))
when false: when false:
reportDiff(sdPreState.data, postState) reportDiff(fhPreState.data, postState)
doAssert getStateRoot(sdPreState[]) == postState[].hash_tree_root() doAssert getStateRoot(fhPreState[]) == postState[].hash_tree_root()
`testImpl _ blck _ testName`() `testImpl _ blck _ testName`()

View File

@ -11,7 +11,8 @@ import
# Standard library # Standard library
os, sequtils, chronicles, os, sequtils, chronicles,
# Beacon chain internals # Beacon chain internals
../../../beacon_chain/spec/[crypto, state_transition, presets], ../../../beacon_chain/spec/[
crypto, forkedbeaconstate_helpers, presets, state_transition],
../../../beacon_chain/spec/datatypes/phase0, ../../../beacon_chain/spec/datatypes/phase0,
../../../beacon_chain/ssz, ../../../beacon_chain/ssz,
# Test utilities # Test utilities
@ -38,8 +39,8 @@ proc runTest(testName, testDir, unitTestName: string) =
test prefix & testName & " - " & unitTestName & preset(): test prefix & testName & " - " & unitTestName & preset():
var var
preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, BeaconState)) preState = newClone(parseTest(testPath/"pre.ssz_snappy", SSZ, BeaconState))
hashedPreState = (ref HashedBeaconState)( fhPreState = (ref ForkedHashedBeaconState)(hbsPhase0: phase0.HashedBeaconState(
data: preState[], root: hash_tree_root(preState[])) data: preState[], root: hash_tree_root(preState[])), beaconStateFork: forkPhase0)
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
@ -51,12 +52,12 @@ proc runTest(testName, testDir, unitTestName: string) =
if hasPostState: if hasPostState:
let success = state_transition( let success = state_transition(
defaultRuntimePreset, hashedPreState[], blck, cache, rewards, flags = {}, defaultRuntimePreset, fhPreState[], blck, cache, rewards, flags = {},
noRollback) noRollback)
doAssert success, "Failure when applying block " & $i doAssert success, "Failure when applying block " & $i
else: else:
let success = state_transition( let success = state_transition(
defaultRuntimePreset, hashedPreState[], blck, cache, rewards, flags = {}, defaultRuntimePreset, fhPreState[], blck, cache, rewards, flags = {},
noRollback) noRollback)
doAssert (i + 1 < numBlocks) or not success, doAssert (i + 1 < numBlocks) or not success,
"We didn't expect these invalid blocks to be processed" "We didn't expect these invalid blocks to be processed"
@ -64,8 +65,8 @@ proc runTest(testName, testDir, unitTestName: string) =
if hasPostState: if hasPostState:
let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, BeaconState)) let postState = newClone(parseTest(testPath/"post.ssz_snappy", SSZ, BeaconState))
when false: when false:
reportDiff(hashedPreState.data, postState) reportDiff(hashedPreState.hbsPhase0.data, postState)
doAssert hashedPreState.root == postState[].hash_tree_root() doAssert getStateRoot(fhPreState[]) == postState[].hash_tree_root()
`testImpl _ blck _ testName`() `testImpl _ blck _ testName`()

View File

@ -12,7 +12,7 @@ import
# Standard library # Standard library
os, strutils, os, strutils,
# Beacon chain internals # Beacon chain internals
../../../beacon_chain/spec/state_transition, ../../../beacon_chain/spec/[forkedbeaconstate_helpers, state_transition],
../../../beacon_chain/spec/datatypes/phase0, ../../../beacon_chain/spec/datatypes/phase0,
# Test utilities # Test utilities
../../testutil, ../../testutil,
@ -30,18 +30,19 @@ proc runTest(identifier: string) =
test "Slots - " & identifier: test "Slots - " & identifier:
var var
preState = newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, BeaconState)) preState = newClone(parseTest(testDir/"pre.ssz_snappy", SSZ, BeaconState))
hashedPreState = (ref HashedBeaconState)( fhPreState = (ref ForkedHashedBeaconState)(hbsPhase0: phase0.HashedBeaconState(
data: preState[], root: hash_tree_root(preState[])) data: preState[], root: hash_tree_root(preState[])), beaconStateFork: forkPhase0)
cache = StateCache() cache = StateCache()
rewards: RewardInfo rewards: RewardInfo
let postState = newClone(parseTest(testDir/"post.ssz_snappy", SSZ, BeaconState)) let postState = newClone(parseTest(testDir/"post.ssz_snappy", SSZ, BeaconState))
check: check:
process_slots( process_slots(
hashedPreState[], hashedPreState.data.slot + num_slots, cache, rewards) fhPreState[], getStateField(fhPreState[], slot) + num_slots, cache,
rewards, {}, FAR_FUTURE_SLOT)
hashedPreState.root == postState[].hash_tree_root() getStateRoot(fhPreState[]) == postState[].hash_tree_root()
let newPreState = newClone(hashedPreState.data) let newPreState = newClone(fhPreState.hbsPhase0.data)
reportDiff(newPreState, postState) reportDiff(newPreState, postState)
`testImpl _ slots _ identifier`() `testImpl _ slots _ identifier`()

View File

@ -14,7 +14,8 @@
import import
stew/results, stew/results,
# Specs # Specs
../../beacon_chain/spec/[beaconstate, datatypes, helpers], ../../beacon_chain/spec/[
beaconstate, datatypes, forkedbeaconstate_helpers, helpers],
# Mock helpers # Mock helpers
../mocking/[mock_genesis, mock_attestations, mock_state], ../mocking/[mock_genesis, mock_attestations, mock_state],
../testutil ../testutil
@ -22,8 +23,10 @@ import
suite "[Unit - Spec - Block processing] Attestations " & preset(): suite "[Unit - Spec - Block processing] Attestations " & preset():
const NumValidators = uint64(8) * SLOTS_PER_EPOCH const NumValidators = uint64(8) * SLOTS_PER_EPOCH
let genesisState = newClone(initGenesisState(NumValidators)) let genesisState = (ref ForkedHashedBeaconState)(
doAssert genesisState.data.validators.lenu64 == NumValidators hbsPhase0: initGenesisState(NumValidators), beaconStateFork: forkPhase0)
doAssert getStateField(genesisState[], validators).lenu64 == NumValidators
template valid_attestation(name: string, body: untyped): untyped {.dirty.}= template valid_attestation(name: string, body: untyped): untyped {.dirty.}=
# Process a valid attestation # Process a valid attestation
@ -41,30 +44,34 @@ suite "[Unit - Spec - Block processing] Attestations " & preset():
# Params for sanity checks # Params for sanity checks
# ---------------------------------------- # ----------------------------------------
let let
current_epoch_count = state.data.current_epoch_attestations.len current_epoch_count =
previous_epoch_count = state.data.previous_epoch_attestations.len state.hbsPhase0.data.current_epoch_attestations.len
previous_epoch_count =
state.hbsPhase0.data.previous_epoch_attestations.len
# State transition # State transition
# ---------------------------------------- # ----------------------------------------
var cache = StateCache() var cache = StateCache()
check process_attestation( check process_attestation(
state.data, attestation, flags = {}, cache state.hbsPhase0.data, attestation, flags = {}, cache
).isOk ).isOk
# Check that the attestation was processed # Check that the attestation was processed
if attestation.data.target.epoch == get_current_epoch(state.data): if attestation.data.target.epoch == get_current_epoch(state[]):
check(state.data.current_epoch_attestations.len == current_epoch_count + 1) check(state.hbsPhase0.data.current_epoch_attestations.len ==
current_epoch_count + 1)
else: else:
check(state.data.previous_epoch_attestations.len == previous_epoch_count + 1) check(state.hbsPhase0.data.previous_epoch_attestations.len ==
previous_epoch_count + 1)
valid_attestation("Valid attestation"): valid_attestation("Valid attestation"):
let attestation = mockAttestation(state.data) let attestation = mockAttestation(state.hbsPhase0.data)
state.data.slot += MIN_ATTESTATION_INCLUSION_DELAY getStateField(state[], slot) += MIN_ATTESTATION_INCLUSION_DELAY
valid_attestation("Valid attestation from previous epoch"): valid_attestation("Valid attestation from previous epoch"):
nextSlot(state[]) nextSlot(state[])
let attestation = mockAttestation(state.data) let attestation = mockAttestation(state.hbsPhase0.data)
state.data.slot = Slot(SLOTS_PER_EPOCH - 1) getStateField(state[], slot) = Slot(SLOTS_PER_EPOCH - 1)
nextEpoch(state[]) nextEpoch(state[])
# TODO: regression BLS V0.10.1 # TODO: regression BLS V0.10.1

View File

@ -1,5 +1,5 @@
# beacon_chain # beacon_chain
# Copyright (c) 2018-2020 Status Research & Development GmbH # Copyright (c) 2018-2021 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -8,25 +8,27 @@
import import
# Specs # Specs
../../beacon_chain/spec/[ ../../beacon_chain/spec/[
datatypes, state_transition_epoch, state_transition] datatypes, forkedbeaconstate_helpers, state_transition,
state_transition_epoch]
proc processSlotsUntilEndCurrentEpoch(state: var HashedBeaconState) = proc processSlotsUntilEndCurrentEpoch(state: var ForkedHashedBeaconState) =
# Process all slots until the end of the last slot of the current epoch # Process all slots until the end of the last slot of the current epoch
var var
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
let slot = let slot =
state.data.slot + SLOTS_PER_EPOCH - (state.data.slot mod SLOTS_PER_EPOCH) getStateField(state, slot) + SLOTS_PER_EPOCH -
(getStateField(state, slot) mod SLOTS_PER_EPOCH)
# Transition to slot before the epoch state transition # Transition to slot before the epoch state transition
discard process_slots(state, slot - 1, cache, rewards) discard process_slots(state, slot - 1, cache, rewards, {}, FAR_FUTURE_SLOT)
# For the last slot of the epoch, # For the last slot of the epoch,
# only process_slot without process_epoch # only process_slot without process_epoch
# (see process_slots()) - state.root is invalid after here! # (see process_slots()) - state.root is invalid after here!
process_slot(state.data, state.root) process_slot(state.hbsPhase0.data, getStateRoot(state))
proc transitionEpochUntilJustificationFinalization*(state: var HashedBeaconState) = proc transitionEpochUntilJustificationFinalization*(state: var ForkedHashedBeaconState) =
# Process slots and do the epoch transition until crosslinks # Process slots and do the epoch transition until crosslinks
processSlotsUntilEndCurrentEpoch(state) processSlotsUntilEndCurrentEpoch(state)
@ -34,7 +36,7 @@ proc transitionEpochUntilJustificationFinalization*(state: var HashedBeaconState
cache = StateCache() cache = StateCache()
rewards = RewardInfo() rewards = RewardInfo()
rewards.init(state.data) rewards.init(state.hbsPhase0.data)
rewards.process_attestations(state.data, cache) rewards.process_attestations(state.hbsPhase0.data, cache)
process_justification_and_finalization( process_justification_and_finalization(
state.data, rewards.total_balances) state.hbsPhase0.data, rewards.total_balances)

View File

@ -1,5 +1,5 @@
# beacon_chain # beacon_chain
# Copyright (c) 2018-2020 Status Research & Development GmbH # Copyright (c) 2018-2021 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -12,9 +12,9 @@ import
# Vendored packages # Vendored packages
stew/bitops2, stew/bitops2,
# Specs # Specs
../../beacon_chain/spec/datatypes, ../../beacon_chain/spec/[datatypes, forkedbeaconstate_helpers],
# Test helpers # Test helpers
../mocking/[mock_genesis], ../mocking/mock_genesis,
./epoch_utils, ./epoch_utils,
./justification_finalization_helpers, ./justification_finalization_helpers,
../testutil ../testutil
@ -23,10 +23,11 @@ import
# (source) https://github.com/protolambda/eth2-docs#justification-and-finalization # (source) https://github.com/protolambda/eth2-docs#justification-and-finalization
# for a visualization of finalization rules # for a visualization of finalization rules
proc finalizeOn234(state: var HashedBeaconState, epoch: Epoch, sufficient_support: bool) = proc finalizeOn234(
state: var ForkedHashedBeaconState, epoch: Epoch, sufficient_support: bool) =
## Check finalization on rule 1 "234" ## Check finalization on rule 1 "234"
doAssert epoch > 4 doAssert epoch > 4
state.data.slot = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch getStateField(state, slot) = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch
# 43210 -- epochs ago # 43210 -- epochs ago
# 3210x -- justification bitfields indices # 3210x -- justification bitfields indices
@ -34,22 +35,22 @@ proc finalizeOn234(state: var HashedBeaconState, epoch: Epoch, sufficient_suppor
# checkpoints for epochs ago # checkpoints for epochs ago
let (c1, c2, c3, c4, _) = getCheckpoints(epoch) let (c1, c2, c3, c4, _) = getCheckpoints(epoch)
putCheckpointsInBlockRoots(state.data, [c1, c2, c3, c4]) putCheckpointsInBlockRoots(state.hbsPhase0.data, [c1, c2, c3, c4])
# Save for final checks # Save for final checks
let old_finalized = state.data.finalized_checkpoint let old_finalized = getStateField(state, finalized_checkpoint)
# Mock the state # Mock the state
state.data.previous_justified_checkpoint = c4 getStateField(state, previous_justified_checkpoint) = c4
state.data.current_justified_checkpoint = c3 getStateField(state, current_justified_checkpoint) = c3
state.data.justification_bits = 0'u8 # Bitvector of length 4 getStateField(state, justification_bits) = 0'u8 # Bitvector of length 4
# mock 3rd and 4th latest epochs as justified # mock 3rd and 4th latest epochs as justified
# indices are pre-shift # indices are pre-shift
state.data.justification_bits.setBit 1 getStateField(state, justification_bits).setBit 1
state.data.justification_bits.setBit 2 getStateField(state, justification_bits).setBit 2
# mock the 2nd latest epoch as justifiable, with 4th as the source # mock the 2nd latest epoch as justifiable, with 4th as the source
addMockAttestations( addMockAttestations(
state.data, state.hbsPhase0.data,
epoch = epoch - 2, epoch = epoch - 2,
source = c4, source = c4,
target = c2, target = c2,
@ -60,18 +61,18 @@ proc finalizeOn234(state: var HashedBeaconState, epoch: Epoch, sufficient_suppor
transitionEpochUntilJustificationFinalization(state) transitionEpochUntilJustificationFinalization(state)
# Checks # Checks
doAssert state.data.previous_justified_checkpoint == c3 # changed to old current doAssert getStateField(state, previous_justified_checkpoint) == c3 # changed to old current
if sufficient_support: if sufficient_support:
doAssert state.data.current_justified_checkpoint == c2 # changed to second latest doAssert getStateField(state, current_justified_checkpoint) == c2 # changed to second latest
doAssert state.data.finalized_checkpoint == c4 # finalized old previous justified epoch doAssert getStateField(state, finalized_checkpoint) == c4 # finalized old previous justified epoch
else: else:
doAssert state.data.current_justified_checkpoint == c3 # still old current doAssert getStateField(state, current_justified_checkpoint) == c3 # still old current
doAssert state.data.finalized_checkpoint == old_finalized # no new finalized checkpoint doAssert getStateField(state, finalized_checkpoint) == old_finalized # no new finalized checkpoint
proc finalizeOn23(state: var HashedBeaconState, epoch: Epoch, sufficient_support: bool) = proc finalizeOn23(state: var ForkedHashedBeaconState, epoch: Epoch, sufficient_support: bool) =
## Check finalization on rule 2 "23" ## Check finalization on rule 2 "23"
doAssert epoch > 3 doAssert epoch > 3
state.data.slot = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch getStateField(state, slot) = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch
# 43210 -- epochs ago # 43210 -- epochs ago
# 210xx -- justification bitfields indices preshift # 210xx -- justification bitfields indices preshift
@ -80,21 +81,21 @@ proc finalizeOn23(state: var HashedBeaconState, epoch: Epoch, sufficient_support
# checkpoints for epochs ago # checkpoints for epochs ago
let (c1, c2, c3, _, _) = getCheckpoints(epoch) let (c1, c2, c3, _, _) = getCheckpoints(epoch)
putCheckpointsInBlockRoots(state.data, [c1, c2, c3]) putCheckpointsInBlockRoots(state.hbsPhase0.data, [c1, c2, c3])
# Save for final checks # Save for final checks
let old_finalized = state.data.finalized_checkpoint let old_finalized = getStateField(state, finalized_checkpoint)
# Mock the state # Mock the state
state.data.previous_justified_checkpoint = c3 getStateField(state, previous_justified_checkpoint) = c3
state.data.current_justified_checkpoint = c3 getStateField(state, current_justified_checkpoint) = c3
state.data.justification_bits = 0'u8 # Bitvector of length 4 getStateField(state, justification_bits) = 0'u8 # Bitvector of length 4
# mock 3rd as justified # mock 3rd as justified
# indices are pre-shift # indices are pre-shift
state.data.justification_bits.setBit 1 getStateField(state, justification_bits).setBit 1
# mock the 2nd latest epoch as justifiable, with 3rd as the source # mock the 2nd latest epoch as justifiable, with 3rd as the source
addMockAttestations( addMockAttestations(
state.data, state.hbsPhase0.data,
epoch = epoch - 2, epoch = epoch - 2,
source = c3, source = c3,
target = c2, target = c2,
@ -105,18 +106,18 @@ proc finalizeOn23(state: var HashedBeaconState, epoch: Epoch, sufficient_support
transitionEpochUntilJustificationFinalization(state) transitionEpochUntilJustificationFinalization(state)
# Checks # Checks
doAssert state.data.previous_justified_checkpoint == c3 # changed to old current doAssert getStateField(state, previous_justified_checkpoint) == c3 # changed to old current
if sufficient_support: if sufficient_support:
doAssert state.data.current_justified_checkpoint == c2 # changed to second latest doAssert getStateField(state, current_justified_checkpoint) == c2 # changed to second latest
doAssert state.data.finalized_checkpoint == c3 # finalized old previous justified epoch doAssert getStateField(state, finalized_checkpoint) == c3 # finalized old previous justified epoch
else: else:
doAssert state.data.current_justified_checkpoint == c3 # still old current doAssert getStateField(state, current_justified_checkpoint) == c3 # still old current
doAssert state.data.finalized_checkpoint == old_finalized # no new finalized checkpoint doAssert getStateField(state, finalized_checkpoint) == old_finalized # no new finalized checkpoint
proc finalizeOn123(state: var HashedBeaconState, epoch: Epoch, sufficient_support: bool) = proc finalizeOn123(state: var ForkedHashedBeaconState, epoch: Epoch, sufficient_support: bool) =
## Check finalization on rule 3 "123" ## Check finalization on rule 3 "123"
doAssert epoch > 5 doAssert epoch > 5
state.data.slot = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch getStateField(state, slot) = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch
# 43210 -- epochs ago # 43210 -- epochs ago
# 210xx -- justification bitfields indices preshift # 210xx -- justification bitfields indices preshift
@ -125,21 +126,21 @@ proc finalizeOn123(state: var HashedBeaconState, epoch: Epoch, sufficient_suppor
# checkpoints for epochs ago # checkpoints for epochs ago
let (c1, c2, c3, c4, c5) = getCheckpoints(epoch) let (c1, c2, c3, c4, c5) = getCheckpoints(epoch)
putCheckpointsInBlockRoots(state.data, [c1, c2, c3, c4, c5]) putCheckpointsInBlockRoots(state.hbsPhase0.data, [c1, c2, c3, c4, c5])
# Save for final checks # Save for final checks
let old_finalized = state.data.finalized_checkpoint let old_finalized = getStateField(state, finalized_checkpoint)
# Mock the state # Mock the state
state.data.previous_justified_checkpoint = c5 getStateField(state, previous_justified_checkpoint) = c5
state.data.current_justified_checkpoint = c3 getStateField(state, current_justified_checkpoint) = c3
state.data.justification_bits = 0'u8 # Bitvector of length 4 getStateField(state, justification_bits) = 0'u8 # Bitvector of length 4
# mock 3rd as justified # mock 3rd as justified
# indices are pre-shift # indices are pre-shift
state.data.justification_bits.setBit 1 getStateField(state, justification_bits).setBit 1
# mock the 2nd latest epoch as justifiable, with 5th as the source # mock the 2nd latest epoch as justifiable, with 5th as the source
addMockAttestations( addMockAttestations(
state.data, state.hbsPhase0.data,
epoch = epoch - 2, epoch = epoch - 2,
source = c5, source = c5,
target = c2, target = c2,
@ -147,7 +148,7 @@ proc finalizeOn123(state: var HashedBeaconState, epoch: Epoch, sufficient_suppor
) )
# mock the 1st latest epoch as justifiable with 3rd as source # mock the 1st latest epoch as justifiable with 3rd as source
addMockAttestations( addMockAttestations(
state.data, state.hbsPhase0.data,
epoch = epoch - 1, epoch = epoch - 1,
source = c3, source = c3,
target = c1, target = c1,
@ -158,18 +159,18 @@ proc finalizeOn123(state: var HashedBeaconState, epoch: Epoch, sufficient_suppor
transitionEpochUntilJustificationFinalization(state) transitionEpochUntilJustificationFinalization(state)
# Checks # Checks
doAssert state.data.previous_justified_checkpoint == c3 # changed to old current doAssert getStateField(state, previous_justified_checkpoint) == c3 # changed to old current
if sufficient_support: if sufficient_support:
doAssert state.data.current_justified_checkpoint == c1 # changed to second latest doAssert getStateField(state, current_justified_checkpoint) == c1 # changed to second latest
doAssert state.data.finalized_checkpoint == c3 # finalized old previous justified epoch doAssert getStateField(state, finalized_checkpoint) == c3 # finalized old previous justified epoch
else: else:
doAssert state.data.current_justified_checkpoint == c3 # still old current doAssert getStateField(state, current_justified_checkpoint) == c3 # still old current
doAssert state.data.finalized_checkpoint == old_finalized # no new finalized checkpoint doAssert getStateField(state, finalized_checkpoint) == old_finalized # no new finalized checkpoint
proc finalizeOn12(state: var HashedBeaconState, epoch: Epoch, sufficient_support: bool) = proc finalizeOn12(state: var ForkedHashedBeaconState, epoch: Epoch, sufficient_support: bool) =
## Check finalization on rule 4 "12" ## Check finalization on rule 4 "12"
doAssert epoch > 2 doAssert epoch > 2
state.data.slot = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch getStateField(state, slot) = Slot((epoch * SLOTS_PER_EPOCH) - 1) # Skip ahead to just before epoch
# 43210 -- epochs ago # 43210 -- epochs ago
# 210xx -- justification bitfields indices preshift # 210xx -- justification bitfields indices preshift
@ -178,21 +179,21 @@ proc finalizeOn12(state: var HashedBeaconState, epoch: Epoch, sufficient_support
# checkpoints for epochs ago # checkpoints for epochs ago
let (c1, c2, _, _, _) = getCheckpoints(epoch) let (c1, c2, _, _, _) = getCheckpoints(epoch)
putCheckpointsInBlockRoots(state.data, [c1, c2]) putCheckpointsInBlockRoots(state.hbsPhase0.data, [c1, c2])
# Save for final checks # Save for final checks
let old_finalized = state.data.finalized_checkpoint let old_finalized = getStateField(state, finalized_checkpoint)
# Mock the state # Mock the state
state.data.previous_justified_checkpoint = c2 getStateField(state, previous_justified_checkpoint) = c2
state.data.current_justified_checkpoint = c2 getStateField(state, current_justified_checkpoint) = c2
state.data.justification_bits = 0'u8 # Bitvector of length 4 getStateField(state, justification_bits) = 0'u8 # Bitvector of length 4
# mock 3rd as justified # mock 3rd as justified
# indices are pre-shift # indices are pre-shift
state.data.justification_bits.setBit 0 getStateField(state, justification_bits).setBit 0
# mock the 2nd latest epoch as justifiable, with 3rd as the source # mock the 2nd latest epoch as justifiable, with 3rd as the source
addMockAttestations( addMockAttestations(
state.data, state.hbsPhase0.data,
epoch = epoch - 1, epoch = epoch - 1,
source = c2, source = c2,
target = c1, target = c1,
@ -203,21 +204,22 @@ proc finalizeOn12(state: var HashedBeaconState, epoch: Epoch, sufficient_support
transitionEpochUntilJustificationFinalization(state) transitionEpochUntilJustificationFinalization(state)
# Checks # Checks
doAssert state.data.previous_justified_checkpoint == c2 # changed to old current doAssert getStateField(state, previous_justified_checkpoint) == c2 # changed to old current
if sufficient_support: if sufficient_support:
doAssert state.data.current_justified_checkpoint == c1 # changed to second latest doAssert getStateField(state, current_justified_checkpoint) == c1 # changed to second latest
doAssert state.data.finalized_checkpoint == c2 # finalized old previous justified epoch doAssert getStateField(state, finalized_checkpoint) == c2 # finalized old previous justified epoch
else: else:
doAssert state.data.current_justified_checkpoint == c2 # still old current doAssert getStateField(state, current_justified_checkpoint) == c2 # still old current
doAssert state.data.finalized_checkpoint == old_finalized # no new finalized checkpoint doAssert getStateField(state, finalized_checkpoint) == old_finalized # no new finalized checkpoint
proc payload = proc payload =
suite "[Unit - Spec - Epoch processing] Justification and Finalization " & preset(): suite "[Unit - Spec - Epoch processing] Justification and Finalization " & preset():
echo " Finalization rules are detailed at https://github.com/protolambda/eth2-docs#justification-and-finalization" echo " Finalization rules are detailed at https://github.com/protolambda/eth2-docs#justification-and-finalization"
const NumValidators = uint64(8) * SLOTS_PER_EPOCH const NumValidators = uint64(8) * SLOTS_PER_EPOCH
let genesisState = newClone(initGenesisState(NumValidators)) let genesisState = (ref ForkedHashedBeaconState)(
doAssert genesisState.data.validators.lenu64 == NumValidators hbsPhase0: initGenesisState(NumValidators), beaconStateFork: forkPhase0)
doAssert getStateField(genesisState[], validators).lenu64 == NumValidators
setup: setup:
var state = assignClone(genesisState[]) var state = assignClone(genesisState[])

View File

@ -19,11 +19,10 @@ import
../beacon_chain/gossip_processing/[gossip_validation], ../beacon_chain/gossip_processing/[gossip_validation],
../beacon_chain/fork_choice/[fork_choice_types, fork_choice], ../beacon_chain/fork_choice/[fork_choice_types, fork_choice],
../beacon_chain/consensus_object_pools/[ ../beacon_chain/consensus_object_pools/[
block_quarantine, blockchain_dag, block_clearance, attestation_pool, block_quarantine, blockchain_dag, block_clearance, attestation_pool],
statedata_helpers],
../beacon_chain/ssz/merkleization, ../beacon_chain/ssz/merkleization,
../beacon_chain/spec/[crypto, datatypes, digest, state_transition, helpers, ../beacon_chain/spec/[crypto, datatypes, digest, forkedbeaconstate_helpers,
presets], state_transition, helpers, presets],
# Test utilities # Test utilities
./testutil, ./testdbutil, ./testblockutil ./testutil, ./testdbutil, ./testblockutil
@ -69,14 +68,16 @@ suite "Attestation pool processing" & preset():
rewards: RewardInfo rewards: RewardInfo
# Slot 0 is a finalized slot - won't be making attestations for it.. # Slot 0 is a finalized slot - won't be making attestations for it..
check: check:
process_slots(state.data, getStateField(state, slot) + 1, cache, rewards) process_slots(
state.data, getStateField(state.data, slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
test "Can add and retrieve simple attestations" & preset(): test "Can add and retrieve simple attestations" & preset():
let let
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation = makeAttestation(state[], state.blck.root, bc0[0], cache) attestation = makeAttestation(state[].data, state.blck.root, bc0[0], cache)
pool[].addAttestation( pool[].addAttestation(
attestation, @[bc0[0]], attestation.loadSig, attestation, @[bc0[0]], attestation.loadSig,
@ -100,10 +101,10 @@ suite "Attestation pool processing" & preset():
process_slots( process_slots(
state.data, state.data,
getStateField(state, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache, getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
rewards) rewards, {}, FAR_FUTURE_SLOT)
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len == 1 attestations.len == 1
@ -114,33 +115,33 @@ suite "Attestation pool processing" & preset():
state.data, state.blck.root, state.data, state.blck.root,
cache, attestations = attestations, nextSlot = false).root cache, attestations = attestations, nextSlot = false).root
bc1 = get_beacon_committee( bc1 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
att1 = makeAttestation(state[], root1, bc1[0], cache) att1 = makeAttestation(state[].data, root1, bc1[0], cache)
check: check:
process_slots( process_slots(
state.data, state.data,
getStateField(state, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache, getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
rewards) rewards, {}, FAR_FUTURE_SLOT)
check: check:
# shouldn't include already-included attestations # shouldn't include already-included attestations
pool[].getAttestationsForBlock(state[], cache) == [] pool[].getAttestationsForTestBlock(state[], cache) == []
pool[].addAttestation( pool[].addAttestation(
att1, @[bc1[0]], att1.loadSig, att1.data.slot) att1, @[bc1[0]], att1.loadSig, att1.data.slot)
check: check:
# but new ones should go in # but new ones should go in
pool[].getAttestationsForBlock(state[], cache).len() == 1 pool[].getAttestationsForTestBlock(state[], cache).len() == 1
let let
att2 = makeAttestation(state[], root1, bc1[1], cache) att2 = makeAttestation(state[].data, root1, bc1[1], cache)
pool[].addAttestation( pool[].addAttestation(
att2, @[bc1[1]], att2.loadSig, att2.data.slot) att2, @[bc1[1]], att2.loadSig, att2.data.slot)
let let
combined = pool[].getAttestationsForBlock(state[], cache) combined = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
# New attestations should be combined with old attestations # New attestations should be combined with old attestations
@ -152,18 +153,18 @@ suite "Attestation pool processing" & preset():
check: check:
# readding the combined attestation shouldn't have an effect # readding the combined attestation shouldn't have an effect
pool[].getAttestationsForBlock(state[], cache).len() == 1 pool[].getAttestationsForTestBlock(state[], cache).len() == 1
let let
# Someone votes for a different root # Someone votes for a different root
att3 = makeAttestation(state[], Eth2Digest(), bc1[2], cache) att3 = makeAttestation(state[].data, Eth2Digest(), bc1[2], cache)
pool[].addAttestation( pool[].addAttestation(
att3, @[bc1[2]], att3.loadSig, att3.data.slot) att3, @[bc1[2]], att3.loadSig, att3.data.slot)
check: check:
# We should now get both attestations for the block, but the aggregate # We should now get both attestations for the block, but the aggregate
# should be the one with the most votes # should be the one with the most votes
pool[].getAttestationsForBlock(state[], cache).len() == 2 pool[].getAttestationsForTestBlock(state[], cache).len() == 2
pool[].getAggregatedAttestation(2.Slot, 0.CommitteeIndex). pool[].getAggregatedAttestation(2.Slot, 0.CommitteeIndex).
get().aggregation_bits.countOnes() == 2 get().aggregation_bits.countOnes() == 2
pool[].getAggregatedAttestation(2.Slot, hash_tree_root(att2.data)). pool[].getAggregatedAttestation(2.Slot, hash_tree_root(att2.data)).
@ -171,7 +172,7 @@ suite "Attestation pool processing" & preset():
let let
# Someone votes for a different root # Someone votes for a different root
att4 = makeAttestation(state[], Eth2Digest(), bc1[2], cache) att4 = makeAttestation(state[].data, Eth2Digest(), bc1[2], cache)
pool[].addAttestation( pool[].addAttestation(
att4, @[bc1[2]], att3.loadSig, att3.data.slot) att4, @[bc1[2]], att3.loadSig, att3.data.slot)
@ -179,14 +180,14 @@ suite "Attestation pool processing" & preset():
let let
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
var var
att0 = makeAttestation(state[], state.blck.root, bc0[0], cache) att0 = makeAttestation(state[].data, state.blck.root, bc0[0], cache)
att0x = att0 att0x = att0
att1 = makeAttestation(state[], state.blck.root, bc0[1], cache) att1 = makeAttestation(state[].data, state.blck.root, bc0[1], cache)
att2 = makeAttestation(state[], state.blck.root, bc0[2], cache) att2 = makeAttestation(state[].data, state.blck.root, bc0[2], cache)
att3 = makeAttestation(state[], state.blck.root, bc0[3], cache) att3 = makeAttestation(state[].data, state.blck.root, bc0[3], cache)
# Both attestations include member 2 but neither is a subset of the other # Both attestations include member 2 but neither is a subset of the other
att0.combine(att2) att0.combine(att2)
@ -198,11 +199,11 @@ suite "Attestation pool processing" & preset():
check: check:
process_slots( process_slots(
state.data, state.data,
getStateField(state, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache, getStateField(state.data, slot) + MIN_ATTESTATION_INCLUSION_DELAY, cache,
rewards) rewards, {}, FAR_FUTURE_SLOT)
check: check:
pool[].getAttestationsForBlock(state[], cache).len() == 2 pool[].getAttestationsForTestBlock(state[], cache).len() == 2
# Can get either aggregate here, random! # Can get either aggregate here, random!
pool[].getAggregatedAttestation(1.Slot, 0.CommitteeIndex).isSome() pool[].getAggregatedAttestation(1.Slot, 0.CommitteeIndex).isSome()
@ -210,7 +211,7 @@ suite "Attestation pool processing" & preset():
pool[].addAttestation(att3, @[bc0[3]], att3.loadSig, att3.data.slot) pool[].addAttestation(att3, @[bc0[3]], att3.loadSig, att3.data.slot)
block: block:
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len() == 2 attestations.len() == 2
attestations[0].aggregation_bits.countOnes() == 3 attestations[0].aggregation_bits.countOnes() == 3
@ -222,7 +223,7 @@ suite "Attestation pool processing" & preset():
pool[].addAttestation(att0x, @[bc0[0]], att0x.loadSig, att0x.data.slot) pool[].addAttestation(att0x, @[bc0[0]], att0x.loadSig, att0x.data.slot)
block: block:
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len() == 1 attestations.len() == 1
attestations[0].aggregation_bits.countOnes() == 4 attestations[0].aggregation_bits.countOnes() == 4
@ -235,42 +236,44 @@ suite "Attestation pool processing" & preset():
root.data[0..<8] = toBytesBE(i.uint64) root.data[0..<8] = toBytesBE(i.uint64)
let let
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
for j in 0..<bc0.len(): for j in 0..<bc0.len():
root.data[8..<16] = toBytesBE(j.uint64) root.data[8..<16] = toBytesBE(j.uint64)
var att = makeAttestation(state[], root, bc0[j], cache) var att = makeAttestation(state[].data, root, bc0[j], cache)
pool[].addAttestation(att, @[bc0[j]], att.loadSig, att.data.slot) pool[].addAttestation(att, @[bc0[j]], att.loadSig, att.data.slot)
inc attestations inc attestations
check: check:
process_slots(state.data, getStateField(state, slot) + 1, cache, process_slots(state.data, getStateField(state.data, slot) + 1, cache,
rewards) rewards, {}, FAR_FUTURE_SLOT)
doAssert attestations.uint64 > MAX_ATTESTATIONS, doAssert attestations.uint64 > MAX_ATTESTATIONS,
"6*SLOTS_PER_EPOCH validators > 128 mainnet MAX_ATTESTATIONS" "6*SLOTS_PER_EPOCH validators > 128 mainnet MAX_ATTESTATIONS"
check: check:
# Fill block with attestations # Fill block with attestations
pool[].getAttestationsForBlock(state[], cache).lenu64() == pool[].getAttestationsForTestBlock(state[], cache).lenu64() ==
MAX_ATTESTATIONS MAX_ATTESTATIONS
pool[].getAggregatedAttestation( pool[].getAggregatedAttestation(
getStateField(state, slot) - 1, 0.CommitteeIndex).isSome() getStateField(state.data, slot) - 1, 0.CommitteeIndex).isSome()
test "Attestations may arrive in any order" & preset(): test "Attestations may arrive in any order" & preset():
var cache = StateCache() var cache = StateCache()
let let
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation0 = makeAttestation(state[], state.blck.root, bc0[0], cache) attestation0 = makeAttestation(state[].data, state.blck.root, bc0[0], cache)
check: check:
process_slots(state.data, getStateField(state, slot) + 1, cache, rewards) process_slots(
state.data, getStateField(state.data, slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
let let
bc1 = get_beacon_committee(state[], bc1 = get_beacon_committee(state[].data,
getStateField(state, slot), 0.CommitteeIndex, cache) getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation1 = makeAttestation(state[], state.blck.root, bc1[0], cache) attestation1 = makeAttestation(state[].data, state.blck.root, bc1[0], cache)
# test reverse order # test reverse order
pool[].addAttestation( pool[].addAttestation(
@ -279,9 +282,10 @@ suite "Attestation pool processing" & preset():
attestation0, @[bc0[0]], attestation0.loadSig, attestation0.data.slot) attestation0, @[bc0[0]], attestation0.loadSig, attestation0.data.slot)
discard process_slots( discard process_slots(
state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards) state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len == 1 attestations.len == 1
@ -291,9 +295,11 @@ suite "Attestation pool processing" & preset():
let let
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation0 = makeAttestation(state[], state.blck.root, bc0[0], cache) attestation0 =
attestation1 = makeAttestation(state[], state.blck.root, bc0[1], cache) makeAttestation(state[].data, state.blck.root, bc0[0], cache)
attestation1 =
makeAttestation(state[].data, state.blck.root, bc0[1], cache)
pool[].addAttestation( pool[].addAttestation(
attestation0, @[bc0[0]], attestation0.loadSig, attestation0.data.slot) attestation0, @[bc0[0]], attestation0.loadSig, attestation0.data.slot)
@ -302,9 +308,10 @@ suite "Attestation pool processing" & preset():
check: check:
process_slots( process_slots(
state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards) state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len == 1 attestations.len == 1
@ -315,9 +322,11 @@ suite "Attestation pool processing" & preset():
var var
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee( bc0 = get_beacon_committee(
state[], getStateField(state, slot), 0.CommitteeIndex, cache) state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation0 = makeAttestation(state[], state.blck.root, bc0[0], cache) attestation0 =
attestation1 = makeAttestation(state[], state.blck.root, bc0[1], cache) makeAttestation(state[].data, state.blck.root, bc0[0], cache)
attestation1 =
makeAttestation(state[].data, state.blck.root, bc0[1], cache)
attestation0.combine(attestation1) attestation0.combine(attestation1)
@ -328,9 +337,10 @@ suite "Attestation pool processing" & preset():
check: check:
process_slots( process_slots(
state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards) state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len == 1 attestations.len == 1
@ -339,10 +349,12 @@ suite "Attestation pool processing" & preset():
var cache = StateCache() var cache = StateCache()
var var
# Create an attestation for slot 1! # Create an attestation for slot 1!
bc0 = get_beacon_committee(state[], bc0 = get_beacon_committee(state[].data,
getStateField(state, slot), 0.CommitteeIndex, cache) getStateField(state.data, slot), 0.CommitteeIndex, cache)
attestation0 = makeAttestation(state[], state.blck.root, bc0[0], cache) attestation0 =
attestation1 = makeAttestation(state[], state.blck.root, bc0[1], cache) makeAttestation(state[].data, state.blck.root, bc0[0], cache)
attestation1 =
makeAttestation(state[].data, state.blck.root, bc0[1], cache)
attestation0.combine(attestation1) attestation0.combine(attestation1)
@ -353,9 +365,10 @@ suite "Attestation pool processing" & preset():
check: check:
process_slots( process_slots(
state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards) state.data, MIN_ATTESTATION_INCLUSION_DELAY.Slot + 1, cache, rewards,
{}, FAR_FUTURE_SLOT)
let attestations = pool[].getAttestationsForBlock(state[], cache) let attestations = pool[].getAttestationsForTestBlock(state[], cache)
check: check:
attestations.len == 1 attestations.len == 1
@ -414,8 +427,9 @@ suite "Attestation pool processing" & preset():
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot) pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
bc1 = get_beacon_committee( bc1 = get_beacon_committee(
state[], getStateField(state, slot) - 1, 1.CommitteeIndex, cache) state[].data, getStateField(state.data, slot) - 1, 1.CommitteeIndex,
attestation0 = makeAttestation(state[], b10.root, bc1[0], cache) cache)
attestation0 = makeAttestation(state[].data, b10.root, bc1[0], cache)
pool[].addAttestation( pool[].addAttestation(
attestation0, @[bc1[0]], attestation0.loadSig, attestation0.data.slot) attestation0, @[bc1[0]], attestation0.loadSig, attestation0.data.slot)
@ -427,8 +441,8 @@ suite "Attestation pool processing" & preset():
head2 == b10Add[] head2 == b10Add[]
let let
attestation1 = makeAttestation(state[], b11.root, bc1[1], cache) attestation1 = makeAttestation(state[].data, b11.root, bc1[1], cache)
attestation2 = makeAttestation(state[], b11.root, bc1[2], cache) attestation2 = makeAttestation(state[].data, b11.root, bc1[2], cache)
pool[].addAttestation( pool[].addAttestation(
attestation1, @[bc1[1]], attestation1.loadSig, attestation1.data.slot) attestation1, @[bc1[1]], attestation1.loadSig, attestation1.data.slot)
@ -503,7 +517,7 @@ suite "Attestation pool processing" & preset():
for epoch in 0 ..< 5: for epoch in 0 ..< 5:
let start_slot = compute_start_slot_at_epoch(Epoch epoch) let start_slot = compute_start_slot_at_epoch(Epoch epoch)
let committees_per_slot = let committees_per_slot =
get_committee_count_per_slot(state[], Epoch epoch, cache) get_committee_count_per_slot(state[].data, Epoch epoch, cache)
for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH: for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH:
let new_block = addTestBlock( let new_block = addTestBlock(
state.data, block_root, cache, attestations = attestations) state.data, block_root, cache, attestations = attestations)
@ -523,7 +537,7 @@ suite "Attestation pool processing" & preset():
attestations.setlen(0) attestations.setlen(0)
for index in 0'u64 ..< committees_per_slot: for index in 0'u64 ..< committees_per_slot:
let committee = get_beacon_committee( let committee = get_beacon_committee(
state[], getStateField(state, slot), index.CommitteeIndex, state[].data, getStateField(state.data, slot), index.CommitteeIndex,
cache) cache)
# Create a bitfield filled with the given count per attestation, # Create a bitfield filled with the given count per attestation,
@ -535,7 +549,7 @@ suite "Attestation pool processing" & preset():
attestations.add Attestation( attestations.add Attestation(
aggregation_bits: aggregation_bits, aggregation_bits: aggregation_bits,
data: makeAttestationData( data: makeAttestationData(
state[], getStateField(state, slot), state[].data, getStateField(state.data, slot),
index.CommitteeIndex, blockroot) index.CommitteeIndex, blockroot)
# signature: ValidatorSig() # signature: ValidatorSig()
) )

View File

@ -12,7 +12,8 @@ import
unittest2, unittest2,
../beacon_chain/[beacon_chain_db, extras, interop, ssz], ../beacon_chain/[beacon_chain_db, extras, interop, ssz],
../beacon_chain/spec/[ ../beacon_chain/spec/[
beaconstate, datatypes, digest, crypto, state_transition, presets], beaconstate, crypto, datatypes, digest, forkedbeaconstate_helpers, presets,
state_transition],
../beacon_chain/consensus_object_pools/blockchain_dag, ../beacon_chain/consensus_object_pools/blockchain_dag,
eth/db/kvstore, eth/db/kvstore,
# test utilies # test utilies
@ -73,12 +74,12 @@ suite "Beacon chain DB" & preset():
testStates = getTestStates(dag.headState.data) testStates = getTestStates(dag.headState.data)
# Ensure transitions beyond just adding validators and increasing slots # Ensure transitions beyond just adding validators and increasing slots
sort(testStates) do (x, y: ref HashedBeaconState) -> int: sort(testStates) do (x, y: ref ForkedHashedBeaconState) -> int:
cmp($x.root, $y.root) cmp($getStateRoot(x[]), $getStateRoot(y[]))
for state in testStates: for state in testStates:
db.putState(state[].data) db.putState(state[].hbsPhase0.data)
let root = hash_tree_root(state[].data) let root = hash_tree_root(state[])
check: check:
db.containsState(root) db.containsState(root)
@ -98,12 +99,12 @@ suite "Beacon chain DB" & preset():
var testStates = getTestStates(dag.headState.data) var testStates = getTestStates(dag.headState.data)
# Ensure transitions beyond just adding validators and increasing slots # Ensure transitions beyond just adding validators and increasing slots
sort(testStates) do (x, y: ref HashedBeaconState) -> int: sort(testStates) do (x, y: ref ForkedHashedBeaconState) -> int:
cmp($x.root, $y.root) cmp($getStateRoot(x[]), $getStateRoot(y[]))
for state in testStates: for state in testStates:
db.putState(state[].data) db.putState(state[].hbsPhase0.data)
let root = hash_tree_root(state[].data) let root = hash_tree_root(state[])
check: check:
db.getState(root, stateBuffer[], noRollback) db.getState(root, stateBuffer[], noRollback)

View File

@ -1,5 +1,5 @@
# beacon_chain # beacon_chain
# Copyright (c) 2018-2020 Status Research & Development GmbH # Copyright (c) 2018-2021 Status Research & Development GmbH
# Licensed and distributed under either of # Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
@ -12,11 +12,13 @@ import
unittest2, unittest2,
stew/assign2, stew/assign2,
eth/keys, eth/keys,
../beacon_chain/spec/[datatypes, digest, helpers, state_transition, presets], ../beacon_chain/spec/[
datatypes, digest, forkedbeaconstate_helpers, helpers, state_transition,
presets],
../beacon_chain/beacon_node_types, ../beacon_chain/beacon_node_types,
../beacon_chain/[beacon_chain_db, ssz], ../beacon_chain/[beacon_chain_db, ssz],
../beacon_chain/consensus_object_pools/[ ../beacon_chain/consensus_object_pools/[
blockchain_dag, block_quarantine, block_clearance, statedata_helpers], blockchain_dag, block_quarantine, block_clearance],
./testutil, ./testdbutil, ./testblockutil ./testutil, ./testdbutil, ./testblockutil
when isMainModule: when isMainModule:
@ -155,7 +157,7 @@ suite "Block pool processing" & preset():
b2Add = dag.addRawBlock(quarantine, b2, nil) b2Add = dag.addRawBlock(quarantine, b2, nil)
b2Get = dag.get(b2.root) b2Get = dag.get(b2.root)
er = dag.findEpochRef(b1Add[], b1Add[].slot.epoch) er = dag.findEpochRef(b1Add[], b1Add[].slot.epoch)
validators = getStateField(dag.headState, validators).lenu64() validators = getStateField(dag.headState.data, validators).lenu64()
check: check:
b2Get.isSome() b2Get.isSome()
@ -175,7 +177,9 @@ suite "Block pool processing" & preset():
# Skip one slot to get a gap # Skip one slot to get a gap
check: check:
process_slots(state[], state.data.slot + 1, cache, rewards) process_slots(
state[], getStateField(state[], slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
let let
b4 = addTestBlock(state[], b2.root, cache) b4 = addTestBlock(state[], b2.root, cache)
@ -263,7 +267,7 @@ suite "Block pool processing" & preset():
check: check:
# ensure we loaded the correct head state # ensure we loaded the correct head state
dag2.head.root == b2.root dag2.head.root == b2.root
hash_tree_root(dag2.headState) == b2.message.state_root hash_tree_root(dag2.headState.data) == b2.message.state_root
dag2.get(b1.root).isSome() dag2.get(b1.root).isSome()
dag2.get(b2.root).isSome() dag2.get(b2.root).isSome()
dag2.heads.len == 1 dag2.heads.len == 1
@ -287,7 +291,7 @@ suite "Block pool processing" & preset():
check: check:
dag.head == b1Add[] dag.head == b1Add[]
getStateField(dag.headState, slot) == b1Add[].slot getStateField(dag.headState.data, slot) == b1Add[].slot
test "updateStateData sanity" & preset(): test "updateStateData sanity" & preset():
let let
@ -305,38 +309,38 @@ suite "Block pool processing" & preset():
check: check:
tmpState.blck == b1Add[] tmpState.blck == b1Add[]
getStateField(tmpState, slot) == bs1.slot getStateField(tmpState.data, slot) == bs1.slot
# Skip slots # Skip slots
dag.updateStateData(tmpState[], bs1_3, false, cache) # skip slots dag.updateStateData(tmpState[], bs1_3, false, cache) # skip slots
check: check:
tmpState.blck == b1Add[] tmpState.blck == b1Add[]
getStateField(tmpState, slot) == bs1_3.slot getStateField(tmpState.data, slot) == bs1_3.slot
# Move back slots, but not blocks # Move back slots, but not blocks
dag.updateStateData(tmpState[], bs1_3.parent(), false, cache) dag.updateStateData(tmpState[], bs1_3.parent(), false, cache)
check: check:
tmpState.blck == b1Add[] tmpState.blck == b1Add[]
getStateField(tmpState, slot) == bs1_3.parent().slot getStateField(tmpState.data, slot) == bs1_3.parent().slot
# Move to different block and slot # Move to different block and slot
dag.updateStateData(tmpState[], bs2_3, false, cache) dag.updateStateData(tmpState[], bs2_3, false, cache)
check: check:
tmpState.blck == b2Add[] tmpState.blck == b2Add[]
getStateField(tmpState, slot) == bs2_3.slot getStateField(tmpState.data, slot) == bs2_3.slot
# Move back slot and block # Move back slot and block
dag.updateStateData(tmpState[], bs1, false, cache) dag.updateStateData(tmpState[], bs1, false, cache)
check: check:
tmpState.blck == b1Add[] tmpState.blck == b1Add[]
getStateField(tmpState, slot) == bs1.slot getStateField(tmpState.data, slot) == bs1.slot
# Move back to genesis # Move back to genesis
dag.updateStateData(tmpState[], bs1.parent(), false, cache) dag.updateStateData(tmpState[], bs1.parent(), false, cache)
check: check:
tmpState.blck == b1Add[].parent tmpState.blck == b1Add[].parent
getStateField(tmpState, slot) == bs1.parent.slot getStateField(tmpState.data, slot) == bs1.parent.slot
suite "chain DAG finalization tests" & preset(): suite "chain DAG finalization tests" & preset():
setup: setup:
@ -354,8 +358,8 @@ suite "chain DAG finalization tests" & preset():
tmpState = assignClone(dag.headState.data) tmpState = assignClone(dag.headState.data)
check: check:
process_slots( process_slots(
tmpState[], tmpState.data.slot + (5 * SLOTS_PER_EPOCH).uint64, tmpState[], getStateField(tmpState[], slot) + (5 * SLOTS_PER_EPOCH).uint64,
cache, rewards) cache, rewards, {}, FAR_FUTURE_SLOT)
let lateBlock = addTestBlock(tmpState[], dag.head.root, cache) let lateBlock = addTestBlock(tmpState[], dag.head.root, cache)
block: block:
@ -373,7 +377,7 @@ suite "chain DAG finalization tests" & preset():
blck = addTestBlock( blck = addTestBlock(
tmpState[], dag.head.root, cache, tmpState[], dag.head.root, cache,
attestations = makeFullAttestations( attestations = makeFullAttestations(
tmpState[], dag.head.root, tmpState.data.slot, cache, {})) tmpState[], dag.head.root, getStateField(tmpState[], slot), cache, {}))
let added = dag.addRawBlock(quarantine, blck, nil) let added = dag.addRawBlock(quarantine, blck, nil)
check: added.isOk() check: added.isOk()
dag.updateHead(added[], quarantine) dag.updateHead(added[], quarantine)
@ -383,7 +387,7 @@ suite "chain DAG finalization tests" & preset():
dag.heads.len() == 1 dag.heads.len() == 1
check: check:
dag.db.immutableValidators.len() == getStateField(dag.headState, validators).len() dag.db.immutableValidators.len() == getStateField(dag.headState.data, validators).len()
let let
finalER = dag.findEpochRef(dag.finalizedHead.blck, dag.finalizedHead.slot.epoch) finalER = dag.findEpochRef(dag.finalizedHead.blck, dag.finalizedHead.slot.epoch)
@ -436,16 +440,15 @@ suite "chain DAG finalization tests" & preset():
dag2.head.root == dag.head.root dag2.head.root == dag.head.root
dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root
dag2.finalizedHead.slot == dag.finalizedHead.slot dag2.finalizedHead.slot == dag.finalizedHead.slot
hash_tree_root(dag2.headState) == hash_tree_root(dag.headState) hash_tree_root(dag2.headState.data) == hash_tree_root(dag.headState.data)
test "orphaned epoch block" & preset(): test "orphaned epoch block" & preset():
var prestate = (ref HashedBeaconState)() var prestate = (ref ForkedHashedBeaconState)(beaconStateFork: forkPhase0)
for i in 0 ..< SLOTS_PER_EPOCH: for i in 0 ..< SLOTS_PER_EPOCH:
if i == SLOTS_PER_EPOCH - 1: if i == SLOTS_PER_EPOCH - 1:
assign(prestate[], dag.headState.data) assign(prestate[], dag.headState.data)
let blck = makeTestBlock( let blck = makeTestBlock(dag.headState.data, dag.head.root, cache)
dag.headState.data, dag.head.root, cache)
let added = dag.addRawBlock(quarantine, blck, nil) let added = dag.addRawBlock(quarantine, blck, nil)
check: added.isOk() check: added.isOk()
dag.updateHead(added[], quarantine) dag.updateHead(added[], quarantine)
@ -457,11 +460,12 @@ suite "chain DAG finalization tests" & preset():
# The loop creates multiple branches, which StateCache isn't suitable for # The loop creates multiple branches, which StateCache isn't suitable for
cache = StateCache() cache = StateCache()
doAssert process_slots(prestate[], prestate[].data.slot + 1, cache, rewards) doAssert process_slots(
prestate[], getStateField(prestate[], slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
# create another block, orphaning the head # create another block, orphaning the head
let blck = makeTestBlock( let blck = makeTestBlock(prestate[], dag.head.parent.root, cache)
prestate[], dag.head.parent.root, cache)
# Add block, but don't update head # Add block, but don't update head
let added = dag.addRawBlock(quarantine, blck, nil) let added = dag.addRawBlock(quarantine, blck, nil)
@ -486,12 +490,13 @@ suite "chain DAG finalization tests" & preset():
# Advance past epoch so that the epoch transition is gapped # Advance past epoch so that the epoch transition is gapped
check: check:
process_slots( process_slots(
dag.headState.data, Slot(SLOTS_PER_EPOCH * 6 + 2), cache, rewards) dag.headState.data, Slot(SLOTS_PER_EPOCH * 6 + 2), cache, rewards, {},
FAR_FUTURE_SLOT)
var blck = makeTestBlock( var blck = makeTestBlock(
dag.headState.data, dag.head.root, cache, dag.headState.data, dag.head.root, cache,
attestations = makeFullAttestations( attestations = makeFullAttestations(
dag.headState, dag.head.root, getStateField(dag.headState, slot), dag.headState.data, dag.head.root, getStateField(dag.headState.data, slot),
cache, {})) cache, {}))
let added = dag.addRawBlock(quarantine, blck, nil) let added = dag.addRawBlock(quarantine, blck, nil)
@ -508,9 +513,8 @@ suite "chain DAG finalization tests" & preset():
assign(tmpStateData[], dag.headState) assign(tmpStateData[], dag.headState)
dag.updateStateData(tmpStateData[], cur.atSlot(cur.slot), false, cache) dag.updateStateData(tmpStateData[], cur.atSlot(cur.slot), false, cache)
check: check:
dag.get(cur).data.message.state_root == dag.get(cur).data.message.state_root == getStateRoot(tmpStateData[].data)
tmpStateData[].data.root getStateRoot(tmpStateData[].data) == hash_tree_root(tmpStateData[].data)
tmpStateData[].data.root == hash_tree_root(tmpSTateData[])
cur = cur.parent cur = cur.parent
let let
@ -522,4 +526,4 @@ suite "chain DAG finalization tests" & preset():
dag2.head.root == dag.head.root dag2.head.root == dag.head.root
dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root
dag2.finalizedHead.slot == dag.finalizedHead.slot dag2.finalizedHead.slot == dag.finalizedHead.slot
hash_tree_root(dag2.headState) == hash_tree_root(dag.headState) hash_tree_root(dag2.headState.data) == hash_tree_root(dag.headState.data)

View File

@ -17,11 +17,10 @@ import
../beacon_chain/gossip_processing/[gossip_validation, batch_validation], ../beacon_chain/gossip_processing/[gossip_validation, batch_validation],
../beacon_chain/fork_choice/[fork_choice_types, fork_choice], ../beacon_chain/fork_choice/[fork_choice_types, fork_choice],
../beacon_chain/consensus_object_pools/[ ../beacon_chain/consensus_object_pools/[
block_quarantine, blockchain_dag, block_clearance, attestation_pool, block_quarantine, blockchain_dag, block_clearance, attestation_pool],
statedata_helpers],
../beacon_chain/ssz/merkleization, ../beacon_chain/ssz/merkleization,
../beacon_chain/spec/[crypto, datatypes, digest, state_transition, helpers, ../beacon_chain/spec/[crypto, datatypes, digest, forkedbeaconstate_helpers,
presets, network], state_transition, helpers, presets, network],
# Test utilities # Test utilities
./testutil, ./testdbutil, ./testblockutil ./testutil, ./testdbutil, ./testblockutil
@ -43,7 +42,9 @@ suite "Gossip validation " & preset():
batchCrypto = BatchCrypto.new(keys.newRng(), eager = proc(): bool = false) batchCrypto = BatchCrypto.new(keys.newRng(), eager = proc(): bool = false)
# Slot 0 is a finalized slot - won't be making attestations for it.. # Slot 0 is a finalized slot - won't be making attestations for it..
check: check:
process_slots(state.data, getStateField(state, slot) + 1, cache, rewards) process_slots(
state.data, getStateField(state.data, slot) + 1, cache, rewards, {},
FAR_FUTURE_SLOT)
test "Validation sanity": test "Validation sanity":
# TODO: refactor tests to avoid skipping BLS validation # TODO: refactor tests to avoid skipping BLS validation
@ -67,14 +68,14 @@ suite "Gossip validation " & preset():
var var
# Create attestations for slot 1 # Create attestations for slot 1
beacon_committee = get_beacon_committee( beacon_committee = get_beacon_committee(
dag.headState, dag.head.slot, 0.CommitteeIndex, cache) dag.headState.data, dag.head.slot, 0.CommitteeIndex, cache)
att_1_0 = makeAttestation( att_1_0 = makeAttestation(
dag.headState, dag.head.root, beacon_committee[0], cache) dag.headState.data, dag.head.root, beacon_committee[0], cache)
att_1_1 = makeAttestation( att_1_1 = makeAttestation(
dag.headState, dag.head.root, beacon_committee[1], cache) dag.headState.data, dag.head.root, beacon_committee[1], cache)
committees_per_slot = committees_per_slot =
get_committee_count_per_slot(dag.headState, get_committee_count_per_slot(dag.headState.data,
att_1_0.data.slot.epoch, cache) att_1_0.data.slot.epoch, cache)
subnet = compute_subnet_for_attestation( subnet = compute_subnet_for_attestation(

View File

@ -11,7 +11,8 @@ import
options, sequtils, options, sequtils,
unittest2, unittest2,
./testutil, ./testdbutil, ./teststateutil, ./testutil, ./testdbutil, ./teststateutil,
../beacon_chain/spec/[datatypes, digest, helpers, presets], ../beacon_chain/spec/[
datatypes, digest, forkedbeaconstate_helpers, helpers, presets],
../beacon_chain/[beacon_node_types, statediff], ../beacon_chain/[beacon_node_types, statediff],
../beacon_chain/ssz, ../beacon_chain/ssz,
../beacon_chain/consensus_object_pools/[blockchain_dag, block_quarantine] ../beacon_chain/consensus_object_pools/[blockchain_dag, block_quarantine]
@ -30,19 +31,22 @@ suite "state diff tests" & preset():
for i in 0 ..< testStates.len: for i in 0 ..< testStates.len:
for j in (i+1) ..< testStates.len: for j in (i+1) ..< testStates.len:
doAssert testStates[i].data.slot < testStates[j].data.slot doAssert getStateField(testStates[i][], slot) <
if testStates[i].data.slot + SLOTS_PER_EPOCH != testStates[j].data.slot: getStateField(testStates[j][], slot)
if getStateField(testStates[i][], slot) + SLOTS_PER_EPOCH != getStateField(testStates[j][], slot):
continue continue
var tmpStateApplyBase = assignClone(testStates[i].data) var tmpStateApplyBase = assignClone(testStates[i].hbsPhase0.data)
let diff = diffStates(testStates[i].data, testStates[j].data) let diff = diffStates(
testStates[i].hbsPhase0.data, testStates[j].hbsPhase0.data)
# Immutable parts of validators stored separately, so aren't part of # Immutable parts of validators stored separately, so aren't part of
# the state diff. Synthesize required portion here for testing. # the state diff. Synthesize required portion here for testing.
applyDiff( applyDiff(
tmpStateApplyBase[], tmpStateApplyBase[],
mapIt(testStates[j].data.validators.asSeq[ mapIt(
testStates[i].data.validators.len .. getStateField(testStates[j][], validators).asSeq[
testStates[j].data.validators.len - 1], getStateField(testStates[i][], validators).len ..
getStateField(testStates[j][], validators).len - 1],
it.getImmutableValidatorData), it.getImmutableValidatorData),
diff) diff)
check hash_tree_root(testStates[j].data) == check hash_tree_root(testStates[j][]) ==
hash_tree_root(tmpStateApplyBase[]) hash_tree_root(tmpStateApplyBase[])

View File

@ -8,12 +8,12 @@
import import
chronicles, chronicles,
options, stew/endians2, options, stew/endians2,
../beacon_chain/extras, ../beacon_chain/[beacon_node_types, extras],
../beacon_chain/validators/validator_pool, ../beacon_chain/validators/validator_pool,
../beacon_chain/ssz/merkleization, ../beacon_chain/ssz/merkleization,
../beacon_chain/spec/[crypto, datatypes, digest, presets, helpers, validator, ../beacon_chain/spec/[crypto, datatypes, digest, presets, helpers,
signatures, state_transition], signatures, state_transition, forkedbeaconstate_helpers],
../beacon_chain/consensus_object_pools/statedata_helpers ../beacon_chain/consensus_object_pools/attestation_pool
func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey = func makeFakeValidatorPrivKey(i: int): ValidatorPrivKey =
# 0 is not a valid BLS private key - 1000 helps interop with rust BLS library, # 0 is not a valid BLS private key - 1000 helps interop with rust BLS library,
@ -76,7 +76,7 @@ func signBlock(
) )
proc addTestBlock*( proc addTestBlock*(
state: var HashedBeaconState, state: var ForkedHashedBeaconState,
parent_root: Eth2Digest, parent_root: Eth2Digest,
cache: var StateCache, cache: var StateCache,
eth1_data = Eth1Data(), eth1_data = Eth1Data(),
@ -88,30 +88,34 @@ proc addTestBlock*(
# Create and add a block to state - state will advance by one slot! # Create and add a block to state - state will advance by one slot!
if nextSlot: if nextSlot:
var rewards: RewardInfo var rewards: RewardInfo
doAssert process_slots(state, state.data.slot + 1, cache, rewards, flags) doAssert process_slots(
state, getStateField(state, slot) + 1, cache, rewards, flags,
FAR_FUTURE_SLOT)
let let
proposer_index = get_beacon_proposer_index(state.data, cache) proposer_index = get_beacon_proposer_index(
privKey = hackPrivKey(state.data.validators[proposer_index.get]) state, cache, getStateField(state, slot))
privKey = hackPrivKey(getStateField(state, validators)[proposer_index.get])
randao_reveal = randao_reveal =
if skipBlsValidation notin flags: if skipBlsValidation notin flags:
privKey.genRandaoReveal( privKey.genRandaoReveal(
state.data.fork, state.data.genesis_validators_root, state.data.slot). getStateField(state, fork),
toValidatorSig() getStateField(state, genesis_validators_root),
getStateField(state, slot)).toValidatorSig()
else: else:
ValidatorSig() ValidatorSig()
let let
message = makeBeaconBlock( message = makeBeaconBlock(
defaultRuntimePreset, defaultRuntimePreset,
state, state.hbsPhase0,
proposer_index.get(), proposer_index.get(),
parent_root, parent_root,
randao_reveal, randao_reveal,
# Keep deposit counts internally consistent. # Keep deposit counts internally consistent.
Eth1Data( Eth1Data(
deposit_root: eth1_data.deposit_root, deposit_root: eth1_data.deposit_root,
deposit_count: state.data.eth1_deposit_index + deposits.lenu64, deposit_count: getStateField(state, eth1_deposit_index) + deposits.lenu64,
block_hash: eth1_data.block_hash), block_hash: eth1_data.block_hash),
graffiti, graffiti,
attestations, attestations,
@ -127,13 +131,14 @@ proc addTestBlock*(
let let
new_block = signBlock( new_block = signBlock(
state.data.fork, getStateField(state, fork),
state.data.genesis_validators_root, message.get(), privKey, flags) getStateField(state, genesis_validators_root), message.get(), privKey,
flags)
new_block new_block
proc makeTestBlock*( proc makeTestBlock*(
state: HashedBeaconState, state: ForkedHashedBeaconState,
parent_root: Eth2Digest, parent_root: Eth2Digest,
cache: var StateCache, cache: var StateCache,
eth1_data = Eth1Data(), eth1_data = Eth1Data(),
@ -150,7 +155,7 @@ proc makeTestBlock*(
graffiti) graffiti)
func makeAttestationData*( func makeAttestationData*(
state: StateData, slot: Slot, committee_index: CommitteeIndex, state: ForkedHashedBeaconState, slot: Slot, committee_index: CommitteeIndex,
beacon_block_root: Eth2Digest): AttestationData = beacon_block_root: Eth2Digest): AttestationData =
## Create an attestation / vote for the block `beacon_block_root` using the ## Create an attestation / vote for the block `beacon_block_root` using the
## data in `state` to fill in the rest of the fields. ## data in `state` to fill in the rest of the fields.
@ -181,7 +186,7 @@ func makeAttestationData*(
) )
func makeAttestation*( func makeAttestation*(
state: StateData, beacon_block_root: Eth2Digest, state: ForkedHashedBeaconState, beacon_block_root: Eth2Digest,
committee: seq[ValidatorIndex], slot: Slot, index: CommitteeIndex, committee: seq[ValidatorIndex], slot: Slot, index: CommitteeIndex,
validator_index: ValidatorIndex, cache: var StateCache, validator_index: ValidatorIndex, cache: var StateCache,
flags: UpdateFlags = {}): Attestation = flags: UpdateFlags = {}): Attestation =
@ -216,7 +221,7 @@ func makeAttestation*(
) )
func find_beacon_committee*( func find_beacon_committee*(
state: StateData, validator_index: ValidatorIndex, state: ForkedHashedBeaconState, validator_index: ValidatorIndex,
cache: var StateCache): auto = cache: var StateCache): auto =
let epoch = compute_epoch_at_slot(getStateField(state, slot)) let epoch = compute_epoch_at_slot(getStateField(state, slot))
for epoch_committee_index in 0'u64 ..< get_committee_count_per_slot( for epoch_committee_index in 0'u64 ..< get_committee_count_per_slot(
@ -231,7 +236,7 @@ func find_beacon_committee*(
doAssert false doAssert false
func makeAttestation*( func makeAttestation*(
state: StateData, beacon_block_root: Eth2Digest, state: ForkedHashedBeaconState, beacon_block_root: Eth2Digest,
validator_index: ValidatorIndex, cache: var StateCache): Attestation = validator_index: ValidatorIndex, cache: var StateCache): Attestation =
let (committee, slot, index) = let (committee, slot, index) =
find_beacon_committee(state, validator_index, cache) find_beacon_committee(state, validator_index, cache)
@ -239,7 +244,7 @@ func makeAttestation*(
validator_index, cache) validator_index, cache)
func makeFullAttestations*( func makeFullAttestations*(
state: StateData, beacon_block_root: Eth2Digest, slot: Slot, state: ForkedHashedBeaconState, beacon_block_root: Eth2Digest, slot: Slot,
cache: var StateCache, cache: var StateCache,
flags: UpdateFlags = {}): seq[Attestation] = flags: UpdateFlags = {}): seq[Attestation] =
# Create attestations in which the full committee participates for each shard # Create attestations in which the full committee participates for each shard
@ -284,10 +289,12 @@ func makeFullAttestations*(
state: HashedBeaconState, beacon_block_root: Eth2Digest, slot: Slot, state: HashedBeaconState, beacon_block_root: Eth2Digest, slot: Slot,
cache: var StateCache, cache: var StateCache,
flags: UpdateFlags = {}): seq[Attestation] = flags: UpdateFlags = {}): seq[Attestation] =
# TODO this only supports phase 0 currently. Either expand that to
# Altair here or use the ForkedHashedBeaconState version only
makeFullAttestations( makeFullAttestations(
(ref StateData)(data: state, blck: BlockRef( (ref ForkedHashedBeaconState)(
root: beacon_block_root, slot: slot))[], beacon_block_root, slot, cache, beaconStateFork: forkPhase0, hbsPhase0: state)[],
flags) beacon_block_root, slot, cache, flags)
iterator makeTestBlocks*( iterator makeTestBlocks*(
state: HashedBeaconState, state: HashedBeaconState,
@ -296,11 +303,13 @@ iterator makeTestBlocks*(
blocks: int, blocks: int,
attested: bool): SignedBeaconBlock = attested: bool): SignedBeaconBlock =
var var
state = assignClone(state) # TODO replace wrapper with more native usage
state = (ref ForkedHashedBeaconState)(
hbsPhase0: state, beaconStateFork: forkPhase0)
parent_root = parent_root parent_root = parent_root
for _ in 0..<blocks: for _ in 0..<blocks:
let attestations = if attested: let attestations = if attested:
makeFullAttestations(state[], parent_root, state[].data.slot, cache) makeFullAttestations(state[], parent_root, getStateField(state[], slot), cache)
else: else:
@[] @[]
@ -308,3 +317,13 @@ iterator makeTestBlocks*(
state[], parent_root, cache, attestations = attestations) state[], parent_root, cache, attestations = attestations)
yield blck yield blck
parent_root = blck.root parent_root = blck.root
iterator makeTestBlocks*(state: ForkedHashedBeaconState; parent_root: Eth2Digest;
cache: var StateCache; blocks: int; attested: bool): SignedBeaconBlock =
for blck in makeTestBlocks(state.hbsPhase0, parent_root, cache, blocks, attested):
yield blck
proc getAttestationsforTestBlock*(
pool: var AttestationPool, stateData: StateData, cache: var StateCache):
seq[Attestation] =
pool.getAttestationsForBlock(stateData.data.hbsPhase0, cache)

View File

@ -12,8 +12,9 @@ import
./mocking/mock_deposits, ./mocking/mock_deposits,
./helpers/math_helpers, ./helpers/math_helpers,
../beacon_chain/ssz/merkleization, ../beacon_chain/ssz/merkleization,
../beacon_chain/spec/[beaconstate, crypto, datatypes, presets, ../beacon_chain/spec/[
helpers, state_transition] beaconstate, crypto, datatypes, forkedbeaconstate_helpers, helpers,
presets, state_transition]
proc valid_deposit(state: var BeaconState) = proc valid_deposit(state: var BeaconState) =
const deposit_amount = MAX_EFFECTIVE_BALANCE const deposit_amount = MAX_EFFECTIVE_BALANCE
@ -40,8 +41,8 @@ proc valid_deposit(state: var BeaconState) =
EFFECTIVE_BALANCE_INCREMENT EFFECTIVE_BALANCE_INCREMENT
) )
proc getTestStates*(initialState: HashedBeaconState): proc getTestStates*(initialState: ForkedHashedBeaconState):
seq[ref HashedBeaconState] = seq[ref ForkedHashedBeaconState] =
# Randomly generated slot numbers, with a jump to around # Randomly generated slot numbers, with a jump to around
# SLOTS_PER_HISTORICAL_ROOT to force wraparound of those # SLOTS_PER_HISTORICAL_ROOT to force wraparound of those
# slot-based mod/increment fields. # slot-based mod/increment fields.
@ -64,9 +65,10 @@ proc getTestStates*(initialState: HashedBeaconState):
for i, epoch in stateEpochs: for i, epoch in stateEpochs:
let slot = epoch.Epoch.compute_start_slot_at_epoch let slot = epoch.Epoch.compute_start_slot_at_epoch
if tmpState.data.slot < slot: if getStateField(tmpState[], slot) < slot:
doAssert process_slots(tmpState[], slot, cache, rewards) doAssert process_slots(
tmpState[], slot, cache, rewards, {}, FAR_FUTURE_SLOT)
if i mod 3 == 0: if i mod 3 == 0:
valid_deposit(tmpState.data) valid_deposit(tmpState.hbsPhase0.data)
doAssert tmpState.data.slot == slot doAssert getStateField(tmpState[], slot) == slot
result.add assignClone(tmpState[]) result.add assignClone(tmpState[])