nimbus-eth2/tests/test_statediff.nim

73 lines
3.0 KiB
Nim
Raw Normal View History

# beacon_chain
# Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
{.used.}
import
unittest2,
./testutil, ./testdbutil, ./teststateutil,
../beacon_chain/spec/forks,
immutable validator database factoring (#2297) * initial immutable validator database factoring * remove changes from chain_dag: this abstraction properly belongs in beacon_chain_db * add merging mutable/immutable validator portions; individually test database roundtripping of immutable validators and states-sans-immutable-validators * update test summaries * use stew/assign2 instead of Nim assignment * add reading/writing of immutable validators in chaindag * remove unused import * replace chunked k/v store of immutable validators with per-row SQL table storage * use List instead of HashList * un-stub some ncli_db code so that it uses * switch HashArray to array; move BeaconStateNoImmutableValidators from datatypes to beacon_chain_db * begin only-mutable-part state storage * uncomment some assigns * work around https://github.com/nim-lang/Nim/issues/17253 * fix most of the issues/oversights; local sim runs again * fix test suite by adding missing beaconstate field to copy function * have ncli bench also store immutable validators * extract some immutable-validator-specific code from the beacon chain db module * add more rigorous database state roundtripping, with changing validator sets * adjust ncli_db to use new schema * simplify putState/getState by moving all immutable validator accounting into beacon state DB * remove redundant test case and move code to immutable-beacon-chain module * more efficient, but still brute-force, mutable+immutable validator merging * reuse BeaconState in getState * ensure HashList/HashArray caches are cleared when reusing getState buffers; add ncli_db and a unit test to verify this * HashList.clear() -> HashList.clearCache() * only copy incrementally necessary immutable validators * increase strictness of test cases and fix/work around resulting HashList cache invalidation issues * remove explanatory scaffolding * allow for storage of full (with all validators) states for backwards/forwards-compatibility * adjust DbSeq type usage * store full, with-validators, state every 64 epochs to enable reverting versions * reduce memory allocation and intermediate objects in state storage codepath * eliminate allocation/copying through intermediate BeaconStateNoImmutableValidators objects * skip benchmarking initial genesis-validator-heavy state store * always store new-style state and sometimes old-style state * document intent behind BeaconState/Validator type-punnery * more accurate failure message on SQLite in-memory database initialization failure
2021-03-15 14:11:51 +00:00
../beacon_chain/consensus_object_pools/[blockchain_dag, block_quarantine]
from std/sequtils import mapIt
from ../beacon_chain/statediff import
applyDiff, diffStates, getBeaconStateDiffSummary
# In live usage, it's unnecessary and excessive to keep both states in memory
# at once, but it simplifies testing so treat this explicitly as testing-only
# infrastructure.
func diffStates(state0, state1: capella.BeaconState): BeaconStateDiff =
doAssert state1.slot > state0.slot
doAssert state0.slot.is_epoch
doAssert state1.slot == state0.slot + SLOTS_PER_EPOCH
# TODO not here, but in dag, an isancestorof check
doAssert state0.genesis_time == state1.genesis_time
doAssert state0.genesis_validators_root == state1.genesis_validators_root
doAssert state0.fork == state1.fork
doAssert state1.historical_roots == state0.historical_roots
doAssert state1.historical_summaries.len -
state0.historical_summaries.len in [0, 1]
diffStates(getBeaconStateDiffSummary(state0), state1)
when isMainModule:
import chronicles # or some random compile error happens...
suite "state diff tests" & preset():
setup:
var
db = makeTestDB(SLOTS_PER_EPOCH)
validatorMonitor = newClone(ValidatorMonitor.init())
dag = init(ChainDAGRef, defaultRuntimeConfig, db, validatorMonitor, {})
test "random slot differences" & preset():
let testStates = getTestStates(dag.headState, ConsensusFork.Capella)
for i in 0 ..< testStates.len:
for j in (i+1) ..< testStates.len:
doAssert getStateField(testStates[i][], slot) <
getStateField(testStates[j][], slot)
if getStateField(testStates[i][], slot) + SLOTS_PER_EPOCH !=
getStateField(testStates[j][], slot):
continue
let
tmpStateApplyBase = assignClone(testStates[i].capellaData.data)
diff = diffStates(
testStates[i].capellaData.data, testStates[j].capellaData.data)
# Immutable parts of validators stored separately, so aren't part of
# the state diff. Synthesize required portion here for testing.
applyDiff(
tmpStateApplyBase[],
mapIt(
getStateField(testStates[j][], validators).asSeq[
getStateField(testStates[i][], validators).len ..
getStateField(testStates[j][], validators).len - 1],
it.getImmutableValidatorData),
diff)
check hash_tree_root(testStates[j][].capellaData.data) ==
hash_tree_root(tmpStateApplyBase[])