altair fork handling cleanups (#3050)

* fix stack overflow crash in REST/debug/getStateV2
* introduce `ForkyXxx` for generic type matching of `Xxx` across
branches (SomeHashedBeaconState -> ForkyHashedBeaconState et al) -
`Some` is already used for other types of type classes
* consolidate function naming in BeaconChainDB, use some generics
* import `forks.nim` from other spec modules and move `Forked*` helpers
around to resolve circular imports
* remove `ForkedBeaconState`, use `ForkedHashedBeaconState` throughout
(less data shuffling between the types)
* fix several cases of states being stored on stack in tests, causing
random failures on some platforms
* remove reading json support from ncli - this should be ported to the
rest json reading instead (doesn't currently work because stack sizes)
This commit is contained in:
Jacek Sieka 2021-11-05 08:34:34 +01:00 committed by GitHub
parent 98668dbf16
commit a086cf01ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 625 additions and 634 deletions

View File

@ -13,7 +13,7 @@ import
serialization, chronicles, snappy,
eth/db/[kvstore, kvstore_sqlite3],
./networking/network_metadata, ./beacon_chain_db_immutable,
./spec/[eth2_ssz_serialization, eth2_merkleization, state_transition],
./spec/[eth2_ssz_serialization, eth2_merkleization, forks, state_transition],
./spec/datatypes/[phase0, altair, merge],
./filepath
@ -93,7 +93,7 @@ type
altairBlocks: KvStoreRef # BlockRoot -> altair.TrustedBeaconBlock
mergeBlocks: KvStoreRef # BlockRoot -> merge.TrustedBeaconBlock
stateRoots: KvStoreRef # (Slot, BlockRoot) -> StateRoot
statesNoVal: KvStoreRef # StateRoot -> BeaconStateNoImmutableValidators
statesNoVal: KvStoreRef # StateRoot -> Phase0BeaconStateNoImmutableValidators
altairStatesNoVal: KvStoreRef # StateRoot -> AltairBeaconStateNoImmutableValidators
mergeStatesNoVal: KvStoreRef # StateRoot -> MergeBeaconStateNoImmutableValidators
stateDiffs: KvStoreRef ##\
@ -120,7 +120,7 @@ type
## past the weak subjectivity period.
kBlockSlotStateRoot
## BlockSlot -> state_root mapping
kGenesisBlockRoot
kGenesisBlock
## Immutable reference to the network genesis state
## (needed for satisfying requests to the beacon node API).
kEth1PersistedTo # Obsolete
@ -168,7 +168,7 @@ func subkey(kind: type phase0.BeaconState, key: Eth2Digest): auto =
subkey(kHashToState, key.data)
func subkey(
kind: type BeaconStateNoImmutableValidators, key: Eth2Digest): auto =
kind: type Phase0BeaconStateNoImmutableValidators, key: Eth2Digest): auto =
subkey(kHashToStateOnlyMutableValidators, key.data)
func subkey(kind: type phase0.SignedBeaconBlock, key: Eth2Digest): auto =
@ -508,27 +508,34 @@ proc updateImmutableValidators*(
db.immutableValidatorsDb.add immutableValidator
db.immutableValidators.add immutableValidator
template toBeaconStateNoImmutableValidators(state: phase0.BeaconState):
Phase0BeaconStateNoImmutableValidators =
isomorphicCast[Phase0BeaconStateNoImmutableValidators](state)
template toBeaconStateNoImmutableValidators(state: altair.BeaconState):
AltairBeaconStateNoImmutableValidators =
isomorphicCast[AltairBeaconStateNoImmutableValidators](state)
template toBeaconStateNoImmutableValidators(state: merge.BeaconState):
MergeBeaconStateNoImmutableValidators =
isomorphicCast[MergeBeaconStateNoImmutableValidators](state)
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: phase0.BeaconState) =
db.updateImmutableValidators(value.validators.asSeq())
db.statesNoVal.putSnappySSZ(
key.data,
isomorphicCast[BeaconStateNoImmutableValidators](value))
key.data, toBeaconStateNoImmutableValidators(value))
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: altair.BeaconState) =
db.updateImmutableValidators(value.validators.asSeq())
db.altairStatesNoVal.putSnappySSZ(
key.data,
isomorphicCast[AltairBeaconStateNoImmutableValidators](value))
key.data, toBeaconStateNoImmutableValidators(value))
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: merge.BeaconState) =
db.updateImmutableValidators(value.validators.asSeq())
db.mergeStatesNoVal.putSnappySSZ(
key.data,
isomorphicCast[MergeBeaconStateNoImmutableValidators](value))
key.data, toBeaconStateNoImmutableValidators(value))
proc putState*(
db: BeaconChainDB,
value: phase0.BeaconState | altair.BeaconState | merge.BeaconState) =
proc putState*(db: BeaconChainDB, value: ForkyBeaconState) =
db.putState(hash_tree_root(value), value)
# For testing rollback
@ -579,14 +586,14 @@ proc putHeadBlock*(db: BeaconChainDB, key: Eth2Digest) =
proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
db.keyValues.putRaw(subkey(kTailBlock), key)
proc putGenesisBlockRoot*(db: BeaconChainDB, key: Eth2Digest) =
db.keyValues.putRaw(subkey(kGenesisBlockRoot), key)
proc putGenesisBlock*(db: BeaconChainDB, key: Eth2Digest) =
db.keyValues.putRaw(subkey(kGenesisBlock), key)
proc putEth2FinalizedTo*(db: BeaconChainDB,
eth1Checkpoint: DepositContractSnapshot) =
db.keyValues.putSnappySSZ(subkey(kDepositsFinalizedByEth2), eth1Checkpoint)
proc getBlock(db: BeaconChainDBV0, key: Eth2Digest): Opt[phase0.TrustedSignedBeaconBlock] =
proc getPhase0Block(db: BeaconChainDBV0, key: Eth2Digest): Opt[phase0.TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database
result.ok(default(phase0.TrustedSignedBeaconBlock))
if db.backend.getSnappySSZ(
@ -596,12 +603,12 @@ proc getBlock(db: BeaconChainDBV0, key: Eth2Digest): Opt[phase0.TrustedSignedBea
# set root after deserializing (so it doesn't get zeroed)
result.get().root = key
proc getBlock*(db: BeaconChainDB, key: Eth2Digest):
proc getPhase0Block*(db: BeaconChainDB, key: Eth2Digest):
Opt[phase0.TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database
result.ok(default(phase0.TrustedSignedBeaconBlock))
if db.blocks.getSnappySSZ(key.data, result.get) != GetResult.found:
result = db.v0.getBlock(key)
result = db.v0.getPhase0Block(key)
else:
# set root after deserializing (so it doesn't get zeroed)
result.get().root = key
@ -628,7 +635,7 @@ proc getMergeBlock*(db: BeaconChainDB, key: Eth2Digest):
proc getStateOnlyMutableValidators(
immutableValidators: openArray[ImmutableValidatorData2],
store: KvStoreRef, key: openArray[byte], output: var phase0.BeaconState,
store: KvStoreRef, key: openArray[byte], output: var ForkyBeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
@ -641,92 +648,7 @@ proc getStateOnlyMutableValidators(
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
case store.getSnappySSZ(
key, isomorphicCast[BeaconStateNoImmutableValidators](output))
of GetResult.found:
let numValidators = output.validators.len
doAssert immutableValidators.len >= numValidators
for i in 0 ..< numValidators:
let
# Bypass hash cache invalidation
dstValidator = addr output.validators.data[i]
assign(
dstValidator.pubkey,
immutableValidators[i].pubkey.loadValid().toPubKey())
assign(
dstValidator.withdrawal_credentials,
immutableValidators[i].withdrawal_credentials)
output.validators.resetCache()
true
of GetResult.notFound:
false
of GetResult.corrupted:
rollback()
false
proc getAltairStateOnlyMutableValidators(
immutableValidators: openArray[ImmutableValidatorData2],
store: KvStoreRef, key: openArray[byte], output: var altair.BeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
## Return `true` iff the entry was found in the database and `output` was
## overwritten.
## Rollback will be called only if output was partially written - if it was
## not found at all, rollback will not be called
# TODO rollback is needed to deal with bug - use `noRollback` to ignore:
# https://github.com/nim-lang/Nim/issues/14126
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
case store.getSnappySSZ(
key, isomorphicCast[AltairBeaconStateNoImmutableValidators](output))
of GetResult.found:
let numValidators = output.validators.len
doAssert immutableValidators.len >= numValidators
for i in 0 ..< numValidators:
let
# Bypass hash cache invalidation
dstValidator = addr output.validators.data[i]
assign(
dstValidator.pubkey,
immutableValidators[i].pubkey.loadValid().toPubKey())
assign(
dstValidator.withdrawal_credentials,
immutableValidators[i].withdrawal_credentials)
output.validators.resetCache()
true
of GetResult.notFound:
false
of GetResult.corrupted:
rollback()
false
proc getMergeStateOnlyMutableValidators(
immutableValidators: openArray[ImmutableValidatorData2],
store: KvStoreRef, key: openArray[byte], output: var merge.BeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
## Return `true` iff the entry was found in the database and `output` was
## overwritten.
## Rollback will be called only if output was partially written - if it was
## not found at all, rollback will not be called
# TODO rollback is needed to deal with bug - use `noRollback` to ignore:
# https://github.com/nim-lang/Nim/issues/14126
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
case store.getSnappySSZ(
key, isomorphicCast[MergeBeaconStateNoImmutableValidators](output))
case store.getSnappySSZ(key, toBeaconStateNoImmutableValidators(output))
of GetResult.found:
let numValidators = output.validators.len
doAssert immutableValidators.len >= numValidators
@ -765,11 +687,11 @@ proc getState(
# from `stateStore`. We will try to read the state from all these locations.
if getStateOnlyMutableValidators(
immutableValidators, db.stateStore,
subkey(BeaconStateNoImmutableValidators, key), output, rollback):
subkey(Phase0BeaconStateNoImmutableValidators, key), output, rollback):
return true
if getStateOnlyMutableValidators(
immutableValidators, db.backend,
subkey(BeaconStateNoImmutableValidators, key), output, rollback):
subkey(Phase0BeaconStateNoImmutableValidators, key), output, rollback):
return true
case db.backend.getSnappySSZ(subkey(phase0.BeaconState, key), output)
@ -800,7 +722,7 @@ proc getState*(
else:
true
proc getAltairState*(
proc getState*(
db: BeaconChainDB, key: Eth2Digest, output: var altair.BeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
@ -813,10 +735,10 @@ proc getAltairState*(
# https://github.com/nim-lang/Nim/issues/14126
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
getAltairStateOnlyMutableValidators(
getStateOnlyMutableValidators(
db.immutableValidators, db.altairStatesNoVal, key.data, output, rollback)
proc getMergeState*(
proc getState*(
db: BeaconChainDB, key: Eth2Digest, output: var merge.BeaconState,
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
@ -829,7 +751,7 @@ proc getMergeState*(
# https://github.com/nim-lang/Nim/issues/14126
# TODO RVO is inefficient for large objects:
# https://github.com/nim-lang/Nim/issues/13879
getMergeStateOnlyMutableValidators(
getStateOnlyMutableValidators(
db.immutableValidators, db.mergeStatesNoVal, key.data, output, rollback)
proc getStateRoot(db: BeaconChainDBV0,
@ -863,12 +785,12 @@ proc getTailBlock*(db: BeaconChainDB): Opt[Eth2Digest] =
db.keyValues.getRaw(subkey(kTailBlock), Eth2Digest) or
db.v0.getTailBlock()
proc getGenesisBlockRoot(db: BeaconChainDBV0): Opt[Eth2Digest] =
db.backend.getRaw(subkey(kGenesisBlockRoot), Eth2Digest)
proc getGenesisBlock(db: BeaconChainDBV0): Opt[Eth2Digest] =
db.backend.getRaw(subkey(kGenesisBlock), Eth2Digest)
proc getGenesisBlockRoot*(db: BeaconChainDB): Opt[Eth2Digest] =
db.keyValues.getRaw(subkey(kGenesisBlockRoot), Eth2Digest) or
db.v0.getGenesisBlockRoot()
proc getGenesisBlock*(db: BeaconChainDB): Opt[Eth2Digest] =
db.keyValues.getRaw(subkey(kGenesisBlock), Eth2Digest) or
db.v0.getGenesisBlock()
proc getEth2FinalizedTo(db: BeaconChainDBV0): Opt[DepositContractSnapshot] =
result.ok(DepositContractSnapshot())
@ -898,7 +820,7 @@ proc containsBlock*(db: BeaconChainDB, key: Eth2Digest): bool =
db.containsBlockPhase0(key)
proc containsState*(db: BeaconChainDBV0, key: Eth2Digest): bool =
let sk = subkey(BeaconStateNoImmutableValidators, key)
let sk = subkey(Phase0BeaconStateNoImmutableValidators, key)
db.stateStore.contains(sk).expectDb() or
db.backend.contains(sk).expectDb() or
db.backend.contains(subkey(phase0.BeaconState, key)).expectDb()

View File

@ -17,7 +17,7 @@ import
type
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#beaconstate
# Memory-representation-equivalent to a phase0 BeaconState for in-place SSZ reading and writing
BeaconStateNoImmutableValidators* = object
Phase0BeaconStateNoImmutableValidators* = object
# Versioning
genesis_time*: uint64
genesis_validators_root*: Eth2Digest

View File

@ -374,8 +374,7 @@ proc addAttestation*(pool: var AttestationPool,
proc addForkChoice*(pool: var AttestationPool,
epochRef: EpochRef,
blckRef: BlockRef,
blck: phase0.TrustedBeaconBlock | altair.TrustedBeaconBlock |
merge.TrustedBeaconBlock,
blck: ForkyTrustedBeaconBlock,
wallSlot: Slot) =
## Add a verified block to the fork choice context
let state = pool.forkChoice.process_block(
@ -510,7 +509,7 @@ proc score(
bitsScore
proc getAttestationsForBlock*(pool: var AttestationPool,
state: SomeHashedBeaconState,
state: ForkyHashedBeaconState,
cache: var StateCache): seq[Attestation] =
## Retrieve attestations that may be added to a new block at the slot of the
## given state

View File

@ -31,43 +31,6 @@ export results, ValidationResult
logScope:
topics = "clearance"
## At the GC-level, the GC is type-agnostic; it's all type-erased so
## casting between seq[Attestation] and seq[TrustedAttestation] will
## not disrupt GC operations.
##
## These SHOULD be used in function calls to avoid expensive temporary.
## see https://github.com/status-im/nimbus-eth2/pull/2250#discussion_r562010679
template asSigVerified(x: phase0.SignedBeaconBlock):
phase0.SigVerifiedSignedBeaconBlock =
## This converts a signed beacon block to a sig verified beacon clock.
## This verifies that their bytes representation is the same.
isomorphicCast[phase0.SigVerifiedSignedBeaconBlock](x)
template asSigVerified(x: altair.SignedBeaconBlock):
altair.SigVerifiedSignedBeaconBlock =
## This converts a signed beacon block to a sig verified beacon clock.
## This verifies that their bytes representation is the same.
isomorphicCast[altair.SigVerifiedSignedBeaconBlock](x)
template asSigVerified(x: merge.SignedBeaconBlock):
merge.SigVerifiedSignedBeaconBlock =
## This converts a signed beacon block to a sig verified beacon clock.
## This verifies that their bytes representation is the same.
isomorphicCast[merge.SigVerifiedSignedBeaconBlock](x)
# TODO aren't these in forks.nim?
template asTrusted(x: phase0.SignedBeaconBlock or phase0.SigVerifiedBeaconBlock):
phase0.TrustedSignedBeaconBlock =
## This converts a sigverified beacon block to a trusted beacon clock.
## This verifies that their bytes representation is the same.
isomorphicCast[phase0.TrustedSignedBeaconBlock](x)
template asTrusted(x: altair.SignedBeaconBlock or altair.SigVerifiedBeaconBlock):
altair.TrustedSignedBeaconBlock =
## This converts a sigverified beacon block to a trusted beacon clock.
## This verifies that their bytes representation is the same.
isomorphicCast[altair.TrustedSignedBeaconBlock](x)
proc batchVerify(quarantine: QuarantineRef, sigs: openArray[SignatureSet]): bool =
var secureRandomBytes: array[32, byte]
quarantine.rng[].brHmacDrbgGenerate(secureRandomBytes)
@ -78,8 +41,7 @@ proc batchVerify(quarantine: QuarantineRef, sigs: openArray[SignatureSet]): bool
proc addRawBlock*(
dag: ChainDAGRef, quarantine: QuarantineRef,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signedBlock: ForkySignedBeaconBlock,
onBlockAdded: OnPhase0BlockAdded | OnAltairBlockAdded | OnMergeBlockAdded
): Result[BlockRef, (ValidationResult, BlockError)] {.gcsafe.}
@ -144,8 +106,7 @@ proc resolveQuarantinedBlocks(
proc addResolvedBlock(
dag: ChainDAGRef, quarantine: QuarantineRef,
state: var StateData,
trustedBlock: phase0.TrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock |
merge.TrustedSignedBeaconBlock,
trustedBlock: ForkyTrustedSignedBeaconBlock,
parent: BlockRef, cache: var StateCache,
onBlockAdded: OnPhase0BlockAdded | OnAltairBlockAdded | OnMergeBlockAdded,
stateDataDur, sigVerifyDur, stateVerifyDur: Duration
@ -261,8 +222,7 @@ proc advanceClearanceState*(dag: ChainDAGRef) =
proc addRawBlockKnownParent(
dag: ChainDAGRef, quarantine: QuarantineRef,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signedBlock: ForkySignedBeaconBlock,
parent: BlockRef,
onBlockAdded: OnPhase0BlockAdded | OnAltairBlockAdded | OnMergeBlockAdded
): Result[BlockRef, (ValidationResult, BlockError)] =
@ -390,8 +350,7 @@ proc addRawBlockUnresolved(
proc addRawBlock(
dag: ChainDAGRef, quarantine: QuarantineRef,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signedBlock: ForkySignedBeaconBlock,
onBlockAdded: OnPhase0BlockAdded | OnAltairBlockAdded | OnMergeBlockAdded
): Result[BlockRef, (ValidationResult, BlockError)] =
## Try adding a block to the chain, verifying first that it passes the state

View File

@ -183,7 +183,7 @@ type
## block - we limit the number of held EpochRefs to put a cap on
## memory usage
forkDigests*: ForkDigestsRef
forkDigests*: ref ForkDigests
## Cached copy of the fork digests associated with the current
## database. We use a ref type to facilitate sharing this small
## value with other components which don't have access to the

View File

@ -12,6 +12,7 @@ import
chronicles,
stew/bitops2,
eth/keys,
../spec/forks,
../spec/datatypes/[phase0, altair, merge],
./block_pools_types
@ -102,9 +103,7 @@ func removeOrphan*(
quarantine.orphansMerge.del((signedBlock.root, signedBlock.signature))
func isViableOrphan(
dag: ChainDAGRef,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock): bool =
dag: ChainDAGRef, signedBlock: ForkySignedBeaconBlock): bool =
# The orphan must be newer than the finalization point so that its parent
# either is the finalized block or more recent
signedBlock.message.slot > dag.finalizedHead.slot

View File

@ -18,7 +18,10 @@ import
".."/beacon_chain_db,
"."/[block_pools_types, block_quarantine, forkedbeaconstate_dbhelpers]
export block_pools_types, results
export
forks, block_pools_types, results, forkedbeaconstate_dbhelpers,
beacon_chain_db,
eth2_merkleization, eth2_ssz_serialization
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#interop-metrics
declareGauge beacon_head_root, "Root of the head block of the beacon chain"
@ -46,9 +49,7 @@ declareGauge beacon_processed_deposits_total, "Number of total deposits included
logScope: topics = "chaindag"
proc putBlock*(
dag: ChainDAGRef,
signedBlock: phase0.TrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock |
merge.TrustedSignedBeaconBlock) =
dag: ChainDAGRef, signedBlock: ForkyTrustedSignedBeaconBlock) =
dag.db.putBlock(signedBlock)
proc updateStateData*(
@ -343,23 +344,18 @@ proc getStateData(
if not root.isSome():
return false
case cfg.stateForkAtEpoch(bs.slot.epoch)
of BeaconStateFork.Merge:
if state.data.kind != BeaconStateFork.Merge:
state.data = (ref ForkedHashedBeaconState)(kind: BeaconStateFork.Merge)[]
let expectedFork = cfg.stateForkAtEpoch(bs.slot.epoch)
if state.data.kind != expectedFork:
state.data = (ref ForkedHashedBeaconState)(kind: expectedFork)[]
if not db.getMergeState(root.get(), state.data.mergeData.data, rollback):
case expectedFork
of BeaconStateFork.Merge:
if not db.getState(root.get(), state.data.mergeData.data, rollback):
return false
of BeaconStateFork.Altair:
if state.data.kind != BeaconStateFork.Altair:
state.data = (ref ForkedHashedBeaconState)(kind: BeaconStateFork.Altair)[]
if not db.getAltairState(root.get(), state.data.altairData.data, rollback):
if not db.getState(root.get(), state.data.altairData.data, rollback):
return false
of BeaconStateFork.Phase0:
if state.data.kind != BeaconStateFork.Phase0:
state.data = (ref ForkedHashedBeaconState)(kind: BeaconStateFork.Phase0)[]
if not db.getState(root.get(), state.data.phase0Data.data, rollback):
return false
@ -384,7 +380,7 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
let
tailRoot = tailBlockRoot.get()
tailBlock = db.getBlock(tailRoot).get()
tailBlock = db.getPhase0Block(tailRoot).get()
tailRef = BlockRef.init(tailRoot, tailBlock.message)
headRoot = headBlockRoot.get()
@ -392,9 +388,9 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
tailRef
else:
let
genesisBlockRoot = db.getGenesisBlockRoot().expect(
genesisBlockRoot = db.getGenesisBlock().expect(
"preInit should have initialized the database with a genesis block root")
genesisBlock = db.getBlock(genesisBlockRoot).expect(
genesisBlock = db.getPhase0Block(genesisBlockRoot).expect(
"preInit should have initialized the database with a genesis block")
BlockRef.init(genesisBlockRoot, genesisBlock.message)
@ -727,7 +723,7 @@ func getBlockBySlot*(dag: ChainDAGRef, slot: Slot): BlockRef =
proc getForkedBlock*(dag: ChainDAGRef, blck: BlockRef): ForkedTrustedSignedBeaconBlock =
case dag.cfg.blockForkAtEpoch(blck.slot.epoch)
of BeaconBlockFork.Phase0:
let data = dag.db.getBlock(blck.root)
let data = dag.db.getPhase0Block(blck.root)
if data.isOk():
return ForkedTrustedSignedBeaconBlock.init(data.get)
of BeaconBlockFork.Altair:
@ -1324,9 +1320,9 @@ proc isInitialized*(T: type ChainDAGRef, db: BeaconChainDB): bool =
return false
let
headBlockPhase0 = db.getBlock(headBlockRoot.get())
headBlockPhase0 = db.getPhase0Block(headBlockRoot.get())
headBlockAltair = db.getAltairBlock(headBlockRoot.get())
tailBlock = db.getBlock(tailBlockRoot.get())
tailBlock = db.getPhase0Block(tailBlockRoot.get())
if not ((headBlockPhase0.isSome() or headBlockAltair.isSome()) and
tailBlock.isSome()):
@ -1359,14 +1355,14 @@ proc preInit*(
db.putStateRoot(tailBlock.root, tailState.slot, tailBlock.message.state_root)
if tailState.slot == GENESIS_SLOT:
db.putGenesisBlockRoot(tailBlock.root)
db.putGenesisBlock(tailBlock.root)
else:
doAssert genesisState.slot == GENESIS_SLOT
db.putState(genesisState)
let genesisBlock = get_initial_beacon_block(genesisState)
db.putBlock(genesisBlock)
db.putStateRoot(genesisBlock.root, GENESIS_SLOT, genesisBlock.message.state_root)
db.putGenesisBlockRoot(genesisBlock.root)
db.putGenesisBlock(genesisBlock.root)
func setTailState*(dag: ChainDAGRef,
checkpointState: phase0.BeaconState,

View File

@ -132,7 +132,7 @@ func getExitMessagesForBlock(
subpool.clear()
func getBeaconBlockExits*(pool: var ExitPool, state: SomeBeaconState): BeaconBlockExits =
func getBeaconBlockExits*(pool: var ExitPool, state: ForkyBeaconState): BeaconBlockExits =
var
indices: HashSet[uint64]
res: BeaconBlockExits

View File

@ -130,8 +130,7 @@ proc addBlock*(
proc dumpBlock*[T](
self: BlockProcessor,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signedBlock: ForkySignedBeaconBlock,
res: Result[T, (ValidationResult, BlockError)]) =
if self.dumpEnabled and res.isErr:
case res.error[1]
@ -146,8 +145,7 @@ proc dumpBlock*[T](
proc storeBlock*(
self: var BlockProcessor,
signedBlock: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signedBlock: ForkySignedBeaconBlock,
wallSlot: Slot): Result[BlockRef, BlockError] =
let
attestationPool = self.consensusManager.attestationPool

View File

@ -76,7 +76,7 @@ type
connTable: HashSet[PeerID]
forkId*: ENRForkID
discoveryForkId*: ENRForkID
forkDigests*: ForkDigestsRef
forkDigests*: ref ForkDigests
rng*: ref BrHmacDrbgContext
peers*: Table[PeerID, Peer]
validTopics: HashSet[string]
@ -1302,7 +1302,7 @@ proc onConnEvent(node: Eth2Node, peerId: PeerID, event: ConnEvent) {.async.} =
peer.connectionState = Disconnected
proc new*(T: type Eth2Node, config: BeaconNodeConf, runtimeCfg: RuntimeConfig,
enrForkId: ENRForkID, discoveryForkId: ENRForkId, forkDigests: ForkDigestsRef,
enrForkId: ENRForkID, discoveryForkId: ENRForkId, forkDigests: ref ForkDigests,
getBeaconTime: GetBeaconTimeFn, switch: Switch,
pubsub: GossipSub, ip: Option[ValidIpAddress], tcpPort,
udpPort: Option[Port], privKey: keys.PrivateKey, discovery: bool,
@ -1827,7 +1827,7 @@ proc createEth2Node*(rng: ref BrHmacDrbgContext,
config: BeaconNodeConf,
netKeys: NetKeyPair,
cfg: RuntimeConfig,
forkDigests: ForkDigestsRef,
forkDigests: ref ForkDigests,
getBeaconTime: GetBeaconTimeFn,
genesisValidatorsRoot: Eth2Digest): Eth2Node
{.raises: [Defect, CatchableError].} =

View File

@ -12,7 +12,7 @@ import
tables, times, terminal],
# Nimble packages
serialization, json_serialization, spec/eth2_apis/eth2_rest_serialization,
spec/eth2_apis/eth2_rest_serialization,
stew/[objects, byteutils, endians2, io2], stew/shims/macros,
chronos, confutils, metrics, metrics/chronos_httpserver,
chronicles, bearssl, blscurve, presto,

View File

@ -14,7 +14,7 @@ import
../beacon_node, ../networking/eth2_network,
../consensus_object_pools/[blockchain_dag, exit_pool, spec_cache],
../validators/validator_duties,
../spec/[eth2_merkleization, forks, network],
../spec/[eth2_merkleization, forks, network, validator],
../spec/datatypes/[phase0, altair]
export rest_utils

View File

@ -77,8 +77,7 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
return
case contentType
of "application/json":
RestApiResponse.jsonResponsePlain(
ForkedBeaconState.init(stateData.data))
RestApiResponse.jsonResponsePlain(stateData.data)
of "application/octet-stream":
withState(stateData.data):
RestApiResponse.sszResponse(state.data)

View File

@ -17,7 +17,7 @@ import
../networking/eth2_network,
../validators/validator_duties,
../consensus_object_pools/blockchain_dag,
../spec/[eth2_merkleization, forks, network],
../spec/[eth2_merkleization, forks, network, validator],
../spec/datatypes/[phase0],
./rpc_utils

View File

@ -14,17 +14,17 @@ import
chronicles,
../extras,
./datatypes/[phase0, altair, merge],
"."/[eth2_merkleization, helpers, signatures, validator],
"."/[eth2_merkleization, forks, signatures, validator],
../../nbench/bench_lab
export extras, phase0, altair, merge
export extras, forks, validator
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#increase_balance
func increase_balance*(balance: var Gwei, delta: Gwei) =
balance += delta
func increase_balance*(
state: var SomeBeaconState, index: ValidatorIndex, delta: Gwei) =
state: var ForkyBeaconState, index: ValidatorIndex, delta: Gwei) =
## Increase the validator balance at index ``index`` by ``delta``.
if delta != 0: # avoid dirtying the balance cache if not needed
increase_balance(state.balances[index], delta)
@ -38,7 +38,7 @@ func decrease_balance*(balance: var Gwei, delta: Gwei) =
balance - delta
func decrease_balance*(
state: var SomeBeaconState, index: ValidatorIndex, delta: Gwei) =
state: var ForkyBeaconState, index: ValidatorIndex, delta: Gwei) =
## Decrease the validator balance at index ``index`` by ``delta``, with
## underflow protection.
if delta != 0: # avoid dirtying the balance cache if not needed
@ -71,7 +71,7 @@ func compute_activation_exit_epoch*(epoch: Epoch): Epoch =
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_validator_churn_limit
func get_validator_churn_limit*(
cfg: RuntimeConfig, state: SomeBeaconState, cache: var StateCache):
cfg: RuntimeConfig, state: ForkyBeaconState, cache: var StateCache):
uint64 =
## Return the validator churn limit for the current epoch.
max(
@ -80,7 +80,7 @@ func get_validator_churn_limit*(
state, state.get_current_epoch(), cache) div cfg.CHURN_LIMIT_QUOTIENT)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#initiate_validator_exit
func initiate_validator_exit*(cfg: RuntimeConfig, state: var SomeBeaconState,
func initiate_validator_exit*(cfg: RuntimeConfig, state: var ForkyBeaconState,
index: ValidatorIndex, cache: var StateCache) =
## Initiate the exit of the validator with index ``index``.
@ -122,7 +122,7 @@ func initiate_validator_exit*(cfg: RuntimeConfig, state: var SomeBeaconState,
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#slash_validator
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/altair/beacon-chain.md#modified-slash_validator
proc slash_validator*(
cfg: RuntimeConfig, state: var SomeBeaconState,
cfg: RuntimeConfig, state: var ForkyBeaconState,
slashed_index: ValidatorIndex, cache: var StateCache) =
## Slash the validator with index ``index``.
let epoch = get_current_epoch(state)
@ -184,26 +184,6 @@ proc slash_validator*(
func genesis_time_from_eth1_timestamp*(cfg: RuntimeConfig, eth1_timestamp: uint64): uint64 =
eth1_timestamp + cfg.GENESIS_DELAY
func genesisFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.GENESIS_FORK_VERSION,
epoch: GENESIS_EPOCH)
func altairFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.ALTAIR_FORK_VERSION,
epoch: cfg.ALTAIR_FORK_EPOCH)
func mergeFork*(cfg: RuntimeConfig): Fork =
# TODO in theory, the altair + merge forks could be in same epoch, so the
# previous fork version would be the GENESIS_FORK_VERSION
Fork(
previous_version: cfg.ALTAIR_FORK_VERSION,
current_version: cfg.MERGE_FORK_VERSION,
epoch: cfg.MERGE_FORK_EPOCH)
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#genesis
proc initialize_beacon_state_from_eth1*(
cfg: RuntimeConfig,
@ -315,8 +295,7 @@ func get_initial_beacon_block*(state: phase0.BeaconState):
message: message, root: hash_tree_root(message))
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_block_root_at_slot
func get_block_root_at_slot*(state: SomeBeaconState,
slot: Slot): Eth2Digest =
func get_block_root_at_slot*(state: ForkyBeaconState, slot: Slot): Eth2Digest =
## Return the block root at a recent ``slot``.
# Potential overflow/wrap shouldn't occur, as get_block_root_at_slot() called
@ -327,14 +306,20 @@ func get_block_root_at_slot*(state: SomeBeaconState,
doAssert slot < state.slot
state.block_roots[slot mod SLOTS_PER_HISTORICAL_ROOT]
func get_block_root_at_slot*(state: ForkedHashedBeaconState,
slot: Slot): Eth2Digest =
## Return the block root at a recent ``slot``.
withState(state):
get_block_root_at_slot(state.data, slot)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_block_root
func get_block_root*(state: SomeBeaconState, epoch: Epoch): Eth2Digest =
func get_block_root*(state: ForkyBeaconState, epoch: Epoch): Eth2Digest =
## Return the block root at the start of a recent ``epoch``.
get_block_root_at_slot(state, compute_start_slot_at_epoch(epoch))
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_total_balance
template get_total_balance(
state: SomeBeaconState, validator_indices: untyped): Gwei =
state: ForkyBeaconState, validator_indices: untyped): Gwei =
## Return the combined effective balance of the ``indices``.
## ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
## Math safe up to ~10B ETH, afterwhich this overflows uint64.
@ -350,7 +335,7 @@ func is_eligible_for_activation_queue*(validator: Validator): bool =
validator.effective_balance == MAX_EFFECTIVE_BALANCE
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#is_eligible_for_activation
func is_eligible_for_activation*(state: SomeBeaconState, validator: Validator):
func is_eligible_for_activation*(state: ForkyBeaconState, validator: Validator):
bool =
## Check if ``validator`` is eligible for activation.
@ -361,7 +346,7 @@ func is_eligible_for_activation*(state: SomeBeaconState, validator: Validator):
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#is_valid_indexed_attestation
proc is_valid_indexed_attestation*(
state: SomeBeaconState, indexed_attestation: SomeIndexedAttestation,
state: ForkyBeaconState, indexed_attestation: SomeIndexedAttestation,
flags: UpdateFlags): Result[void, cstring] =
## Check if ``indexed_attestation`` is not empty, has sorted and unique
## indices and has a valid aggregate signature.
@ -398,7 +383,7 @@ proc is_valid_indexed_attestation*(
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_attesting_indices
func get_attesting_indices*(state: SomeBeaconState,
func get_attesting_indices*(state: ForkyBeaconState,
data: AttestationData,
bits: CommitteeValidatorsBits,
cache: var StateCache): seq[ValidatorIndex] =
@ -419,8 +404,21 @@ func get_attesting_indices*(state: SomeBeaconState,
res
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]
withState(state):
for vidx in state.data.get_attesting_indices(data, bits, cache):
idxBuf.add vidx
idxBuf
proc is_valid_indexed_attestation*(
state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
state: ForkyBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] =
# This is a variation on `is_valid_indexed_attestation` that works directly
# with an attestation instead of first constructing an `IndexedAttestation`
@ -524,7 +522,7 @@ func get_attestation_participation_flag_indices(state: altair.BeaconState | merg
# better to centralize around that if feasible
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_total_active_balance
func get_total_active_balance*(state: SomeBeaconState, cache: var StateCache): Gwei =
func get_total_active_balance*(state: ForkyBeaconState, cache: var StateCache): Gwei =
## Return the combined effective balance of the active validators.
# Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei
# minimum to avoid divisions by zero.
@ -555,7 +553,7 @@ func get_base_reward(
# https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/phase0/beacon-chain.md#attestations
proc check_attestation*(
state: SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
state: ForkyBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] =
## Check that an attestation follows the rules of being included in the state
## at the current slot. When acting as a proposer, the same rules need to
@ -589,7 +587,7 @@ proc check_attestation*(
ok()
proc process_attestation*(
state: var SomeBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
state: var ForkyBeaconState, attestation: SomeAttestation, flags: UpdateFlags,
base_reward_per_increment: Gwei, cache: var StateCache):
Result[void, cstring] {.nbench.} =
# In the spec, attestation validation is mixed with state mutation, so here

View File

@ -543,3 +543,14 @@ template hash*(x: LightClientUpdate): Hash =
func clear*(info: var EpochInfo) =
info.validators.setLen(0)
info.balances = UnslashedParticipatingBalances()
template asSigned*(x: SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock):
SignedBeaconBlock =
isomorphicCast[SignedBeaconBlock](x)
template asSigVerified*(x: SignedBeaconBlock | TrustedSignedBeaconBlock): SigVerifiedSignedBeaconBlock =
isomorphicCast[SigVerifiedSignedBeaconBlock](x)
template asTrusted*(
x: SignedBeaconBlock | SigVerifiedSignedBeaconBlock): TrustedSignedBeaconBlock =
isomorphicCast[TrustedSignedBeaconBlock](x)

View File

@ -734,6 +734,7 @@ template assignClone*[T: not ref](x: T): ref T =
# This is a bit of a mess: if x is an rvalue (temporary), RVO kicks in for
# newClone - if it's not, `genericAssign` will be called which is ridiculously
# slow - so `assignClone` should be used when RVO doesn't work. sigh.
mixin assign
let res = new typeof(x) # TODO safe to do noinit here?
assign(res[], x)
res
@ -938,6 +939,12 @@ func getSizeofSig(x: auto, n: int = 0): seq[(string, int, int)] =
# is still better to keep field names parallel.
result.add((name.replace("blob", "data"), sizeof(value), n))
## At the GC-level, the GC is type-agnostic; it's all type-erased so
## casting between seq[Attestation] and seq[TrustedAttestation] will
## not disrupt GC operations.
##
## These SHOULD be used in function calls to avoid expensive temporary.
## see https://github.com/status-im/nimbus-eth2/pull/2250#discussion_r562010679
template isomorphicCast*[T, U](x: U): T =
# Each of these pairs of types has ABI-compatible memory representations.
static:

View File

@ -167,9 +167,6 @@ type
data*: BeaconState
root*: Eth2Digest # hash_tree_root(data)
SomeBeaconState* = BeaconState | altair.BeaconState | phase0.BeaconState
SomeHashedBeaconState* = HashedBeaconState | altair.HashedBeaconState | phase0.HashedBeaconState
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconblock
BeaconBlock* = object
## For each slot, a proposer is chosen from the validator pool to propose
@ -397,3 +394,14 @@ func shortLog*(v: SomeSignedBeaconBlock): auto =
blck: shortLog(v.message),
signature: shortLog(v.signature)
)
template asSigned*(x: SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock):
SignedBeaconBlock =
isomorphicCast[SignedBeaconBlock](x)
template asSigVerified*(x: SignedBeaconBlock | TrustedSignedBeaconBlock): SigVerifiedSignedBeaconBlock =
isomorphicCast[SigVerifiedSignedBeaconBlock](x)
template asTrusted*(
x: SignedBeaconBlock | SigVerifiedSignedBeaconBlock): TrustedSignedBeaconBlock =
isomorphicCast[TrustedSignedBeaconBlock](x)

View File

@ -289,3 +289,14 @@ func shortLog*(v: SomeSignedBeaconBlock): auto =
blck: shortLog(v.message),
signature: shortLog(v.signature)
)
template asSigned*(x: SigVerifiedSignedBeaconBlock | TrustedSignedBeaconBlock):
SignedBeaconBlock =
isomorphicCast[SignedBeaconBlock](x)
template asSigVerified*(x: SignedBeaconBlock | TrustedSignedBeaconBlock): SigVerifiedSignedBeaconBlock =
isomorphicCast[SigVerifiedSignedBeaconBlock](x)
template asTrusted*(
x: SignedBeaconBlock | SigVerifiedSignedBeaconBlock): TrustedSignedBeaconBlock =
isomorphicCast[TrustedSignedBeaconBlock](x)

View File

@ -5,7 +5,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import std/typetraits
import stew/[results, base10, byteutils, endians2], presto/common,
import stew/[assign2, results, base10, byteutils, endians2], presto/common,
libp2p/peerid, serialization,
json_serialization, json_serialization/std/[options, net, sets],
nimcrypto/utils as ncrutils
@ -821,9 +821,10 @@ proc writeValue*(writer: var JsonWriter[RestJson],
writer.writeField("data", value.mergeData)
writer.endRecord()
# ForkedBeaconState
# ForkedHashedBeaconState is used where a `ForkedBeaconState` normally would
# be used, mainly because caching the hash early on is easier to do
proc readValue*(reader: var JsonReader[RestJson],
value: var ForkedBeaconState) {.
value: var ForkedHashedBeaconState) {.
raises: [IOError, SerializationError, Defect].} =
var
version: Option[BeaconStateFork]
@ -854,53 +855,58 @@ proc readValue*(reader: var JsonReader[RestJson],
if data.isNone():
reader.raiseUnexpectedValue("Field data is missing")
# Use a temporary to avoid stack instances and `value` mutation in case of
# exception
let
tmp = (ref ForkedHashedBeaconState)(kind: version.get())
template toValue(field: untyped) =
if tmp[].kind == value.kind:
assign(value.field, tmp[].field)
else:
value = tmp[] # slow, but rare (hopefully)
value.field.root = hash_tree_root(value.field.data)
case version.get():
of BeaconStateFork.Phase0:
let res =
try:
some(RestJson.decode(string(data.get()), phase0.BeaconState,
requireAllFields = true))
except SerializationError:
none[phase0.BeaconState]()
if res.isNone():
try:
tmp[].phase0Data.data = RestJson.decode(
string(data.get()), phase0.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect phase0 beacon state format")
value = ForkedBeaconState.init(res.get())
of BeaconStateFork.Altair:
let res =
try:
some(RestJson.decode(string(data.get()), altair.BeaconState,
requireAllFields = true))
except SerializationError:
none[altair.BeaconState]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect altair beacon state format")
value = ForkedBeaconState.init(res.get())
of BeaconStateFork.Merge:
let res =
try:
some(RestJson.decode(string(data.get()), merge.BeaconState,
requireAllFields = true))
except SerializationError:
none[merge.BeaconState]()
if res.isNone():
reader.raiseUnexpectedValue("Incorrect merge beacon state format")
value = ForkedBeaconState.init(res.get())
proc writeValue*(writer: var JsonWriter[RestJson], value: ForkedBeaconState) {.
toValue(phase0Data)
of BeaconStateFork.Altair:
try:
tmp[].altairData.data = RestJson.decode(
string(data.get()), altair.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect altair beacon state format")
toValue(altairData)
of BeaconStateFork.Merge:
try:
tmp[].mergeData.data = RestJson.decode(
string(data.get()), merge.BeaconState, requireAllFields = true)
except SerializationError:
reader.raiseUnexpectedValue("Incorrect altair beacon state format")
toValue(mergeData)
proc writeValue*(writer: var JsonWriter[RestJson], value: ForkedHashedBeaconState) {.
raises: [IOError, Defect].} =
writer.beginRecord()
case value.kind
of BeaconStateFork.Phase0:
writer.writeField("version", "phase0")
writer.writeField("data", value.phase0Data)
writer.writeField("data", value.phase0Data.data)
of BeaconStateFork.Altair:
writer.writeField("version", "altair")
writer.writeField("data", value.altairData)
writer.writeField("data", value.altairData.data)
of BeaconStateFork.Merge:
writer.writeField("version", "merge")
when false:
# TODO SerializationError
writer.writeField("data", value.mergeData)
writer.writeField("data", value.mergeData.data)
writer.endRecord()
# SyncSubcommitteeIndex

View File

@ -20,7 +20,7 @@ proc getStatePlain*(state_id: StateIdent): RestPlainResponse {.
## https://ethereum.github.io/beacon-APIs/#/Beacon/getState
proc getState*(client: RestClientRef, state_id: StateIdent,
restAccept = ""): Future[ForkedBeaconState] {.async.} =
restAccept = ""): Future[phase0.BeaconState] {.async.} =
let resp =
if len(restAccept) > 0:
await client.getStatePlain(state_id, restAcceptType = restAccept)
@ -38,7 +38,7 @@ proc getState*(client: RestClientRef, state_id: StateIdent,
if res.isErr():
raise newException(RestError, $res.error())
res.get()
ForkedBeaconState.init(state.data)
state.data
of "application/octet-stream":
let state =
block:
@ -47,7 +47,7 @@ proc getState*(client: RestClientRef, state_id: StateIdent,
if res.isErr():
raise newException(RestError, $res.error())
res.get()
ForkedBeaconState.init(state)
state
else:
raise newException(RestError, "Unsupported content-type")
of 400, 404, 500:
@ -79,7 +79,7 @@ proc getStateV2Plain*(state_id: StateIdent): RestPlainResponse {.
proc getStateV2*(client: RestClientRef, state_id: StateIdent,
forks: array[2, Fork],
restAccept = ""): Future[ForkedBeaconState] {.async.} =
restAccept = ""): Future[ForkedHashedBeaconState] {.async.} =
let resp =
if len(restAccept) > 0:
await client.getStateV2Plain(state_id, restAcceptType = restAccept)
@ -106,23 +106,25 @@ proc getStateV2*(client: RestClientRef, state_id: StateIdent,
raise newException(RestError, $res.error())
res.get()
if header.slot.epoch() < forks[1].epoch:
let state =
let state = newClone(
block:
let res = decodeBytes(GetPhase0StateSszResponse, resp.data,
resp.contentType)
if res.isErr():
raise newException(RestError, $res.error())
res.get()
ForkedBeaconState.init(state)
let res = newClone(decodeBytes(
GetPhase0StateSszResponse, resp.data, resp.contentType))
if res[].isErr():
raise newException(RestError, $res[].error())
res[].get())
ForkedHashedBeaconState.init(phase0.HashedBeaconState(
data: state[], root: hash_tree_root(state[])))
else:
let blck =
let state = newClone(
block:
let res = decodeBytes(GetAltairStateSszResponse, resp.data,
resp.contentType)
if res.isErr():
raise newException(RestError, $res.error())
res.get()
ForkedBeaconState.init(blck)
let res = newClone(decodeBytes(
GetAltairStateSszResponse, resp.data, resp.contentType))
if res[].isErr():
raise newException(RestError, $res[].error())
res[].get())
ForkedHashedBeaconState.init(altair.HashedBeaconState(
data: state[], root: hash_tree_root(state[])))
else:
raise newException(RestError, "Unsupported content-type")
of 400, 404, 500:

View File

@ -414,7 +414,7 @@ type
GetStateResponse* = DataEnclosedObject[phase0.BeaconState]
GetBlockV2Response* = ForkedSignedBeaconBlock
GetBlockV2Header* = ForkedSignedBlockHeader
GetStateV2Response* = ForkedBeaconState
GetStateV2Response* = ForkedHashedBeaconState
GetStateV2Header* = ForkedBeaconStateHeader
GetPhase0StateSszResponse* = phase0.BeaconState
GetAltairStateSszResponse* = altair.BeaconState

View File

@ -8,15 +8,31 @@
{.push raises: [Defect].}
import
std/macros,
stew/[assign2],
chronicles,
stew/[assign2, results],
../extras,
../spec/[
beaconstate, eth2_merkleization, helpers, state_transition_block, validator],
"."/[eth2_merkleization, eth2_ssz_serialization, presets],
./datatypes/[phase0, altair, merge]
export extras, phase0, altair, eth2_merkleization
export
extras, phase0, altair, merge, eth2_merkleization, eth2_ssz_serialization,
presets
# This file contains helpers for dealing with forks - we have two ways we can
# deal with forks:
# * generics - this means using the static typing and differentiating forks
# at compile time - this is preferred in fork-specific code where the fork
# is known up-front, for example spec functions.
# * variants - this means using a variant object and determining the fork at
# runtime - this carries the obvious risk and complexity of dealing with
# runtime checking, but is of course needed for external data that may be
# of any fork kind.
#
# For generics, we define `Forky*` type classes that cover "similar" objects
# across forks - for variants, they're called `Forked*` instead.
# See withXxx and `init` for convenient ways of moving between these two worlds.
# A clever programmer would use templates, macros and dark magic to create all
# these types and converters :)
type
BeaconStateFork* {.pure.} = enum
@ -24,49 +40,70 @@ type
Altair,
Merge
ForkyBeaconState* =
phase0.BeaconState |
altair.BeaconState |
merge.BeaconState
ForkyHashedBeaconState* =
phase0.HashedBeaconState |
altair.HashedBeaconState |
merge.HashedBeaconState
ForkedHashedBeaconState* = object
case kind*: BeaconStateFork
of BeaconStateFork.Phase0: phase0Data*: phase0.HashedBeaconState
of BeaconStateFork.Altair: altairData*: altair.HashedBeaconState
of BeaconStateFork.Merge: mergeData*: merge.HashedBeaconState
ForkedBeaconState* = object
case kind*: BeaconStateFork
of BeaconStateFork.Phase0: phase0Data*: phase0.BeaconState
of BeaconStateFork.Altair: altairData*: altair.BeaconState
of BeaconStateFork.Merge: mergeData*: merge.BeaconState
BeaconBlockFork* {.pure.} = enum
Phase0
Altair
Merge
ForkyBeaconBlock* =
phase0.BeaconBlock |
altair.BeaconBlock |
merge.BeaconBlock
ForkyTrustedBeaconBlock* =
phase0.TrustedBeaconBlock |
altair.TrustedBeaconBlock |
merge.TrustedBeaconBlock
ForkedBeaconBlock* = object
case kind*: BeaconBlockFork
of BeaconBlockFork.Phase0:
phase0Data*: phase0.BeaconBlock
of BeaconBlockFork.Altair:
altairData*: altair.BeaconBlock
of BeaconBlockFork.Merge:
mergeData*: merge.BeaconBlock
of BeaconBlockFork.Phase0: phase0Data*: phase0.BeaconBlock
of BeaconBlockFork.Altair: altairData*: altair.BeaconBlock
of BeaconBlockFork.Merge: mergeData*: merge.BeaconBlock
ForkedTrustedBeaconBlock* = object
case kind*: BeaconBlockFork
of BeaconBlockFork.Phase0: phase0Data*: phase0.TrustedBeaconBlock
of BeaconBlockFork.Altair: altairData*: altair.TrustedBeaconBlock
of BeaconBlockFork.Merge: mergeData*: merge.TrustedBeaconBlock
ForkySignedBeaconBlock* =
phase0.SignedBeaconBlock |
altair.SignedBeaconBlock |
merge.SignedBeaconBlock
ForkedSignedBeaconBlock* = object
case kind*: BeaconBlockFork
of BeaconBlockFork.Phase0:
phase0Data*: phase0.SignedBeaconBlock
of BeaconBlockFork.Altair:
altairData*: altair.SignedBeaconBlock
of BeaconBlockFork.Merge:
mergeData*: merge.SignedBeaconBlock
of BeaconBlockFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
of BeaconBlockFork.Altair: altairData*: altair.SignedBeaconBlock
of BeaconBlockFork.Merge: mergeData*: merge.SignedBeaconBlock
ForkyTrustedSignedBeaconBlock* =
phase0.TrustedSignedBeaconBlock |
altair.TrustedSignedBeaconBlock |
merge.TrustedSignedBeaconBlock
ForkedTrustedSignedBeaconBlock* = object
case kind*: BeaconBlockFork
of BeaconBlockFork.Phase0:
phase0Data*: phase0.TrustedSignedBeaconBlock
of BeaconBlockFork.Altair:
altairData*: altair.TrustedSignedBeaconBlock
of BeaconBlockFork.Merge:
mergeData*: merge.TrustedSignedBeaconBlock
of BeaconBlockFork.Phase0: phase0Data*: phase0.TrustedSignedBeaconBlock
of BeaconBlockFork.Altair: altairData*: altair.TrustedSignedBeaconBlock
of BeaconBlockFork.Merge: mergeData*: merge.TrustedSignedBeaconBlock
EpochInfoFork* {.pure.} = enum
Phase0
@ -74,10 +111,8 @@ type
ForkedEpochInfo* = object
case kind*: EpochInfoFork
of EpochInfoFork.Phase0:
phase0Data*: phase0.EpochInfo
of EpochInfoFork.Altair:
altairData*: altair.EpochInfo
of EpochInfoFork.Phase0: phase0Data*: phase0.EpochInfo
of EpochInfoFork.Altair: altairData*: altair.EpochInfo
ForkyEpochInfo* = phase0.EpochInfo | altair.EpochInfo
@ -86,7 +121,22 @@ type
altair*: ForkDigest
merge*: ForkDigest
ForkDigestsRef* = ref ForkDigests
template toFork*[T: phase0.BeaconState | phase0.HashedBeaconState](
t: type T): BeaconStateFork =
BeaconStateFork.Phase0
template toFork*[T: altair.BeaconState | altair.HashedBeaconState](
t: type T): BeaconStateFork =
BeaconStateFork.Altair
template toFork*[T: merge.BeaconState | merge.HashedBeaconState](
t: type T): BeaconStateFork =
BeaconStateFork.Merge
template init*(T: type ForkedHashedBeaconState, data: phase0.HashedBeaconState): T =
T(kind: BeaconStateFork.Phase0, phase0Data: data)
template init*(T: type ForkedHashedBeaconState, data: altair.HashedBeaconState): T =
T(kind: BeaconStateFork.Altair, altairData: data)
template init*(T: type ForkedHashedBeaconState, data: merge.HashedBeaconState): T =
T(kind: BeaconStateFork.Merge, mergeData: data)
template init*(T: type ForkedBeaconBlock, blck: phase0.BeaconBlock): T =
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
@ -95,6 +145,13 @@ template init*(T: type ForkedBeaconBlock, blck: altair.BeaconBlock): T =
template init*(T: type ForkedBeaconBlock, blck: merge.BeaconBlock): T =
T(kind: BeaconBlockFork.Merge, mergeData: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: altair.TrustedBeaconBlock): T =
T(kind: BeaconBlockFork.Altair, altairData: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: merge.TrustedBeaconBlock): T =
T(kind: BeaconBlockFork.Merge, mergeData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: phase0.SignedBeaconBlock): T =
T(kind: BeaconBlockFork.Phase0, phase0Data: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: altair.SignedBeaconBlock): T =
@ -102,37 +159,19 @@ template init*(T: type ForkedSignedBeaconBlock, blck: altair.SignedBeaconBlock):
template init*(T: type ForkedSignedBeaconBlock, blck: merge.SignedBeaconBlock): T =
T(kind: BeaconBlockFork.Merge, mergeData: blck)
template init*(T: type ForkedBeaconState, state: phase0.BeaconState): T =
T(kind: BeaconStateFork.Phase0, phase0Data: state)
template init*(T: type ForkedBeaconState, state: altair.BeaconState): T =
T(kind: BeaconStateFork.Altair, altairData: state)
template init*(T: type ForkedBeaconState, state: merge.BeaconState): T =
T(kind: BeaconStateFork.Merge, mergeData: state)
template init*(T: type ForkedBeaconState, state: ForkedHashedBeaconState): T =
case state.kind
of BeaconStateFork.Phase0:
T(kind: BeaconStateFork.Phase0,
phase0Data: state.phase0Data.data)
of BeaconStateFork.Altair:
T(kind: BeaconStateFork.Altair,
altairData: state.altairData.data)
of BeaconStateFork.Merge:
T(kind: BeaconStateFork.Merge,
mergeData: state.mergeData.data)
template init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
blockRoot: Eth2Digest, signature: ValidatorSig): T =
case forked.kind
of BeaconBlockFork.Phase0:
T(kind: BeaconBlockFork.Phase0,
phase0Data: phase0.SignedBeaconBlock(message: forked.phase0Data,
root: blockRoot,
signature: signature))
root: blockRoot,
signature: signature))
of BeaconBlockFork.Altair:
T(kind: BeaconBlockFork.Altair,
altairData: altair.SignedBeaconBlock(message: forked.altairData,
root: blockRoot,
signature: signature))
root: blockRoot,
signature: signature))
of BeaconBlockFork.Merge:
T(kind: BeaconBlockFork.Merge,
mergeData: merge.SignedBeaconBlock(message: forked.mergeData,
@ -146,13 +185,21 @@ template init*(T: type ForkedTrustedSignedBeaconBlock, blck: altair.TrustedSigne
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: merge.TrustedSignedBeaconBlock): T =
T(kind: BeaconBlockFork.Merge, mergeData: blck)
template toFork*[T: phase0.TrustedSignedBeaconBlock](
t: type T): BeaconBlockFork =
BeaconBlockFork.Phase0
template toFork*[T: altair.TrustedSignedBeaconBlock](
t: type T): BeaconBlockFork =
BeaconBlockFork.Altair
template toFork*[T: merge.TrustedSignedBeaconBlock](
t: type T): BeaconBlockFork =
BeaconBlockFork.Merge
template init*(T: type ForkedEpochInfo, info: phase0.EpochInfo): T =
T(kind: EpochInfoFork.Phase0, phase0Data: info)
template init*(T: type ForkedEpochInfo, info: altair.EpochInfo): T =
T(kind: EpochInfoFork.Altair, altairData: info)
# State-related functionality based on ForkedHashedBeaconState instead of HashedBeaconState
template withState*(x: ForkedHashedBeaconState, body: untyped): untyped =
case x.kind
of BeaconStateFork.Merge:
@ -190,7 +237,6 @@ template withEpochInfo*(
template info: untyped {.inject.} = x.altairData
body
# Dispatch functions
func assign*(tgt: var ForkedHashedBeaconState, src: ForkedHashedBeaconState) =
if tgt.kind == src.kind:
case tgt.kind
@ -222,93 +268,6 @@ func getStateRoot*(x: ForkedHashedBeaconState): Eth2Digest =
func setStateRoot*(x: var ForkedHashedBeaconState, root: Eth2Digest) =
withState(x): state.root = root
func hash_tree_root*(x: ForkedHashedBeaconState): Eth2Digest =
# This is a bit of a hack because we drill into data here, unlike other places
withState(x): hash_tree_root(state.data)
func get_active_validator_indices_len*(
state: ForkedHashedBeaconState; epoch: Epoch): uint64 =
withState(state):
get_active_validator_indices_len(state.data, epoch)
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.
withState(state):
get_beacon_committee(state.data, slot, index, cache)
func get_beacon_committee_len*(
state: ForkedHashedBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): uint64 =
# This one is used by tests
withState(state):
get_beacon_committee_len(state.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``.
withState(state):
get_committee_count_per_slot(state.data, epoch, cache)
func get_beacon_proposer_index*(state: ForkedHashedBeaconState,
cache: var StateCache, slot: Slot):
Option[ValidatorIndex] =
withState(state):
get_beacon_proposer_index(state.data, cache, slot)
func get_shuffled_active_validator_indices*(
cache: var StateCache, state: ForkedHashedBeaconState, epoch: Epoch):
seq[ValidatorIndex] =
withState(state):
cache.get_shuffled_active_validator_indices(state.data, epoch)
# https://github.com/ethereum/consensus-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``.
withState(state):
get_block_root_at_slot(state.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]
withState(state):
for vidx in state.data.get_attesting_indices(data, bits, cache):
idxBuf.add vidx
idxBuf
proc check_attester_slashing*(
state: var ForkedHashedBeaconState; attester_slashing: SomeAttesterSlashing;
flags: UpdateFlags): Result[seq[ValidatorIndex], cstring] =
withState(state):
check_attester_slashing(state.data, attester_slashing, flags)
proc check_proposer_slashing*(
state: var ForkedHashedBeaconState; proposer_slashing: SomeProposerSlashing;
flags: UpdateFlags): Result[void, cstring] =
withState(state):
check_proposer_slashing(state.data, proposer_slashing, flags)
proc check_voluntary_exit*(
cfg: RuntimeConfig, state: ForkedHashedBeaconState;
signed_voluntary_exit: SomeSignedVoluntaryExit;
flags: UpdateFlags): Result[void, cstring] =
withState(state):
check_voluntary_exit(cfg, state.data, signed_voluntary_exit, flags)
# Derived utilities
func stateForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): BeaconStateFork =
## Return the current fork for the given epoch.
static:
@ -326,55 +285,9 @@ func blockForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): BeaconBlockFork =
elif epoch >= cfg.ALTAIR_FORK_EPOCH: BeaconBlockFork.Altair
else: BeaconBlockFork.Phase0
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(x: ForkedHashedBeaconState): Epoch =
## Return the current epoch.
withState(x): state.data.slot.epoch
# https://github.com/ethereum/consensus-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
func init*(T: type ForkDigests,
cfg: RuntimeConfig,
genesisValidatorsRoot: Eth2Digest): T =
T(
phase0:
compute_fork_digest(cfg.GENESIS_FORK_VERSION, genesisValidatorsRoot),
altair:
compute_fork_digest(cfg.ALTAIR_FORK_VERSION, genesisValidatorsRoot),
merge:
compute_fork_digest(cfg.MERGE_FORK_VERSION, genesisValidatorsRoot),
)
template asSigned*(x: phase0.TrustedSignedBeaconBlock or phase0.SigVerifiedBeaconBlock):
phase0.SignedBeaconBlock =
isomorphicCast[phase0.SignedBeaconBlock](x)
template asSigned*(x: altair.TrustedSignedBeaconBlock or altair.SigVerifiedBeaconBlock):
altair.SignedBeaconBlock =
isomorphicCast[altair.SignedBeaconBlock](x)
template asSigned*(x: ForkedTrustedSignedBeaconBlock): ForkedSignedBeaconBlock =
isomorphicCast[ForkedSignedBeaconBlock](x)
template asTrusted*(x: phase0.SignedBeaconBlock or phase0.SigVerifiedBeaconBlock):
phase0.TrustedSignedBeaconBlock =
isomorphicCast[phase0.TrustedSignedBeaconBlock](x)
template asTrusted*(x: altair.SignedBeaconBlock or altair.SigVerifiedBeaconBlock):
altair.TrustedSignedBeaconBlock =
isomorphicCast[altair.TrustedSignedBeaconBlock](x)
template asTrusted*(x: merge.SignedBeaconBlock or merge.SigVerifiedBeaconBlock):
merge.TrustedSignedBeaconBlock =
isomorphicCast[merge.TrustedSignedBeaconBlock](x)
template asTrusted*(x: ForkedSignedBeaconBlock): ForkedTrustedSignedBeaconBlock =
isomorphicCast[ForkedTrustedSignedBeaconBlock](x)
@ -453,6 +366,26 @@ template withStateAndBlck*(
template blck: untyped {.inject.} = b.phase0Data
body
func genesisFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.GENESIS_FORK_VERSION,
epoch: GENESIS_EPOCH)
func altairFork*(cfg: RuntimeConfig): Fork =
Fork(
previous_version: cfg.GENESIS_FORK_VERSION,
current_version: cfg.ALTAIR_FORK_VERSION,
epoch: cfg.ALTAIR_FORK_EPOCH)
func mergeFork*(cfg: RuntimeConfig): Fork =
# TODO in theory, the altair + merge forks could be in same epoch, so the
# previous fork version would be the GENESIS_FORK_VERSION
Fork(
previous_version: cfg.ALTAIR_FORK_VERSION,
current_version: cfg.MERGE_FORK_VERSION,
epoch: cfg.MERGE_FORK_EPOCH)
proc forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork =
case cfg.stateForkAtEpoch(epoch)
of BeaconStateFork.Merge: cfg.mergeFork
@ -478,3 +411,99 @@ func getForkSchedule*(cfg: RuntimeConfig): array[2, Fork] =
##
## NOTE: Update this procedure when new fork will be scheduled.
[cfg.genesisFork(), cfg.altairFork()]
func readSszForkedHashedBeaconState*(
data: openArray[byte], likelyFork: BeaconStateFork):
ForkedHashedBeaconState {.raises: [Defect, SszError].} =
## Helper to read a state from bytes when it's not certain what kind of state
## it is - this happens for example when loading an SSZ state from command
## line - we'll use wall time to "guess" which state to start with
# careful - `result` is used, RVO didn't seem to work without
result = ForkedHashedBeaconState(kind: likelyFork)
var tried: set[BeaconStateFork]
template readFork() =
withState(result):
try:
readSszBytes(data, state.data)
state.root = hash_tree_root(state.data)
return result
except SszError as exc:
tried.incl result.kind
readFork()
for fork in BeaconStateFork:
if fork in tried: continue
result = ForkedHashedBeaconState(kind: fork)
readFork()
raise (ref SszError)(msg: "Unable to match data to any known fork")
func readSszForkedTrustedSignedBeaconBlock*(
data: openArray[byte], likelyFork: BeaconBlockFork):
ForkedTrustedSignedBeaconBlock {.raises: [Defect, SszError].} =
## Helper to read a state from bytes when it's not certain what kind of state
## it is - this happens for example when loading an SSZ state from command
## line - we'll use wall time to "guess" which state to start with
var
res = ForkedTrustedSignedBeaconBlock(kind: likelyFork)
tried: set[BeaconBlockFork]
template readFork() =
withBlck(res):
try:
readSszBytes(data, blck)
return res
except SszError as exc:
tried.incl res.kind
readFork()
for fork in BeaconBlockFork:
if fork in tried: continue
res = ForkedTrustedSignedBeaconBlock(kind: fork)
readFork()
raise (ref SszError)(msg: "Unable to match data to any known fork")
func toBeaconBlockFork*(fork: BeaconStateFork): BeaconBlockFork =
case fork
of BeaconStateFork.Phase0: BeaconBlockFork.Phase0
of BeaconStateFork.Altair: BeaconBlockFork.Altair
of BeaconStateFork.Merge: BeaconBlockFork.Merge
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#compute_fork_data_root
func compute_fork_data_root*(current_version: Version,
genesis_validators_root: Eth2Digest): Eth2Digest =
## Return the 32-byte fork data root for the ``current_version`` and
## ``genesis_validators_root``.
## This is used primarily in signature domains to avoid collisions across
## forks/chains.
hash_tree_root(ForkData(
current_version: current_version,
genesis_validators_root: genesis_validators_root
))
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#compute_fork_digest
func compute_fork_digest*(current_version: Version,
genesis_validators_root: Eth2Digest): ForkDigest =
## Return the 4-byte fork digest for the ``current_version`` and
## ``genesis_validators_root``.
## This is a digest primarily used for domain separation on the p2p layer.
## 4-bytes suffices for practical separation of forks/chains.
array[4, byte](result)[0..3] =
compute_fork_data_root(
current_version, genesis_validators_root).data.toOpenArray(0, 3)
func init*(T: type ForkDigests,
cfg: RuntimeConfig,
genesisValidatorsRoot: Eth2Digest): T =
T(
phase0:
compute_fork_digest(cfg.GENESIS_FORK_VERSION, genesisValidatorsRoot),
altair:
compute_fork_digest(cfg.ALTAIR_FORK_VERSION, genesisValidatorsRoot),
merge:
compute_fork_digest(cfg.MERGE_FORK_VERSION, genesisValidatorsRoot),
)

View File

@ -17,12 +17,12 @@ import
chronicles,
# Internal
./datatypes/[phase0, altair, merge],
./eth2_merkleization, ./ssz_codec
"."/[eth2_merkleization, forks, ssz_codec]
# TODO although eth2_merkleization already exports ssz_codec, *sometimes* code
# fails to compile if the export is not done here also
export
phase0, altair, eth2_merkleization, ssz_codec
forks, eth2_merkleization, ssz_codec
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#integer_squareroot
func integer_squareroot*(n: SomeInteger): SomeInteger =
@ -370,13 +370,13 @@ func is_active_validator*(validator: Validator, epoch: Epoch): bool =
validator.activation_epoch <= epoch and epoch < validator.exit_epoch
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_active_validator_indices
iterator get_active_validator_indices*(state: SomeBeaconState, epoch: Epoch):
iterator get_active_validator_indices*(state: ForkyBeaconState, epoch: Epoch):
ValidatorIndex =
for idx in 0..<state.validators.len:
if is_active_validator(state.validators[idx], epoch):
yield idx.ValidatorIndex
func get_active_validator_indices*(state: SomeBeaconState, epoch: Epoch):
func get_active_validator_indices*(state: ForkyBeaconState, epoch: Epoch):
seq[ValidatorIndex] =
## Return the sequence of active validator indices at ``epoch``.
var res = newSeqOfCap[ValidatorIndex](state.validators.len)
@ -384,20 +384,30 @@ func get_active_validator_indices*(state: SomeBeaconState, epoch: Epoch):
res.add idx.ValidatorIndex
res
func get_active_validator_indices_len*(state: SomeBeaconState, epoch: Epoch):
func get_active_validator_indices_len*(state: ForkyBeaconState, epoch: Epoch):
uint64 =
for idx in 0..<state.validators.len:
if is_active_validator(state.validators[idx], epoch):
inc result
func get_active_validator_indices_len*(
state: ForkedHashedBeaconState; epoch: Epoch): uint64 =
withState(state):
get_active_validator_indices_len(state.data, epoch)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(state: SomeBeaconState): Epoch =
func get_current_epoch*(state: ForkyBeaconState): Epoch =
## Return the current epoch.
doAssert state.slot >= GENESIS_SLOT, $state.slot
compute_epoch_at_slot(state.slot)
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_current_epoch
func get_current_epoch*(state: ForkedHashedBeaconState): Epoch =
## Return the current epoch.
withState(state): state.data.slot.epoch
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_randao_mix
func get_randao_mix*(state: SomeBeaconState, epoch: Epoch): Eth2Digest =
func get_randao_mix*(state: ForkyBeaconState, epoch: Epoch): Eth2Digest =
## Returns the randao mix at a recent ``epoch``.
state.randao_mixes[epoch mod EPOCHS_PER_HISTORICAL_VECTOR]
@ -421,29 +431,6 @@ func uint_to_bytes4*(x: uint64): array[4, byte] =
result[2] = ((x shr 16) and 0xff).byte
result[3] = ((x shr 24) and 0xff).byte
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#compute_fork_data_root
func compute_fork_data_root(current_version: Version,
genesis_validators_root: Eth2Digest): Eth2Digest =
## Return the 32-byte fork data root for the ``current_version`` and
## ``genesis_validators_root``.
## This is used primarily in signature domains to avoid collisions across
## forks/chains.
hash_tree_root(ForkData(
current_version: current_version,
genesis_validators_root: genesis_validators_root
))
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#compute_fork_digest
func compute_fork_digest*(current_version: Version,
genesis_validators_root: Eth2Digest): ForkDigest =
## Return the 4-byte fork digest for the ``current_version`` and
## ``genesis_validators_root``.
## This is a digest primarily used for domain separation on the p2p layer.
## 4-bytes suffices for practical separation of forks/chains.
array[4, byte](result)[0..3] =
compute_fork_data_root(
current_version, genesis_validators_root).data.toOpenArray(0, 3)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#compute_domain
func compute_domain*(
domain_type: DomainType,
@ -471,7 +458,7 @@ func get_domain*(
compute_domain(domain_type, fork_version, genesis_validators_root)
func get_domain*(
state: SomeBeaconState, domain_type: DomainType, epoch: Epoch): Eth2Domain =
state: ForkyBeaconState, domain_type: DomainType, epoch: Epoch): Eth2Domain =
## Return the signature domain (fork version concatenated with domain type)
## of a message.
get_domain(state.fork, domain_type, epoch, state.genesis_validators_root)
@ -487,7 +474,7 @@ func compute_signing_root*(ssz_object: auto, domain: Eth2Domain): Eth2Digest =
hash_tree_root(domain_wrapped_object)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_seed
func get_seed*(state: SomeBeaconState, epoch: Epoch, domain_type: DomainType):
func get_seed*(state: ForkyBeaconState, epoch: Epoch, domain_type: DomainType):
Eth2Digest =
## Return the seed at ``epoch``.
@ -539,7 +526,7 @@ func is_execution_enabled*(
is_merge_block(state, body) or is_merge_complete(state)
# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.4/specs/merge/beacon-chain.md#compute_timestamp_at_slot
func compute_timestamp_at_slot*(state: SomeBeaconState, slot: Slot): uint64 =
func compute_timestamp_at_slot*(state: ForkyBeaconState, slot: Slot): uint64 =
# Note: This function is unsafe with respect to overflows and underflows.
let slots_since_genesis = slot - GENESIS_SLOT
state.genesis_time + slots_since_genesis * SECONDS_PER_SLOT

View File

@ -250,8 +250,7 @@ proc addAggregateAndProofSignature*(
proc collectSignatureSets*(
sigs: var seq[SignatureSet],
signed_block: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock,
signed_block: ForkySignedBeaconBlock,
validatorKeys: auto,
state: ForkedHashedBeaconState,
cache: var StateCache): Result[void, cstring] =

View File

@ -58,9 +58,9 @@ type Foo = phase0.SignedBeaconBlock | altair.SignedBeaconBlock | phase0.TrustedS
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc verify_block_signature(
#state: SomeBeaconState, signed_block: SomeSomeSignedBeaconBlock): bool {.nbench.} =
state: SomeBeaconState, signed_block: Foo): bool {.nbench.} =
#state: SomeBeaconState, signed_block: phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock): bool {.nbench.} =
#state: ForkyBeaconState, signed_block: SomeSomeSignedBeaconBlock): bool {.nbench.} =
state: ForkyBeaconState, signed_block: Foo): bool {.nbench.} =
#state: ForkyBeaconState, signed_block: phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock): bool {.nbench.} =
let
proposer_index = signed_block.message.proposer_index
if proposer_index >= state.validators.lenu64:
@ -79,7 +79,7 @@ proc verify_block_signature(
true
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc verifyStateRoot(state: SomeBeaconState, blck: phase0.BeaconBlock or phase0.SigVerifiedBeaconBlock or altair.BeaconBlock or altair.SigVerifiedBeaconBlock or merge.BeaconBlock or merge.SigVerifiedBeaconBlock or merge.TrustedBeaconBlock): bool =
proc verifyStateRoot(state: ForkyBeaconState, blck: phase0.BeaconBlock or phase0.SigVerifiedBeaconBlock or altair.BeaconBlock or altair.SigVerifiedBeaconBlock or merge.BeaconBlock or merge.SigVerifiedBeaconBlock or merge.TrustedBeaconBlock): bool =
# This is inlined in state_transition(...) in spec.
let state_root = hash_tree_root(state)
if state_root != blck.state_root:
@ -135,7 +135,7 @@ type
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
func process_slot*(
state: var SomeBeaconState, pre_state_root: Eth2Digest) {.nbench.} =
state: var ForkyBeaconState, pre_state_root: Eth2Digest) {.nbench.} =
# `process_slot` is the first stage of per-slot processing - it is run for
# every slot, including epoch slots - it does not however update the slot
# number! `pre_state_root` refers to the state root of the incoming
@ -164,7 +164,7 @@ func clear_epoch_from_cache(cache: var StateCache, epoch: Epoch) =
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
proc advance_slot(
cfg: RuntimeConfig,
state: var SomeBeaconState, previous_slot_state_root: Eth2Digest,
state: var ForkyBeaconState, previous_slot_state_root: Eth2Digest,
flags: UpdateFlags, cache: var StateCache, info: var ForkyEpochInfo) {.nbench.} =
# Do the per-slot and potentially the per-epoch processing, then bump the
# slot number - we've now arrived at the slot state on top of which a block
@ -249,7 +249,7 @@ proc process_slots*(
proc state_transition_block_aux(
cfg: RuntimeConfig,
state: var SomeHashedBeaconState,
state: var ForkyHashedBeaconState,
signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock |
phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock |
altair.SigVerifiedSignedBeaconBlock | altair.TrustedSignedBeaconBlock |

View File

@ -31,7 +31,7 @@ export extras, phase0, altair
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#block-header
func process_block_header*(
state: var SomeBeaconState, blck: SomeSomeBeaconBlock, flags: UpdateFlags,
state: var ForkyBeaconState, blck: SomeSomeBeaconBlock, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] {.nbench.} =
# Verify that the slots match
if not (blck.slot == state.slot):
@ -74,7 +74,7 @@ func `xor`[T: array](a, b: T): T =
# https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/phase0/beacon-chain.md#randao
proc process_randao(
state: var SomeBeaconState, body: SomeSomeBeaconBlockBody, flags: UpdateFlags,
state: var ForkyBeaconState, body: SomeSomeBeaconBlockBody, flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] {.nbench.} =
let
proposer_index = get_beacon_proposer_index(state, cache)
@ -106,7 +106,7 @@ proc process_randao(
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#eth1-data
func process_eth1_data(state: var SomeBeaconState, body: SomeSomeBeaconBlockBody): Result[void, cstring] {.nbench.}=
func process_eth1_data(state: var ForkyBeaconState, body: SomeSomeBeaconBlockBody): Result[void, cstring] {.nbench.}=
if not state.eth1_data_votes.add body.eth1_data:
# Count is reset in process_final_updates, so this should never happen
return err("process_eth1_data: no more room for eth1 data")
@ -125,7 +125,7 @@ func is_slashable_validator(validator: Validator, epoch: Epoch): bool =
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#proposer-slashings
proc check_proposer_slashing*(
state: var SomeBeaconState, proposer_slashing: SomeProposerSlashing,
state: var ForkyBeaconState, proposer_slashing: SomeProposerSlashing,
flags: UpdateFlags):
Result[void, cstring] {.nbench.} =
@ -166,9 +166,15 @@ proc check_proposer_slashing*(
ok()
proc check_proposer_slashing*(
state: var ForkedHashedBeaconState; proposer_slashing: SomeProposerSlashing;
flags: UpdateFlags): Result[void, cstring] =
withState(state):
check_proposer_slashing(state.data, proposer_slashing, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#proposer-slashings
proc process_proposer_slashing*(
cfg: RuntimeConfig, state: var SomeBeaconState,
cfg: RuntimeConfig, state: var ForkyBeaconState,
proposer_slashing: SomeProposerSlashing, flags: UpdateFlags,
cache: var StateCache):
Result[void, cstring] {.nbench.} =
@ -193,7 +199,7 @@ func is_slashable_attestation_data(
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#attester-slashings
proc check_attester_slashing*(
state: var SomeBeaconState,
state: var ForkyBeaconState,
attester_slashing: SomeAttesterSlashing,
flags: UpdateFlags
): Result[seq[ValidatorIndex], cstring] {.nbench.} =
@ -225,10 +231,16 @@ proc check_attester_slashing*(
ok slashed_indices
proc check_attester_slashing*(
state: var ForkedHashedBeaconState; attester_slashing: SomeAttesterSlashing;
flags: UpdateFlags): Result[seq[ValidatorIndex], cstring] =
withState(state):
check_attester_slashing(state.data, attester_slashing, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#attester-slashings
proc process_attester_slashing*(
cfg: RuntimeConfig,
state: var SomeBeaconState,
state: var ForkyBeaconState,
attester_slashing: SomeAttesterSlashing,
flags: UpdateFlags,
cache: var StateCache
@ -245,7 +257,7 @@ proc process_attester_slashing*(
ok()
proc process_deposit*(cfg: RuntimeConfig,
state: var SomeBeaconState,
state: var ForkyBeaconState,
deposit: Deposit,
flags: UpdateFlags): Result[void, cstring] {.nbench.} =
## Process an Eth1 deposit, registering a validator or increasing its balance.
@ -314,7 +326,7 @@ proc process_deposit*(cfg: RuntimeConfig,
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#voluntary-exits
proc check_voluntary_exit*(
cfg: RuntimeConfig,
state: SomeBeaconState,
state: ForkyBeaconState,
signed_voluntary_exit: SomeSignedVoluntaryExit,
flags: UpdateFlags): Result[void, cstring] {.nbench.} =
@ -364,10 +376,17 @@ proc check_voluntary_exit*(
ok()
proc check_voluntary_exit*(
cfg: RuntimeConfig, state: ForkedHashedBeaconState;
signed_voluntary_exit: SomeSignedVoluntaryExit;
flags: UpdateFlags): Result[void, cstring] =
withState(state):
check_voluntary_exit(cfg, state.data, signed_voluntary_exit, flags)
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#voluntary-exits
proc process_voluntary_exit*(
cfg: RuntimeConfig,
state: var SomeBeaconState,
state: var ForkyBeaconState,
signed_voluntary_exit: SomeSignedVoluntaryExit,
flags: UpdateFlags,
cache: var StateCache): Result[void, cstring] {.nbench.} =
@ -379,7 +398,7 @@ proc process_voluntary_exit*(
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#operations
proc process_operations(cfg: RuntimeConfig,
state: var SomeBeaconState,
state: var ForkyBeaconState,
body: SomeSomeBeaconBlockBody,
base_reward_per_increment: Gwei,
flags: UpdateFlags,

View File

@ -461,7 +461,7 @@ func get_proposer_reward(base_reward: Gwei): Gwei =
func is_in_inactivity_leak(finality_delay: uint64): bool =
finality_delay > MIN_EPOCHS_TO_INACTIVITY_PENALTY
func get_finality_delay(state: SomeBeaconState): uint64 =
func get_finality_delay(state: ForkyBeaconState): uint64 =
get_previous_epoch(state) - state.finalized_checkpoint.epoch
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#rewards-and-penalties-1
@ -746,7 +746,7 @@ func process_rewards_and_penalties(
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#registry-updates
func process_registry_updates*(
cfg: RuntimeConfig, state: var SomeBeaconState, cache: var StateCache) {.nbench.} =
cfg: RuntimeConfig, state: var ForkyBeaconState, cache: var StateCache) {.nbench.} =
## Process activation eligibility and ejections
# Make visible, e.g.,
@ -796,7 +796,7 @@ func process_registry_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#slashings
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/altair/beacon-chain.md#slashings
func process_slashings*(state: var SomeBeaconState, total_balance: Gwei) {.nbench.} =
func process_slashings*(state: var ForkyBeaconState, total_balance: Gwei) {.nbench.} =
let
epoch = get_current_epoch(state)
multiplier =
@ -824,7 +824,7 @@ func process_slashings*(state: var SomeBeaconState, total_balance: Gwei) {.nbenc
decrease_balance(state, index.ValidatorIndex, penalty)
# https://github.com/ethereum/consensus-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#eth1-data-votes-updates
func process_eth1_data_reset*(state: var SomeBeaconState) {.nbench.} =
func process_eth1_data_reset*(state: var ForkyBeaconState) {.nbench.} =
let next_epoch = get_current_epoch(state) + 1
# Reset eth1 data votes
@ -832,7 +832,7 @@ func process_eth1_data_reset*(state: var SomeBeaconState) {.nbench.} =
state.eth1_data_votes = default(type state.eth1_data_votes)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#effective-balances-updates
func process_effective_balance_updates*(state: var SomeBeaconState) {.nbench.} =
func process_effective_balance_updates*(state: var ForkyBeaconState) {.nbench.} =
# Update effective balances with hysteresis
for index in 0..<state.validators.len:
let balance = state.balances.asSeq()[index]
@ -851,14 +851,14 @@ func process_effective_balance_updates*(state: var SomeBeaconState) {.nbench.} =
MAX_EFFECTIVE_BALANCE)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#slashings-balances-updates
func process_slashings_reset*(state: var SomeBeaconState) {.nbench.} =
func process_slashings_reset*(state: var ForkyBeaconState) {.nbench.} =
let next_epoch = get_current_epoch(state) + 1
# Reset slashings
state.slashings[int(next_epoch mod EPOCHS_PER_SLASHINGS_VECTOR)] = 0.Gwei
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#randao-mixes-updates
func process_randao_mixes_reset*(state: var SomeBeaconState) {.nbench.} =
func process_randao_mixes_reset*(state: var ForkyBeaconState) {.nbench.} =
let
current_epoch = get_current_epoch(state)
next_epoch = current_epoch + 1
@ -868,7 +868,7 @@ func process_randao_mixes_reset*(state: var SomeBeaconState) {.nbench.} =
get_randao_mix(state, current_epoch)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#historical-roots-updates
func process_historical_roots_update*(state: var SomeBeaconState) {.nbench.} =
func process_historical_roots_update*(state: var ForkyBeaconState) {.nbench.} =
## Set historical root accumulator
let next_epoch = get_current_epoch(state) + 1

View File

@ -13,7 +13,7 @@ import
./datatypes/[phase0, altair, merge],
./helpers
export phase0, altair
export helpers
const
SEED_SIZE = sizeof(Eth2Digest)
@ -126,7 +126,7 @@ func shuffle_list*(input: var seq[ValidatorIndex], seed: Eth2Digest) =
shuffle
func get_shuffled_active_validator_indices*(
state: SomeBeaconState, epoch: Epoch): seq[ValidatorIndex] =
state: ForkyBeaconState, epoch: Epoch): seq[ValidatorIndex] =
# Non-spec function, to cache a data structure from which one can cheaply
# compute both get_active_validator_indexes() and get_beacon_committee().
var active_validator_indices = get_active_validator_indices(state, epoch)
@ -137,7 +137,7 @@ func get_shuffled_active_validator_indices*(
active_validator_indices
func get_shuffled_active_validator_indices*(
cache: var StateCache, state: SomeBeaconState, epoch: Epoch):
cache: var StateCache, state: ForkyBeaconState, epoch: Epoch):
var seq[ValidatorIndex] =
# `cache` comes first because of nim's borrowing rules for the `var` return -
# the `var` returns avoids copying the validator set.
@ -147,8 +147,14 @@ func get_shuffled_active_validator_indices*(
let indices = get_shuffled_active_validator_indices(state, epoch)
return cache.shuffled_active_validator_indices.mgetOrPut(epoch, indices)
func get_shuffled_active_validator_indices*(
cache: var StateCache, state: ForkedHashedBeaconState, epoch: Epoch):
seq[ValidatorIndex] =
withState(state):
cache.get_shuffled_active_validator_indices(state.data, epoch)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_active_validator_indices
func count_active_validators*(state: SomeBeaconState,
func count_active_validators*(state: ForkyBeaconState,
epoch: Epoch,
cache: var StateCache): uint64 =
cache.get_shuffled_active_validator_indices(state, epoch).lenu64
@ -159,7 +165,7 @@ func get_committee_count_per_slot*(num_active_validators: uint64): uint64 =
num_active_validators div SLOTS_PER_EPOCH div TARGET_COMMITTEE_SIZE,
1'u64, MAX_COMMITTEES_PER_SLOT)
func get_committee_count_per_slot*(state: SomeBeaconState,
func get_committee_count_per_slot*(state: ForkyBeaconState,
epoch: Epoch,
cache: var StateCache): uint64 =
## Return the number of committees at ``slot``.
@ -171,13 +177,19 @@ func get_committee_count_per_slot*(state: SomeBeaconState,
# Otherwise, get_beacon_committee(...) cannot access some committees.
doAssert (SLOTS_PER_EPOCH * MAX_COMMITTEES_PER_SLOT) >= uint64(result)
iterator committee_indices_per_slot*(state: SomeBeaconState,
func get_committee_count_per_slot*(state: ForkedHashedBeaconState,
epoch: Epoch,
cache: var StateCache): uint64 =
withState(state):
get_committee_count_per_slot(state.data, epoch, cache)
iterator committee_indices_per_slot*(state: ForkyBeaconState,
epoch: Epoch,
cache: var StateCache): CommitteeIndex =
for idx in 0'u64 ..< get_committee_count_per_slot(state, epoch, cache):
yield CommitteeIndex.verifiedValue(idx)
func get_committee_count_per_slot*(state: SomeBeaconState,
func get_committee_count_per_slot*(state: ForkyBeaconState,
slot: Slot,
cache: var StateCache): uint64 =
get_committee_count_per_slot(state, slot.compute_epoch_at_slot, cache)
@ -190,11 +202,16 @@ func get_previous_epoch*(current_epoch: Epoch): Epoch =
else:
current_epoch - 1
func get_previous_epoch*(state: SomeBeaconState): Epoch =
func get_previous_epoch*(state: ForkyBeaconState): Epoch =
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
# Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
get_previous_epoch(get_current_epoch(state))
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_previous_epoch
func get_previous_epoch*(state: ForkedHashedBeaconState): Epoch =
## Return the previous epoch (unless the current epoch is ``GENESIS_EPOCH``).
get_previous_epoch(get_current_epoch(state))
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#compute_committee
func compute_committee_slice*(
active_validators, index, count: uint64): Slice[int] =
@ -241,7 +258,7 @@ func compute_committee_len*(
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_beacon_committee
iterator get_beacon_committee*(
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
state: ForkyBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): ValidatorIndex =
## Return the beacon committee at ``slot`` for ``index``.
let
@ -255,7 +272,7 @@ iterator get_beacon_committee*(
): yield idx
func get_beacon_committee*(
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
state: ForkyBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): seq[ValidatorIndex] =
## Return the beacon committee at ``slot`` for ``index``.
let
@ -268,9 +285,20 @@ func get_beacon_committee*(
committees_per_slot * SLOTS_PER_EPOCH
)
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.
withState(state):
get_beacon_committee(state.data, slot, index, cache)
# https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/phase0/beacon-chain.md#get_beacon_committee
func get_beacon_committee_len*(
state: SomeBeaconState, slot: Slot, index: CommitteeIndex,
state: ForkyBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): uint64 =
# Return the number of members in the beacon committee at ``slot`` for ``index``.
let
@ -284,6 +312,13 @@ func get_beacon_committee_len*(
committees_per_slot * SLOTS_PER_EPOCH
)
func get_beacon_committee_len*(
state: ForkedHashedBeaconState, slot: Slot, index: CommitteeIndex,
cache: var StateCache): uint64 =
# This one is used by tests
withState(state):
get_beacon_committee_len(state.data, slot, index, cache)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#compute_shuffled_index
func compute_shuffled_index*(
index: uint64, index_count: uint64, seed: Eth2Digest): uint64 =
@ -320,7 +355,7 @@ func compute_shuffled_index*(
cur_idx_permuted
# https://github.com/ethereum/consensus-specs/blob/v1.1.0/specs/phase0/beacon-chain.md#compute_proposer_index
func compute_proposer_index(state: SomeBeaconState,
func compute_proposer_index(state: ForkyBeaconState,
indices: seq[ValidatorIndex], seed: Eth2Digest): Option[ValidatorIndex] =
## Return from ``indices`` a random index sampled by effective balance.
const MAX_RANDOM_BYTE = 255
@ -348,7 +383,7 @@ func compute_proposer_index(state: SomeBeaconState,
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(
state: SomeBeaconState, cache: var StateCache, slot: Slot):
state: ForkyBeaconState, cache: var StateCache, slot: Slot):
Option[ValidatorIndex] =
cache.beacon_proposer_indices.withValue(slot, proposer) do:
return proposer[]
@ -380,10 +415,16 @@ func get_beacon_proposer_index*(
return res
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/beacon-chain.md#get_beacon_proposer_index
func get_beacon_proposer_index*(state: SomeBeaconState, cache: var StateCache):
func get_beacon_proposer_index*(state: ForkyBeaconState, cache: var StateCache):
Option[ValidatorIndex] =
get_beacon_proposer_index(state, cache, state.slot)
func get_beacon_proposer_index*(state: ForkedHashedBeaconState,
cache: var StateCache, slot: Slot):
Option[ValidatorIndex] =
withState(state):
get_beacon_proposer_index(state.data, cache, slot)
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/phase0/validator.md#aggregation-selection
func is_aggregator*(committee_len: uint64, slot_signature: ValidatorSig): bool =
let

View File

@ -10,10 +10,13 @@
import
std/[os, strformat],
chronicles,
./spec/[eth2_ssz_serialization, eth2_merkleization],
./spec/[eth2_ssz_serialization, eth2_merkleization, forks],
./spec/datatypes/[phase0, altair, merge],
./consensus_object_pools/block_pools_types
export
eth2_ssz_serialization, eth2_merkleization, forks, block_pools_types
# Dump errors are generally not fatal where used currently - the code calling
# these functions, like most code, is not exception safe
template logErrors(body: untyped) =
@ -46,14 +49,14 @@ proc dump*(dir: string, v: merge.SignedBeaconBlock) =
logErrors:
SSZ.saveFile(dir / &"block-{v.message.slot}-{shortLog(v.root)}.ssz", v)
proc dump*(dir: string, v: SomeHashedBeaconState, blck: BlockRef) =
proc dump*(dir: string, v: ForkyHashedBeaconState, blck: BlockRef) =
mixin saveFile
logErrors:
SSZ.saveFile(
dir / &"state-{v.data.slot}-{shortLog(blck.root)}-{shortLog(v.root)}.ssz",
v.data)
proc dump*(dir: string, v: SomeHashedBeaconState) =
proc dump*(dir: string, v: ForkyHashedBeaconState) =
mixin saveFile
logErrors:
SSZ.saveFile(

View File

@ -152,7 +152,7 @@ proc runFullTransition*(dir, preState, blocksPrefix: string, blocksQty: int, ski
phase0Data: phase0.HashedBeaconState(data: parseSSZ(prePath, phase0.BeaconState)),
kind: BeaconStateFork.Phase0
)
setStateRoot(state[], hash_tree_root(state[]))
setStateRoot(state[], hash_tree_root(state[].phase0Data.data))
for i in 0 ..< blocksQty:
let blockPath = dir / blocksPrefix & $i & ".ssz"
@ -177,7 +177,7 @@ proc runProcessSlots*(dir, preState: string, numSlots: uint64) =
phase0Data: phase0.HashedBeaconState(
data: parseSSZ(prePath, phase0.BeaconState)),
kind: BeaconStateFork.Phase0)
setStateRoot(state[], hash_tree_root(state[]))
setStateRoot(state[], hash_tree_root(state[].phase0Data.data))
# Shouldn't necessarily assert, because nbench can run test suite
discard process_slots(

View File

@ -89,7 +89,7 @@ proc doTransition(conf: NcliConf) =
blckX = SSZ.loadFile(conf.blck, phase0.SignedBeaconBlock)
flags = if not conf.verifyStateRoot: {skipStateRootValidation} else: {}
setStateRoot(stateY[], hash_tree_root(stateY[]))
setStateRoot(stateY[], hash_tree_root(stateY[].phase0Data.data))
var
cache = StateCache()
@ -117,7 +117,7 @@ proc doSlots(conf: NcliConf) =
kind: BeaconStateFork.Phase0
)
setStateRoot(stateY[], hash_tree_root(stateY[]))
setStateRoot(stateY[], hash_tree_root(stateY[].phase0Data.data))
var
cache = StateCache()
@ -147,7 +147,9 @@ proc doSSZ(conf: NcliConf) =
if cmpIgnoreCase(ext, ".ssz") == 0:
SSZ.loadFile(file, t)
elif cmpIgnoreCase(ext, ".json") == 0:
JSON.loadFile(file, t)
# JSON.loadFile(file, t)
echo "TODO needs porting to RestJson"
quit 1
else:
echo "Unknown file type: ", ext
quit 1

View File

@ -7,7 +7,7 @@ import
blockchain_dag, forkedbeaconstate_dbhelpers],
../beacon_chain/spec/datatypes/phase0,
../beacon_chain/spec/[
forks, helpers, state_transition, state_transition_epoch],
beaconstate, helpers, state_transition, state_transition_epoch, validator],
../beacon_chain/sszdump,
../research/simutils, ./e2store
@ -183,7 +183,7 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
for b in 0..<blockRefs.len:
withTimer(timers[tLoadBlock]):
blocks.add db.getBlock(blockRefs[blockRefs.len - b - 1].root).get()
blocks.add db.getPhase0Block(blockRefs[blockRefs.len - b - 1].root).get()
let state = newClone(dag.headState)
@ -233,7 +233,7 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
doAssert dbBenchmark.getState(getStateRoot(state[].data), loadedState[], noRollback)
if getStateField(state[].data, slot).epoch mod 16 == 0:
doAssert hash_tree_root(state[].data) == hash_tree_root(loadedState[])
doAssert hash_tree_root(state[].data.phase0Data.data) == hash_tree_root(loadedState[])
printTimers(false, timers)
@ -259,7 +259,7 @@ proc cmdDumpBlock(conf: DbConf) =
for blockRoot in conf.blockRootx:
try:
let root = Eth2Digest(data: hexToByteArray[32](blockRoot))
if (let blck = db.getBlock(root); blck.isSome):
if (let blck = db.getPhase0Block(root); blck.isSome):
dump("./", blck.get())
else:
echo "Couldn't load ", root
@ -276,20 +276,20 @@ proc copyPrunedDatabase(
tailBlock = db.getTailBlock()
doAssert headBlock.isOk and tailBlock.isOk
doAssert db.getBlock(headBlock.get).isOk
doAssert db.getBlock(tailBlock.get).isOk
doAssert db.getPhase0Block(headBlock.get).isOk
doAssert db.getPhase0Block(tailBlock.get).isOk
var
beaconState: ref phase0.BeaconState
finalizedEpoch: Epoch # default value of 0 is conservative/safe
prevBlockSlot = db.getBlock(db.getHeadBlock().get).get.message.slot
prevBlockSlot = db.getPhase0Block(db.getHeadBlock().get).get.message.slot
beaconState = new phase0.BeaconState
let headEpoch = db.getBlock(headBlock.get).get.message.slot.epoch
let headEpoch = db.getPhase0Block(headBlock.get).get.message.slot.epoch
# Tail states are specially addressed; no stateroot intermediary
if not db.getState(
db.getBlock(tailBlock.get).get.message.state_root, beaconState[],
db.getPhase0Block(tailBlock.get).get.message.state_root, beaconState[],
noRollback):
doAssert false, "could not load tail state"
if not dry_run:
@ -421,7 +421,7 @@ proc cmdExportEra(conf: DbConf, cfg: RuntimeConfig) =
for i in 0..<ancestors.len():
let
ancestor = ancestors[ancestors.len - 1 - i]
e2s.appendRecord(db.getBlock(ancestor.root).get()).get()
e2s.appendRecord(db.getPhase0Block(ancestor.root).get()).get()
type
# Validator performance metrics tool based on
@ -525,7 +525,7 @@ proc cmdValidatorPerf(conf: DbConf, cfg: RuntimeConfig) =
echo "TODO altair"
for bi in 0..<blockRefs.len:
blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get()
blck = db.getPhase0Block(blockRefs[blockRefs.len - bi - 1].root).get()
while getStateField(state[].data, slot) < blck.message.slot:
let
nextSlot = getStateField(state[].data, slot) + 1
@ -768,7 +768,7 @@ proc cmdValidatorDb(conf: DbConf, cfg: RuntimeConfig) =
outDb.exec("COMMIT;").expect("DB")
for bi in 0..<blockRefs.len:
blck = db.getBlock(blockRefs[blockRefs.len - bi - 1].root).get()
blck = db.getPhase0Block(blockRefs[blockRefs.len - bi - 1].root).get()
while getStateField(state[].data, slot) < blck.message.slot:
let
nextSlot = getStateField(state[].data, slot) + 1

View File

@ -9,7 +9,7 @@ proc print(t: auto, n: string, indent: int) =
for n, p in t.fieldPairs:
print(p, n, indent + 1)
print(BeaconState(), "state", 0)
print((ref BeaconState)()[], "state", 0)
echo ""

View File

@ -44,7 +44,7 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
(hashedState, _) = loadGenesis(validators, validate)
genesisBlock = get_initial_beacon_block(hashedState.data)
state = (ref ForkedHashedBeaconState)(
phase0Data: hashedState[], kind: BeaconStateFork.Phase0)
kind: BeaconStateFork.Phase0, phase0Data: hashedState[])
echo "Starting simulation..."

View File

@ -26,8 +26,8 @@ proc mockAttestationData(
if slot == state.slot:
let forkedState = (ref ForkedHashedBeaconState)(kind: BeaconStateFork.Phase0,
phase0Data: phase0.HashedBeaconState(root: hash_tree_root(state), data: state))[]
result.beacon_block_root = mockBlockForNextSlot(forkedState).phase0Data.message.parent_root
phase0Data: phase0.HashedBeaconState(root: hash_tree_root(state), data: state))
result.beacon_block_root = mockBlockForNextSlot(forkedState[]).phase0Data.message.parent_root
else:
result.beacon_block_root = get_block_root_at_slot(state, slot)

View File

@ -17,10 +17,7 @@ import
# ---------------------------------------------------------------
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/tests/core/pyspec/eth2spec/test/helpers/block.py#L26-L35
func apply_randao_reveal(
state: SomeBeaconState,
blck: var (phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock)) =
func apply_randao_reveal(state: ForkyBeaconState, blck: var ForkySignedBeaconBlock) =
doAssert state.slot <= blck.message.slot
let
proposer_index = blck.message.proposer_index.ValidatorIndex
@ -33,10 +30,7 @@ func apply_randao_reveal(
privkey).toValidatorSig()
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/tests/core/pyspec/eth2spec/test/helpers/block.py#L38-L54
func sign_block(
state: SomeBeaconState,
blck: var (phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
merge.SignedBeaconBlock)) =
func sign_block(state: ForkyBeaconState, blck: var ForkySignedBeaconBlock) =
let
proposer_index = blck.message.proposer_index.ValidatorIndex
privkey = MockPrivKeys[proposer_index]
@ -50,8 +44,7 @@ func sign_block(
privkey).toValidatorSig()
# https://github.com/ethereum/consensus-specs/blob/v1.1.3/tests/core/pyspec/eth2spec/test/helpers/execution_payload.py#L1-L31
func build_empty_execution_payload(
state: merge.BeaconState): ExecutionPayload =
func build_empty_execution_payload(state: merge.BeaconState): ExecutionPayload =
## Assuming a pre-state of the same slot, build a valid ExecutionPayload
## without any transactions.
let

View File

@ -20,7 +20,7 @@ import
../beacon_chain/consensus_object_pools/[
block_quarantine, blockchain_dag, block_clearance, attestation_pool],
../beacon_chain/spec/datatypes/phase0,
../beacon_chain/spec/[forks, state_transition, helpers],
../beacon_chain/spec/[helpers, state_transition, validator],
# Test utilities
./testutil, ./testdbutil, ./testblockutil

View File

@ -32,14 +32,14 @@ proc getAltairStateRef(db: BeaconChainDB, root: Eth2Digest):
altair.NilableBeaconStateRef =
# load beaconstate the way the block pool does it - into an existing instance
let res = (altair.BeaconStateRef)()
if db.getAltairState(root, res[], noRollback):
if db.getState(root, res[], noRollback):
return res
proc getMergeStateRef(db: BeaconChainDB, root: Eth2Digest):
merge.NilableBeaconStateRef =
# load beaconstate the way the block pool does it - into an existing instance
let res = (merge.BeaconStateRef)()
if db.getMergeState(root, res[], noRollback):
if db.getState(root, res[], noRollback):
return res
func withDigest(blck: phase0.TrustedBeaconBlock):
@ -88,7 +88,7 @@ suite "Beacon chain DB" & preset():
db = BeaconChainDB.new("", inMemory = true)
check:
db.getPhase0StateRef(Eth2Digest()).isNil
db.getBlock(Eth2Digest()).isNone
db.getPhase0Block(Eth2Digest()).isNone
test "sanity check phase 0 blocks" & preset():
var db = BeaconChainDB.new("", inMemory = true)
@ -104,7 +104,7 @@ suite "Beacon chain DB" & preset():
db.containsBlockPhase0(root)
not db.containsBlockAltair(root)
not db.containsBlockMerge(root)
db.getBlock(root).get() == signedBlock
db.getPhase0Block(root).get() == signedBlock
db.delBlock(root)
check:
@ -112,7 +112,7 @@ suite "Beacon chain DB" & preset():
not db.containsBlockPhase0(root)
not db.containsBlockAltair(root)
not db.containsBlockMerge(root)
db.getBlock(root).isErr()
db.getPhase0Block(root).isErr()
db.putStateRoot(root, signedBlock.message.slot, root)
var root2 = root
@ -200,7 +200,7 @@ suite "Beacon chain DB" & preset():
for state in testStatesPhase0:
db.putState(state[].phase0Data.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].phase0Data.data)
check:
db.containsState(root)
@ -218,7 +218,7 @@ suite "Beacon chain DB" & preset():
for state in testStatesAltair:
db.putState(state[].altairData.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].altairData.data)
check:
db.containsState(root)
@ -236,7 +236,7 @@ suite "Beacon chain DB" & preset():
for state in testStatesMerge:
db.putState(state[].mergeData.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].mergeData.data)
check:
db.containsState(root)
@ -255,7 +255,7 @@ suite "Beacon chain DB" & preset():
for state in testStatesPhase0:
db.putState(state[].phase0Data.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].phase0Data.data)
check:
db.getState(root, stateBuffer[], noRollback)
@ -275,17 +275,17 @@ suite "Beacon chain DB" & preset():
for state in testStatesAltair:
db.putState(state[].altairData.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].altairData.data)
check:
db.getAltairState(root, stateBuffer[], noRollback)
db.getState(root, stateBuffer[], noRollback)
db.containsState(root)
hash_tree_root(stateBuffer[]) == root
db.delState(root)
check:
not db.containsState(root)
not db.getAltairState(root, stateBuffer[], noRollback)
not db.getState(root, stateBuffer[], noRollback)
db.close()
@ -295,17 +295,17 @@ suite "Beacon chain DB" & preset():
for state in testStatesMerge:
db.putState(state[].mergeData.data)
let root = hash_tree_root(state[])
let root = hash_tree_root(state[].mergeData.data)
check:
db.getMergeState(root, stateBuffer[], noRollback)
db.getState(root, stateBuffer[], noRollback)
db.containsState(root)
hash_tree_root(stateBuffer[]) == root
db.delState(root)
check:
not db.containsState(root)
not db.getMergeState(root, stateBuffer[], noRollback)
not db.getState(root, stateBuffer[], noRollback)
db.close()
@ -350,7 +350,7 @@ suite "Beacon chain DB" & preset():
check:
state[].altairData.data.slot == 10.Slot
not db.getAltairState(root, state[].altairData.data, restore)
not db.getState(root, state[].altairData.data, restore)
# assign() has switched the case object fork
state[].kind == BeaconStateFork.Phase0
@ -375,7 +375,7 @@ suite "Beacon chain DB" & preset():
check:
state[].mergeData.data.slot == 10.Slot
not db.getMergeState(root, state[].mergeData.data, restore)
not db.getState(root, state[].mergeData.data, restore)
# assign() has switched the case object fork
state[].kind == BeaconStateFork.Phase0

View File

@ -265,7 +265,7 @@ suite "Block pool processing" & preset():
check:
# ensure we loaded the correct head state
dag2.head.root == b2.root
hash_tree_root(dag2.headState.data) == b2.message.state_root
getStateRoot(dag2.headState.data) == b2.message.state_root
dag2.get(b1.root).isSome()
dag2.get(b2.root).isSome()
dag2.heads.len == 1
@ -443,7 +443,7 @@ suite "chain DAG finalization tests" & preset():
dag2.head.root == dag.head.root
dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root
dag2.finalizedHead.slot == dag.finalizedHead.slot
hash_tree_root(dag2.headState.data) == hash_tree_root(dag.headState.data)
getStateRoot(dag2.headState.data) == getStateRoot(dag.headState.data)
test "orphaned epoch block" & preset():
var prestate = (ref ForkedHashedBeaconState)(kind: BeaconStateFork.Phase0)
@ -516,8 +516,10 @@ suite "chain DAG finalization tests" & preset():
assign(tmpStateData[], dag.headState)
dag.updateStateData(tmpStateData[], cur.atSlot(cur.slot), false, cache)
check:
dag.get(cur).data.phase0Data.message.state_root == getStateRoot(tmpStateData[].data)
getStateRoot(tmpStateData[].data) == hash_tree_root(tmpStateData[].data)
dag.get(cur).data.phase0Data.message.state_root ==
getStateRoot(tmpStateData[].data)
getStateRoot(tmpStateData[].data) == hash_tree_root(
tmpStateData[].data.phase0Data.data)
cur = cur.parent
let
@ -529,7 +531,7 @@ suite "chain DAG finalization tests" & preset():
dag2.head.root == dag.head.root
dag2.finalizedHead.blck.root == dag.finalizedHead.blck.root
dag2.finalizedHead.slot == dag.finalizedHead.slot
hash_tree_root(dag2.headState.data) == hash_tree_root(dag.headState.data)
getStateRoot(dag2.headState.data) == getStateRoot(dag.headState.data)
suite "Old database versions" & preset():
setup:
@ -555,7 +557,7 @@ suite "Old database versions" & preset():
db.putTailBlock(genBlock.root)
db.putHeadBlock(genBlock.root)
db.putStateRoot(genBlock.root, genState.slot, genBlock.message.state_root)
db.putGenesisBlockRoot(genBlock.root)
db.putGenesisBlock(genBlock.root)
var
dag = init(ChainDAGRef, defaultRuntimeConfig, db, {})

View File

@ -22,7 +22,7 @@ import
block_quarantine, blockchain_dag, block_clearance, attestation_pool,
sync_committee_msg_pool],
../beacon_chain/spec/datatypes/[phase0, altair],
../beacon_chain/spec/[forks, state_transition, helpers, network],
../beacon_chain/spec/[state_transition, helpers, network, validator],
../beacon_chain/validators/validator_pool,
# Test utilities
./testutil, ./testdbutil, ./testblockutil
@ -206,7 +206,7 @@ suite "Gossip validation - Extra": # Not based on preset config
check: added.isOk()
dag.updateHead(added[], quarantine)
dag
state = newClone(dag.headState.data.altairData)
state = assignClone(dag.headState.data.altairData)
syncCommitteeIdx = 0.SyncSubcommitteeIndex
syncCommittee = @(dag.syncCommitteeParticipants(state[].data.slot))

View File

@ -47,5 +47,5 @@ suite "state diff tests" & preset():
getStateField(testStates[j][], validators).len - 1],
it.getImmutableValidatorData),
diff)
check hash_tree_root(testStates[j][]) ==
check hash_tree_root(testStates[j][].phase0Data.data) ==
hash_tree_root(tmpStateApplyBase[])

View File

@ -10,7 +10,8 @@ import
options, stew/endians2,
../beacon_chain/validators/validator_pool,
../beacon_chain/spec/datatypes/merge,
../beacon_chain/spec/[helpers, keystore, signatures, state_transition, forks]
../beacon_chain/spec/[
beaconstate, helpers, keystore, signatures, state_transition, validator]
type
MockPrivKeysT = object
@ -289,15 +290,15 @@ iterator makeTestBlocks*(
attested: bool,
cfg = defaultRuntimeConfig): ForkedSignedBeaconBlock =
var
state = assignClone(state)[]
state = assignClone(state)
parent_root = parent_root
for _ in 0..<blocks:
let attestations = if attested:
makeFullAttestations(state, parent_root, getStateField(state, slot), cache)
makeFullAttestations(state[], parent_root, getStateField(state[], slot), cache)
else:
@[]
let blck = addTestBlock(
state, parent_root, cache, attestations = attestations, cfg = cfg)
state[], parent_root, cache, attestations = attestations, cfg = cfg)
yield blck
parent_root = blck.root