Skip to content

Commit

Permalink
add Electra beacon chain database state tests (#6584)
Browse files Browse the repository at this point in the history
  • Loading branch information
tersec authored Sep 27, 2024
1 parent 744cc00 commit fa8b7e3
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 26 deletions.
7 changes: 5 additions & 2 deletions AllTests-mainnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ OK: 4/4 Fail: 0/4 Skip: 0/4
+ sanity check Deneb blocks [Preset: mainnet] OK
+ sanity check Deneb states [Preset: mainnet] OK
+ sanity check Deneb states, reusing buffers [Preset: mainnet] OK
+ sanity check Electra and cross-fork getState rollback [Preset: mainnet] OK
+ sanity check Electra blocks [Preset: mainnet] OK
+ sanity check Electra states [Preset: mainnet] OK
+ sanity check Electra states, reusing buffers [Preset: mainnet] OK
+ sanity check blobs [Preset: mainnet] OK
+ sanity check genesis roundtrip [Preset: mainnet] OK
+ sanity check phase 0 blocks [Preset: mainnet] OK
Expand All @@ -66,7 +69,7 @@ OK: 4/4 Fail: 0/4 Skip: 0/4
+ sanity check phase 0 states, reusing buffers [Preset: mainnet] OK
+ sanity check state diff roundtrip [Preset: mainnet] OK
```
OK: 26/26 Fail: 0/26 Skip: 0/26
OK: 29/29 Fail: 0/29 Skip: 0/29
## Beacon state [Preset: mainnet]
```diff
+ Smoke test initialize_beacon_state_from_eth1 [Preset: mainnet] OK
Expand Down Expand Up @@ -1125,4 +1128,4 @@ OK: 2/2 Fail: 0/2 Skip: 0/2
OK: 9/9 Fail: 0/9 Skip: 0/9

---TOTAL---
OK: 762/767 Fail: 0/767 Skip: 5/767
OK: 765/770 Fail: 0/770 Skip: 5/770
3 changes: 0 additions & 3 deletions beacon_chain/consensus_object_pools/blockchain_dag.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@ import
../spec/[beaconstate, eth2_merkleization, eth2_ssz_serialization, helpers,
state_transition, validator],
../spec/forks,
../spec/datatypes/[phase0, altair, bellatrix, capella],
".."/[beacon_chain_db, beacon_clock, era_db],
"."/[block_pools_types, block_quarantine]

from ../spec/datatypes/deneb import shortLog

export
eth2_merkleization, eth2_ssz_serialization,
block_pools_types, results, beacon_chain_db
Expand Down
109 changes: 90 additions & 19 deletions tests/test_beacon_chain_db.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,24 @@
import
unittest2,
../beacon_chain/beacon_chain_db,
../beacon_chain/spec/[beaconstate, forks, state_transition],
../beacon_chain/consensus_object_pools/blockchain_dag,
eth/db/kvstore,
# test utilies
./mocking/mock_genesis,
./testutil, ./testdbutil, ./testblockutil, ./teststateutil
../beacon_chain/consensus_object_pools/block_dag,
../beacon_chain/spec/forks,
./testutil

from std/algorithm import sort
from std/sequtils import toSeq
from snappy import encodeFramed, uncompressedLenFramed
from ../beacon_chain/consensus_object_pools/block_pools_types import
ChainDAGRef
from ../beacon_chain/consensus_object_pools/blockchain_dag import init
from ../beacon_chain/spec/beaconstate import
initialize_hashed_beacon_state_from_eth1
from ../beacon_chain/spec/state_transition import noRollback
from ../beacon_chain/validators/validator_monitor import ValidatorMonitor
from ./mocking/mock_genesis import mockEth1BlockHash
from ./testblockutil import makeInitialDeposits
from ./testdbutil import makeTestDB
from ./teststateutil import getTestStates

when isMainModule:
import chronicles # or some random compile error happens...
Expand All @@ -46,25 +54,27 @@ proc getBellatrixStateRef(db: BeaconChainDB, root: Eth2Digest):
if db.getState(root, res[], noRollback):
return res

from ../beacon_chain/spec/datatypes/capella import
BeaconStateRef, NilableBeaconStateRef

proc getCapellaStateRef(db: BeaconChainDB, root: Eth2Digest):
capella.NilableBeaconStateRef =
# load beaconstate the way the block pool does it - into an existing instance
let res = (capella.BeaconStateRef)()
if db.getState(root, res[], noRollback):
return res

from ../beacon_chain/spec/datatypes/deneb import TrustedSignedBeaconBlock

proc getDenebStateRef(db: BeaconChainDB, root: Eth2Digest):
deneb.NilableBeaconStateRef =
# load beaconstate the way the block pool does it - into an existing instance
let res = (deneb.BeaconStateRef)()
if db.getState(root, res[], noRollback):
return res

proc getElectraStateRef(db: BeaconChainDB, root: Eth2Digest):
electra.NilableBeaconStateRef =
# load beaconstate the way the block pool does it - into an existing instance
let res = (electra.BeaconStateRef)()
if db.getState(root, res[], noRollback):
return res

func withDigest(blck: phase0.TrustedBeaconBlock):
phase0.TrustedSignedBeaconBlock =
phase0.TrustedSignedBeaconBlock(
Expand Down Expand Up @@ -120,20 +130,20 @@ proc getTestStates(consensusFork: ConsensusFork): auto =

testStates

debugComment "add some electra states, and test electra state loading/etc"

# Each set of states gets used twice, so scope them to module
let
testStatesPhase0 = getTestStates(ConsensusFork.Phase0)
testStatesAltair = getTestStates(ConsensusFork.Altair)
testStatesBellatrix = getTestStates(ConsensusFork.Bellatrix)
testStatesCapella = getTestStates(ConsensusFork.Capella)
testStatesDeneb = getTestStates(ConsensusFork.Deneb)
testStatesElectra = getTestStates(ConsensusFork.Electra)
doAssert len(testStatesPhase0) > 8
doAssert len(testStatesAltair) > 8
doAssert len(testStatesBellatrix) > 8
doAssert len(testStatesCapella) > 8
doAssert len(testStatesDeneb) > 8
doAssert len(testStatesElectra) > 8

suite "Beacon chain DB" & preset():
test "empty database" & preset():
Expand Down Expand Up @@ -527,6 +537,24 @@ suite "Beacon chain DB" & preset():

db.close()

test "sanity check Electra states" & preset():
let db = makeTestDB(SLOTS_PER_EPOCH)

for state in testStatesElectra:
let root = state[].electraData.root
db.putState(root, state[].electraData.data)

check:
db.containsState(root)
hash_tree_root(db.getElectraStateRef(root)[]) == root

db.delState(ConsensusFork.Electra, root)
check:
not db.containsState(root)
db.getElectraStateRef(root).isNil

db.close()

test "sanity check phase 0 states, reusing buffers" & preset():
let db = makeTestDB(SLOTS_PER_EPOCH)
let stateBuffer = (phase0.BeaconStateRef)()
Expand Down Expand Up @@ -627,6 +655,26 @@ suite "Beacon chain DB" & preset():

db.close()

test "sanity check Electra states, reusing buffers" & preset():
let db = makeTestDB(SLOTS_PER_EPOCH)
let stateBuffer = (electra.BeaconStateRef)()

for state in testStatesElectra:
let root = state[].electraData.root
db.putState(root, state[].electraData.data)

check:
db.getState(root, stateBuffer[], noRollback)
db.containsState(root)
hash_tree_root(stateBuffer[]) == root

db.delState(ConsensusFork.Electra, root)
check:
not db.containsState(root)
not db.getState(root, stateBuffer[], noRollback)

db.close()

test "sanity check phase 0 getState rollback" & preset():
var
db = makeTestDB(SLOTS_PER_EPOCH)
Expand Down Expand Up @@ -754,9 +802,34 @@ suite "Beacon chain DB" & preset():
state[].kind == ConsensusFork.Phase0
state[].phase0Data.data.slot != 10.Slot

test "find ancestors" & preset():
test "sanity check Electra and cross-fork getState rollback" & preset():
var
db = BeaconChainDB.new("", inMemory = true)
db = makeTestDB(SLOTS_PER_EPOCH)
validatorMonitor = newClone(ValidatorMonitor.init())
dag = init(ChainDAGRef, defaultRuntimeConfig, db, validatorMonitor, {})
state = (ref ForkedHashedBeaconState)(
kind: ConsensusFork.Electra,
electraData: electra.HashedBeaconState(data: electra.BeaconState(
slot: 10.Slot)))
root = Eth2Digest()

db.putCorruptState(ConsensusFork.Electra, root)

let restoreAddr = addr dag.headState

func restore() =
assign(state[], restoreAddr[])

check:
state[].electraData.data.slot == 10.Slot
not db.getState(root, state[].electraData.data, restore)

# assign() has switched the case object fork
state[].kind == ConsensusFork.Phase0
state[].phase0Data.data.slot != 10.Slot

test "find ancestors" & preset():
var db = BeaconChainDB.new("", inMemory = true)

let
a0 = withDigest(
Expand Down Expand Up @@ -791,8 +864,7 @@ suite "Beacon chain DB" & preset():
# state. We've been bit by this because we've had a bug in the BLS
# serialization where an all-zero default-initialized bls signature could
# not be deserialized because the deserialization was too strict.
var
db = BeaconChainDB.new("", inMemory = true)
var db = BeaconChainDB.new("", inMemory = true)

let
state = newClone(initialize_hashed_beacon_state_from_eth1(
Expand All @@ -811,8 +883,7 @@ suite "Beacon chain DB" & preset():
hash_tree_root(state2[]) == state[].root

test "sanity check state diff roundtrip" & preset():
var
db = BeaconChainDB.new("", inMemory = true)
var db = BeaconChainDB.new("", inMemory = true)

# TODO htr(diff) probably not interesting/useful, but stand-in
let
Expand Down
11 changes: 9 additions & 2 deletions tests/teststateutil.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,15 @@ proc valid_deposit(state: var ForkyHashedBeaconState) =
defaultRuntimeConfig, state.data,
sortValidatorBuckets(state.data.validators.asSeq)[], deposit, {}).isOk
doAssert state.data.validators.len == pre_val_count + 1
doAssert state.data.balances.len == pre_val_count + 1
doAssert state.data.balances.item(validator_index) == pre_balance + deposit.data.amount
when typeof(state).kind >= ConsensusFork.Electra:
doAssert state.data.pending_balance_deposits.asSeq[^1] ==
PendingBalanceDeposit(index: pre_val_count.uint64,
amount: deposit.data.amount)
doAssert state.data.balances.item(validator_index) == pre_balance
else:
doAssert state.data.balances.item(validator_index) ==
pre_balance + deposit.data.amount

doAssert state.data.validators.item(validator_index).effective_balance ==
round_multiple_down(
min(
Expand Down

0 comments on commit fa8b7e3

Please sign in to comment.