mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-14 16:47:21 +00:00
introduce database support for Altair (#2667)
* introduce immutable Altair BeaconState * add database support for Altair blocks and states * add tests for Altair get/put/contains/delete state * enable blockchain_dag Altair state database storing * properly return error on getting missing altair block
This commit is contained in:
parent
ae1abf24af
commit
41e0a7abc0
@ -82,13 +82,16 @@ OK: 11/11 Fail: 0/11 Skip: 0/11
|
||||
```diff
|
||||
+ empty database [Preset: mainnet] OK
|
||||
+ find ancestors [Preset: mainnet] OK
|
||||
+ sanity check blocks [Preset: mainnet] OK
|
||||
+ sanity check Altair blocks [Preset: mainnet] OK
|
||||
+ sanity check Altair states [Preset: mainnet] OK
|
||||
+ sanity check Altair states, reusing buffers [Preset: mainnet] OK
|
||||
+ sanity check genesis roundtrip [Preset: mainnet] OK
|
||||
+ sanity check phase 0 blocks [Preset: mainnet] OK
|
||||
+ sanity check phase 0 states [Preset: mainnet] OK
|
||||
+ sanity check phase 0 states, reusing buffers [Preset: mainnet] OK
|
||||
+ sanity check state diff roundtrip [Preset: mainnet] OK
|
||||
+ sanity check states [Preset: mainnet] OK
|
||||
+ sanity check states, reusing buffers [Preset: mainnet] OK
|
||||
```
|
||||
OK: 7/7 Fail: 0/7 Skip: 0/7
|
||||
OK: 10/10 Fail: 0/10 Skip: 0/10
|
||||
## Beacon state [Preset: mainnet]
|
||||
```diff
|
||||
+ Smoke test initialize_beacon_state_from_eth1 [Preset: mainnet] OK
|
||||
@ -308,4 +311,4 @@ OK: 3/3 Fail: 0/3 Skip: 0/3
|
||||
OK: 1/1 Fail: 0/1 Skip: 0/1
|
||||
|
||||
---TOTAL---
|
||||
OK: 174/182 Fail: 0/182 Skip: 8/182
|
||||
OK: 177/185 Fail: 0/185 Skip: 8/185
|
||||
|
@ -89,9 +89,11 @@ type
|
||||
checkpoint*: proc() {.gcsafe, raises: [Defect].}
|
||||
|
||||
keyValues: KvStoreRef # Random stuff using DbKeyKind - suitable for small values mainly!
|
||||
blocks: KvStoreRef # BlockRoot -> TrustedBeaconBlock
|
||||
blocks: KvStoreRef # BlockRoot -> phase0.TrustedBeaconBlock
|
||||
altairBlocks: KvStoreRef # BlockRoot -> altair.TrustedBeaconBlock
|
||||
stateRoots: KvStoreRef # (Slot, BlockRoot) -> StateRoot
|
||||
statesNoVal: KvStoreRef # StateRoot -> BeaconStateNoImmutableValidators
|
||||
altairStatesNoVal: KvStoreRef # StateRoot -> AltairBeaconStateNoImmutableValidators
|
||||
stateDiffs: KvStoreRef ##\
|
||||
## StateRoot -> BeaconStateDiff
|
||||
## Instead of storing full BeaconStates, one can store only the diff from
|
||||
@ -301,8 +303,10 @@ proc new*(T: type BeaconChainDB,
|
||||
# V1 - expected-to-be small rows get without rowid optimizations
|
||||
keyValues = kvStore db.openKvStore("key_values", true).expectDb()
|
||||
blocks = kvStore db.openKvStore("blocks").expectDb()
|
||||
altairBlocks = kvStore db.openKvStore("altair_blocks").expectDb()
|
||||
stateRoots = kvStore db.openKvStore("state_roots", true).expectDb()
|
||||
statesNoVal = kvStore db.openKvStore("state_no_validators2").expectDb()
|
||||
altairStatesNoVal = kvStore db.openKvStore("altair_state_no_validators").expectDb()
|
||||
stateDiffs = kvStore db.openKvStore("state_diffs").expectDb()
|
||||
summaries = kvStore db.openKvStore("beacon_block_summaries", true).expectDb()
|
||||
|
||||
@ -337,8 +341,10 @@ proc new*(T: type BeaconChainDB,
|
||||
checkpoint: proc() = db.checkpoint(),
|
||||
keyValues: keyValues,
|
||||
blocks: blocks,
|
||||
altair_blocks: altair_blocks,
|
||||
stateRoots: stateRoots,
|
||||
statesNoVal: statesNoVal,
|
||||
altairStatesNoVal: statesNoVal,
|
||||
stateDiffs: stateDiffs,
|
||||
summaries: summaries,
|
||||
)
|
||||
@ -449,8 +455,10 @@ proc close*(db: BeaconchainDB) =
|
||||
# Close things in reverse order
|
||||
discard db.summaries.close()
|
||||
discard db.stateDiffs.close()
|
||||
discard db.altairStatesNoVal.close()
|
||||
discard db.statesNoVal.close()
|
||||
discard db.stateRoots.close()
|
||||
discard db.altairBlocks.close()
|
||||
discard db.blocks.close()
|
||||
discard db.keyValues.close()
|
||||
db.immutableValidatorsDb.close()
|
||||
@ -475,6 +483,10 @@ proc putBlock*(db: BeaconChainDB, value: phase0.TrustedSignedBeaconBlock) =
|
||||
db.blocks.putSnappySSZ(value.root.data, value)
|
||||
db.putBeaconBlockSummary(value.root, value.message.toBeaconBlockSummary())
|
||||
|
||||
proc putBlock*(db: BeaconChainDB, value: altair.TrustedSignedBeaconBlock) =
|
||||
db.altairBlocks.putSnappySSZ(value.root.data, value)
|
||||
db.putBeaconBlockSummary(value.root, value.message.toBeaconBlockSummary())
|
||||
|
||||
proc updateImmutableValidators*(
|
||||
db: BeaconChainDB, validators: openArray[Validator]) =
|
||||
# Must be called before storing a state that references the new validators
|
||||
@ -492,7 +504,14 @@ proc putState*(db: BeaconChainDB, key: Eth2Digest, value: phase0.BeaconState) =
|
||||
key.data,
|
||||
isomorphicCast[BeaconStateNoImmutableValidators](value))
|
||||
|
||||
proc putState*(db: BeaconChainDB, value: phase0.BeaconState) =
|
||||
proc putState*(db: BeaconChainDB, key: Eth2Digest, value: altair.BeaconState) =
|
||||
db.updateImmutableValidators(value.validators.asSeq())
|
||||
db.altairStatesNoVal.putSnappySSZ(
|
||||
key.data,
|
||||
isomorphicCast[AltairBeaconStateNoImmutableValidators](value))
|
||||
|
||||
proc putState*(
|
||||
db: BeaconChainDB, value: phase0.BeaconState | altair.BeaconState) =
|
||||
db.putState(hash_tree_root(value), value)
|
||||
|
||||
func stateRootKey(root: Eth2Digest, slot: Slot): array[40, byte] =
|
||||
@ -512,10 +531,12 @@ proc putStateDiff*(db: BeaconChainDB, root: Eth2Digest, value: BeaconStateDiff)
|
||||
|
||||
proc delBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||
db.blocks.del(key.data).expectDb()
|
||||
db.altairBlocks.del(key.data).expectDb()
|
||||
db.summaries.del(key.data).expectDb()
|
||||
|
||||
proc delState*(db: BeaconChainDB, key: Eth2Digest) =
|
||||
db.statesNoVal.del(key.data).expectDb()
|
||||
db.altairStatesNoVal.del(key.data).expectDb()
|
||||
|
||||
proc delStateRoot*(db: BeaconChainDB, root: Eth2Digest, slot: Slot) =
|
||||
db.stateRoots.del(stateRootKey(root, slot)).expectDb()
|
||||
@ -556,6 +577,16 @@ proc getBlock*(db: BeaconChainDB, key: Eth2Digest):
|
||||
# set root after deserializing (so it doesn't get zeroed)
|
||||
result.get().root = key
|
||||
|
||||
proc getAltairBlock*(db: BeaconChainDB, key: Eth2Digest):
|
||||
Opt[altair.TrustedSignedBeaconBlock] =
|
||||
# We only store blocks that we trust in the database
|
||||
result.ok(default(altair.TrustedSignedBeaconBlock))
|
||||
if db.altairBlocks.getSnappySSZ(key.data, result.get) == GetResult.found:
|
||||
# set root after deserializing (so it doesn't get zeroed)
|
||||
result.get().root = key
|
||||
else:
|
||||
result.err()
|
||||
|
||||
proc getStateOnlyMutableValidators(
|
||||
immutableValidators: openArray[ImmutableValidatorData2],
|
||||
store: KvStoreRef, key: openArray[byte], output: var phase0.BeaconState,
|
||||
@ -598,6 +629,48 @@ proc getStateOnlyMutableValidators(
|
||||
rollback(output)
|
||||
false
|
||||
|
||||
proc getAltairStateOnlyMutableValidators(
|
||||
immutableValidators: openArray[ImmutableValidatorData2],
|
||||
store: KvStoreRef, key: openArray[byte], output: var altair.BeaconState,
|
||||
rollback: AltairRollbackProc): 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(output)
|
||||
false
|
||||
|
||||
proc getState(
|
||||
db: BeaconChainDBV0,
|
||||
immutableValidators: openArray[ImmutableValidatorData2],
|
||||
@ -646,6 +719,22 @@ proc getState*(
|
||||
else:
|
||||
true
|
||||
|
||||
proc getAltairState*(
|
||||
db: BeaconChainDB, key: Eth2Digest, output: var altair.BeaconState,
|
||||
rollback: AltairRollbackProc): 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
|
||||
getAltairStateOnlyMutableValidators(
|
||||
db.immutableValidators, db.altairStatesNoVal, key.data, output, rollback)
|
||||
|
||||
proc getStateRoot(db: BeaconChainDBV0,
|
||||
root: Eth2Digest,
|
||||
slot: Slot): Opt[Eth2Digest] =
|
||||
@ -698,7 +787,9 @@ proc containsBlock*(db: BeaconChainDBV0, key: Eth2Digest): bool =
|
||||
db.backend.contains(subkey(phase0.SignedBeaconBlock, key)).expectDb()
|
||||
|
||||
proc containsBlock*(db: BeaconChainDB, key: Eth2Digest): bool =
|
||||
db.blocks.contains(key.data).expectDb() or db.v0.containsBlock(key)
|
||||
db.altairBlocks.contains(key.data).expectDb() or
|
||||
db.blocks.contains(key.data).expectDb() or
|
||||
db.v0.containsBlock(key)
|
||||
|
||||
proc containsState*(db: BeaconChainDBV0, key: Eth2Digest): bool =
|
||||
let sk = subkey(BeaconStateNoImmutableValidators, key)
|
||||
@ -707,6 +798,7 @@ proc containsState*(db: BeaconChainDBV0, key: Eth2Digest): bool =
|
||||
db.backend.contains(subkey(phase0.BeaconState, key)).expectDb()
|
||||
|
||||
proc containsState*(db: BeaconChainDB, key: Eth2Digest, legacy: bool = true): bool =
|
||||
db.altairStatesNoVal.contains(key.data).expectDb or
|
||||
db.statesNoVal.contains(key.data).expectDb or
|
||||
(legacy and db.v0.containsState(key))
|
||||
|
||||
|
@ -12,13 +12,14 @@ import
|
||||
stew/[assign2, io2, objects, results],
|
||||
serialization,
|
||||
eth/db/[kvstore, kvstore_sqlite3],
|
||||
./spec/[crypto, datatypes, digest],
|
||||
./spec/[crypto, digest],
|
||||
./spec/datatypes/[base, altair],
|
||||
./ssz/[ssz_serialization, merkleization],
|
||||
filepath
|
||||
|
||||
type
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beaconstate
|
||||
# Memory-representation-equivalent to a v1.0.1 BeaconState for in-place SSZ reading and writing
|
||||
# Memory-representation-equivalent to a phase0 BeaconState for in-place SSZ reading and writing
|
||||
BeaconStateNoImmutableValidators* = object
|
||||
# Versioning
|
||||
genesis_time*: uint64
|
||||
@ -71,6 +72,68 @@ type
|
||||
current_justified_checkpoint*: Checkpoint
|
||||
finalized_checkpoint*: Checkpoint
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#beaconstate
|
||||
# Memory-representation-equivalent to an Altair BeaconState for in-place SSZ
|
||||
# reading and writing
|
||||
AltairBeaconStateNoImmutableValidators* = object
|
||||
# Versioning
|
||||
genesis_time*: uint64
|
||||
genesis_validators_root*: Eth2Digest
|
||||
slot*: Slot
|
||||
fork*: Fork
|
||||
|
||||
# History
|
||||
latest_block_header*: BeaconBlockHeader ##\
|
||||
## `latest_block_header.state_root == ZERO_HASH` temporarily
|
||||
|
||||
block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest] ##\
|
||||
## Needed to process attestations, older to newer
|
||||
|
||||
state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
|
||||
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
|
||||
|
||||
# Eth1
|
||||
eth1_data*: Eth1Data
|
||||
eth1_data_votes*:
|
||||
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
|
||||
eth1_deposit_index*: uint64
|
||||
|
||||
# Registry
|
||||
validators*: HashList[ValidatorStatus, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
balances*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Randomness
|
||||
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]
|
||||
|
||||
# Slashings
|
||||
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, uint64] ##\
|
||||
## Per-epoch sums of slashed effective balances
|
||||
|
||||
# Participation
|
||||
previous_epoch_participation*:
|
||||
HashList[ParticipationFlags, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
current_epoch_participation*:
|
||||
HashList[ParticipationFlags, Limit VALIDATOR_REGISTRY_LIMIT]
|
||||
|
||||
# Finality
|
||||
justification_bits*: uint8 ##\
|
||||
## Bit set for every recent justified epoch
|
||||
## Model a Bitvector[4] as a one-byte uint, which should remain consistent
|
||||
## with ssz/hashing.
|
||||
|
||||
previous_justified_checkpoint*: Checkpoint ##\
|
||||
## Previous epoch snapshot
|
||||
|
||||
current_justified_checkpoint*: Checkpoint
|
||||
finalized_checkpoint*: Checkpoint
|
||||
|
||||
# Inactivity
|
||||
inactivity_scores*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT] # [New in Altair]
|
||||
|
||||
# Light client sync committees
|
||||
current_sync_committee*: SyncCommittee # [New in Altair]
|
||||
next_sync_committee*: SyncCommittee # [New in Altair]
|
||||
|
||||
func getSizeofSig(x: auto, n: int = 0): seq[(string, int, int)] =
|
||||
for name, value in x.fieldPairs:
|
||||
when value is tuple|object:
|
||||
|
@ -559,9 +559,11 @@ proc putState(dag: ChainDAGRef, state: var StateData) =
|
||||
# Ideally we would save the state and the root lookup cache in a single
|
||||
# transaction to prevent database inconsistencies, but the state loading code
|
||||
# is resilient against one or the other going missing
|
||||
if state.data.beaconStateFork != forkAltair:
|
||||
# TODO re-enable for Altair
|
||||
case state.data.beaconStateFork:
|
||||
of forkPhase0:
|
||||
dag.db.putState(getStateRoot(state.data), state.data.hbsPhase0.data)
|
||||
of forkAltair:
|
||||
dag.db.putState(getStateRoot(state.data), state.data.hbsAltair.data)
|
||||
|
||||
dag.db.putStateRoot(
|
||||
state.blck.root, getStateField(state.data, slot), getStateRoot(state.data))
|
||||
|
@ -105,9 +105,13 @@ func verifyStateRoot(state: phase0.BeaconState, blck: altair.TrustedBeaconBlock)
|
||||
|
||||
type
|
||||
RollbackProc* = proc(v: var phase0.BeaconState) {.gcsafe, raises: [Defect].}
|
||||
AltairRollbackProc* = proc(v: var altair.BeaconState) {.gcsafe, raises: [Defect].}
|
||||
|
||||
func noRollback*(state: var phase0.BeaconState) =
|
||||
trace "Skipping rollback of broken state"
|
||||
trace "Skipping rollback of broken phase 0 state"
|
||||
|
||||
func noRollback*(state: var altair.BeaconState) =
|
||||
trace "Skipping rollback of broken Altair state"
|
||||
|
||||
type
|
||||
RollbackHashedProc* = proc(state: var phase0.HashedBeaconState) {.gcsafe, raises: [Defect].}
|
||||
@ -170,7 +174,7 @@ func noRollback*(state: var phase0.HashedBeaconState) =
|
||||
func noRollback*(state: var altair.HashedBeaconState) =
|
||||
trace "Skipping rollback of broken Altair state"
|
||||
|
||||
proc maybeUpgradeStateToAltair(
|
||||
proc maybeUpgradeStateToAltair*(
|
||||
state: var ForkedHashedBeaconState, altairForkSlot: Slot) =
|
||||
# Both process_slots() and state_transition_block() call this, so only run it
|
||||
# once by checking for existing fork.
|
||||
|
@ -1,5 +1,5 @@
|
||||
# beacon_chain
|
||||
# Copyright (c) 2018-2020 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
@ -13,8 +13,8 @@ import
|
||||
math,
|
||||
|
||||
# Specs
|
||||
../../beacon_chain/spec/[datatypes, crypto, digest,
|
||||
keystore, signatures, presets],
|
||||
../../beacon_chain/spec/[crypto, digest, keystore, signatures, presets],
|
||||
../../beacon_chain/spec/datatypes/base,
|
||||
|
||||
# Internals
|
||||
../../beacon_chain/extras,
|
||||
@ -103,8 +103,8 @@ proc mockGenesisBalancedDeposits*(
|
||||
mockGenesisDepositsImpl(result, validatorCount,amount,flags):
|
||||
discard
|
||||
|
||||
proc mockUpdateStateForNewDeposit*(
|
||||
state: var BeaconState,
|
||||
proc mockUpdateStateForNewDeposit*[T](
|
||||
state: var T,
|
||||
validator_index: uint64,
|
||||
amount: uint64,
|
||||
# withdrawal_credentials: Eth2Digest
|
||||
|
@ -12,8 +12,9 @@ import
|
||||
unittest2,
|
||||
../beacon_chain/[beacon_chain_db, extras, interop, ssz],
|
||||
../beacon_chain/spec/[
|
||||
beaconstate, crypto, datatypes, digest, forkedbeaconstate_helpers, presets,
|
||||
beaconstate, crypto, digest, forkedbeaconstate_helpers, presets,
|
||||
state_transition],
|
||||
../beacon_chain/spec/datatypes/[phase0, altair],
|
||||
../beacon_chain/consensus_object_pools/blockchain_dag,
|
||||
eth/db/kvstore,
|
||||
# test utilies
|
||||
@ -22,14 +23,30 @@ import
|
||||
when isMainModule:
|
||||
import chronicles # or some random compile error happens...
|
||||
|
||||
proc getStateRef(db: BeaconChainDB, root: Eth2Digest): NilableBeaconStateRef =
|
||||
proc getPhase0StateRef(db: BeaconChainDB, root: Eth2Digest):
|
||||
phase0.NilableBeaconStateRef =
|
||||
# load beaconstate the way the block pool does it - into an existing instance
|
||||
let res = BeaconStateRef()
|
||||
let res = (phase0.BeaconStateRef)()
|
||||
if db.getState(root, res[], noRollback):
|
||||
return res
|
||||
|
||||
func withDigest(blck: TrustedBeaconBlock): TrustedSignedBeaconBlock =
|
||||
TrustedSignedBeaconBlock(
|
||||
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):
|
||||
return res
|
||||
|
||||
func withDigest(blck: phase0.TrustedBeaconBlock):
|
||||
phase0.TrustedSignedBeaconBlock =
|
||||
phase0.TrustedSignedBeaconBlock(
|
||||
message: blck,
|
||||
root: hash_tree_root(blck)
|
||||
)
|
||||
|
||||
func withDigest(blck: altair.TrustedBeaconBlock):
|
||||
altair.TrustedSignedBeaconBlock =
|
||||
altair.TrustedSignedBeaconBlock(
|
||||
message: blck,
|
||||
root: hash_tree_root(blck)
|
||||
)
|
||||
@ -39,15 +56,15 @@ suite "Beacon chain DB" & preset():
|
||||
var
|
||||
db = BeaconChainDB.new(defaultRuntimePreset, "", inMemory = true)
|
||||
check:
|
||||
db.getStateRef(Eth2Digest()).isNil
|
||||
db.getPhase0StateRef(Eth2Digest()).isNil
|
||||
db.getBlock(Eth2Digest()).isNone
|
||||
|
||||
test "sanity check blocks" & preset():
|
||||
test "sanity check phase 0 blocks" & preset():
|
||||
var
|
||||
db = BeaconChainDB.new(defaultRuntimePreset, "", inMemory = true)
|
||||
|
||||
let
|
||||
signedBlock = withDigest(TrustedBeaconBlock())
|
||||
signedBlock = withDigest((phase0.TrustedBeaconBlock)())
|
||||
root = hash_tree_root(signedBlock.message)
|
||||
|
||||
db.putBlock(signedBlock)
|
||||
@ -56,6 +73,11 @@ suite "Beacon chain DB" & preset():
|
||||
db.containsBlock(root)
|
||||
db.getBlock(root).get() == signedBlock
|
||||
|
||||
db.delBlock(root)
|
||||
check:
|
||||
not db.containsBlock(root)
|
||||
db.getBlock(root).isErr()
|
||||
|
||||
db.putStateRoot(root, signedBlock.message.slot, root)
|
||||
var root2 = root
|
||||
root2.data[0] = root.data[0] + 1
|
||||
@ -67,7 +89,37 @@ suite "Beacon chain DB" & preset():
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check states" & preset():
|
||||
test "sanity check Altair blocks" & preset():
|
||||
var
|
||||
db = BeaconChainDB.new(defaultRuntimePreset, "", inMemory = true)
|
||||
|
||||
let
|
||||
signedBlock = withDigest((altair.TrustedBeaconBlock)())
|
||||
root = hash_tree_root(signedBlock.message)
|
||||
|
||||
db.putBlock(signedBlock)
|
||||
|
||||
check:
|
||||
db.containsBlock(root)
|
||||
db.getAltairBlock(root).get() == signedBlock
|
||||
|
||||
db.delBlock(root)
|
||||
check:
|
||||
not db.containsBlock(root)
|
||||
db.getAltairBlock(root).isErr()
|
||||
|
||||
db.putStateRoot(root, signedBlock.message.slot, root)
|
||||
var root2 = root
|
||||
root2.data[0] = root.data[0] + 1
|
||||
db.putStateRoot(root, signedBlock.message.slot + 1, root2)
|
||||
|
||||
check:
|
||||
db.getStateRoot(root, signedBlock.message.slot).get() == root
|
||||
db.getStateRoot(root, signedBlock.message.slot + 1).get() == root2
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check phase 0 states" & preset():
|
||||
var
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
dag = init(ChainDAGRef, defaultRuntimePreset, db)
|
||||
@ -83,19 +135,46 @@ suite "Beacon chain DB" & preset():
|
||||
|
||||
check:
|
||||
db.containsState(root)
|
||||
hash_tree_root(db.getStateRef(root)[]) == root
|
||||
hash_tree_root(db.getPhase0StateRef(root)[]) == root
|
||||
|
||||
db.delState(root)
|
||||
check: not db.containsState(root)
|
||||
check:
|
||||
not db.containsState(root)
|
||||
db.getPhase0StateRef(root).isNil
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check states, reusing buffers" & preset():
|
||||
test "sanity check Altair states" & preset():
|
||||
var
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
dag = init(ChainDAGRef, defaultRuntimePreset, db)
|
||||
testStates = getTestStates(dag.headState.data, true)
|
||||
|
||||
# Ensure transitions beyond just adding validators and increasing slots
|
||||
sort(testStates) do (x, y: ref ForkedHashedBeaconState) -> int:
|
||||
cmp($getStateRoot(x[]), $getStateRoot(y[]))
|
||||
|
||||
for state in testStates:
|
||||
db.putState(state[].hbsAltair.data)
|
||||
let root = hash_tree_root(state[])
|
||||
|
||||
check:
|
||||
db.containsState(root)
|
||||
hash_tree_root(db.getAltairStateRef(root)[]) == root
|
||||
|
||||
db.delState(root)
|
||||
check:
|
||||
not db.containsState(root)
|
||||
db.getAltairStateRef(root).isNil
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check phase 0 states, reusing buffers" & preset():
|
||||
var
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
dag = init(ChainDAGRef, defaultRuntimePreset, db)
|
||||
|
||||
let stateBuffer = BeaconStateRef()
|
||||
let stateBuffer = (phase0.BeaconStateRef)()
|
||||
var testStates = getTestStates(dag.headState.data)
|
||||
|
||||
# Ensure transitions beyond just adding validators and increasing slots
|
||||
@ -112,7 +191,37 @@ suite "Beacon chain DB" & preset():
|
||||
hash_tree_root(stateBuffer[]) == root
|
||||
|
||||
db.delState(root)
|
||||
check: not db.containsState(root)
|
||||
check:
|
||||
not db.containsState(root)
|
||||
not db.getState(root, stateBuffer[], noRollback)
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check Altair states, reusing buffers" & preset():
|
||||
var
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
dag = init(ChainDAGRef, defaultRuntimePreset, db)
|
||||
|
||||
let stateBuffer = (altair.BeaconStateRef)()
|
||||
var testStates = getTestStates(dag.headState.data, true)
|
||||
|
||||
# Ensure transitions beyond just adding validators and increasing slots
|
||||
sort(testStates) do (x, y: ref ForkedHashedBeaconState) -> int:
|
||||
cmp($getStateRoot(x[]), $getStateRoot(y[]))
|
||||
|
||||
for state in testStates:
|
||||
db.putState(state[].hbsAltair.data)
|
||||
let root = hash_tree_root(state[])
|
||||
|
||||
check:
|
||||
db.getAltairState(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)
|
||||
|
||||
db.close()
|
||||
|
||||
@ -122,11 +231,11 @@ suite "Beacon chain DB" & preset():
|
||||
|
||||
let
|
||||
a0 = withDigest(
|
||||
TrustedBeaconBlock(slot: GENESIS_SLOT + 0))
|
||||
(phase0.TrustedBeaconBlock)(slot: GENESIS_SLOT + 0))
|
||||
a1 = withDigest(
|
||||
TrustedBeaconBlock(slot: GENESIS_SLOT + 1, parent_root: a0.root))
|
||||
(phase0.TrustedBeaconBlock)(slot: GENESIS_SLOT + 1, parent_root: a0.root))
|
||||
a2 = withDigest(
|
||||
TrustedBeaconBlock(slot: GENESIS_SLOT + 2, parent_root: a1.root))
|
||||
(phase0.TrustedBeaconBlock)(slot: GENESIS_SLOT + 2, parent_root: a1.root))
|
||||
|
||||
doAssert toSeq(db.getAncestors(a0.root)) == []
|
||||
doAssert toSeq(db.getAncestors(a2.root)) == []
|
||||
@ -175,7 +284,7 @@ suite "Beacon chain DB" & preset():
|
||||
db.putState(state[])
|
||||
|
||||
check db.containsState(root)
|
||||
let state2 = db.getStateRef(root)
|
||||
let state2 = db.getPhase0StateRef(root)
|
||||
db.delState(root)
|
||||
check not db.containsState(root)
|
||||
db.close()
|
||||
|
@ -16,7 +16,7 @@ import
|
||||
beaconstate, crypto, datatypes, forkedbeaconstate_helpers, helpers,
|
||||
presets, state_transition]
|
||||
|
||||
proc valid_deposit(state: var BeaconState) =
|
||||
proc valid_deposit[T](state: var T) =
|
||||
const deposit_amount = MAX_EFFECTIVE_BALANCE
|
||||
let validator_index = state.validators.len
|
||||
let deposit = mockUpdateStateForNewDeposit(
|
||||
@ -41,7 +41,8 @@ proc valid_deposit(state: var BeaconState) =
|
||||
EFFECTIVE_BALANCE_INCREMENT
|
||||
)
|
||||
|
||||
proc getTestStates*(initialState: ForkedHashedBeaconState):
|
||||
proc getTestStates*(
|
||||
initialState: ForkedHashedBeaconState, useAltair: bool = false):
|
||||
seq[ref ForkedHashedBeaconState] =
|
||||
# Randomly generated slot numbers, with a jump to around
|
||||
# SLOTS_PER_HISTORICAL_ROOT to force wraparound of those
|
||||
@ -68,7 +69,16 @@ proc getTestStates*(initialState: ForkedHashedBeaconState):
|
||||
if getStateField(tmpState[], slot) < slot:
|
||||
doAssert process_slots(
|
||||
tmpState[], slot, cache, rewards, {}, FAR_FUTURE_SLOT)
|
||||
|
||||
if useAltair and epoch == 1:
|
||||
maybeUpgradeStateToAltair(tmpState[], slot)
|
||||
|
||||
if i mod 3 == 0:
|
||||
valid_deposit(tmpState.hbsPhase0.data)
|
||||
if tmpState[].beaconStateFork == forkPhase0:
|
||||
valid_deposit(tmpState[].hbsPhase0.data)
|
||||
else:
|
||||
valid_deposit(tmpState[].hbsAltair.data)
|
||||
doAssert getStateField(tmpState[], slot) == slot
|
||||
result.add assignClone(tmpState[])
|
||||
|
||||
if useAltair == (tmpState[].beaconStateFork == forkAltair):
|
||||
result.add assignClone(tmpState[])
|
||||
|
Loading…
x
Reference in New Issue
Block a user