nimbus-eth2/tests/test_deposit_snapshots.nim

192 lines
8.4 KiB
Nim

# beacon_chain
# Copyright (c) 2022-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
std/[os, random, strutils, times],
chronos, stew/results, unittest2, chronicles,
../beacon_chain/beacon_chain_db,
../beacon_chain/spec/deposit_snapshots
from eth/db/kvstore import kvStore
from nimcrypto import toDigest
from snappy import encode
from stew/byteutils import hexToSeqByte
const ROOT = "342cecb5a18945fbbda7c62ede3016f3"
template databaseRoot: string = getTempDir().joinPath(ROOT)
template key1: array[1, byte] = [byte(kOldDepositContractSnapshot)]
type
DepositSnapshotUpgradeProc = proc(old: OldDepositContractSnapshot): DepositTreeSnapshot
{.gcsafe, raises: [].}
proc ifNecessaryMigrateDCS(db: BeaconChainDB,
upgradeProc: DepositSnapshotUpgradeProc) =
if not db.hasDepositTreeSnapshot():
let oldSnapshot = db.getUpgradableDepositSnapshot()
if oldSnapshot.isSome:
db.putDepositTreeSnapshot upgradeProc(oldSnapshot.get)
# Hexlified copy of
# eth2-networks/shared/mainnet/genesis_deposit_contract_snapshot.ssz
let ds1: seq[byte] = hexToSeqByte(
"""
eeea1373d4aa9e099d7c9deddb694db9aeb4577755ef83f9b6345ce4357d9abfca3bfce2c
304c4f52e0c83f96daf8c98a05f80281b62cf08f6be9c1bc10c0adbabcf2f74605a9eb36c
f243bb5009259a3717d44df3caf02acc53ab49cfd2eeb6d4079d31e57638b3a6928ff3940
d0d06545ae164278597bb8d46053084c335eaf9585ef52fc5eaf1f11718df7988d3f414d8
b0be2e56e15d7ade9f5ee4cc7ee4a4c96f16c3a300034788ba8bf79c3125a697488006a4a
4288c38fdc4e9891891cae036d14b83ff1523749d4fabf5c91e8d455dce2f14eae3408dce
22f901efc7858ccad1a32af9e9796d3026ba18925103cad44cba4bdc1f3d3c23be125bba1
811f1e08405d5d180444147397ea0d4aebf12edff5cebc52cb05983c8d4bd2d4a93d66676
459ab2c5ca9d553a5c5599cc6992ed90edc939c51cc99d1820b5691914bfcab6eb8016c51
77e9e8f006e7893ea46b232b91b1f923b05273a927cd6d0aa14720bc149ce68f20809d6fe
55816acf09e72c14b54637dea24eb961558a7ac726d03ced287a817fa8fea71c90bd89955
b093d7c5908305177efa8289457190435298b2d5b2b67543e4dceaf2c8b7fdbdac12836a7
0ed910c34abcd10b3ddf53f640c85e35fef7e7ba4ab8c561fe9f1d763a32c65a1fbad5756
6bda135236257aa502116cb72c9347d10dca1b64a342b41a829cc7ba95e71499f57be2be3
cd00000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000005251
""".replace(" ", "").replace("\n", "")
)
const
ds1Root = toDigest("1a4c3cce02935defd159e4e207890ae26a325bf03e205c9ee94ca040ecce008a")
proc fixture1() =
## Inserts a OldDepositContractSnapshot fixture.
let
compressed = snappy.encode(ds1)
db = SqStoreRef.init(databaseRoot, "nbc").expect("")
kv = kvStore(db.openKvStore("key_values", true).expect(""))
kv.put(key1, compressed).expect("")
db.close()
proc inspectDCS(snapshot: OldDepositContractSnapshot | DepositTreeSnapshot) =
## Inspects a DCS and checks if all of its data corresponds to
## what's encoded in ds1.
const zero = toDigest("0000000000000000000000000000000000000000000000000000000000000000")
const root = toDigest("1a4c3cce02935defd159e4e207890ae26a325bf03e205c9ee94ca040ecce008a")
const want = [
"ca3bfce2c304c4f52e0c83f96daf8c98a05f80281b62cf08f6be9c1bc10c0adb",
"abcf2f74605a9eb36cf243bb5009259a3717d44df3caf02acc53ab49cfd2eeb6",
"d4079d31e57638b3a6928ff3940d0d06545ae164278597bb8d46053084c335ea",
"f9585ef52fc5eaf1f11718df7988d3f414d8b0be2e56e15d7ade9f5ee4cc7ee4",
"a4c96f16c3a300034788ba8bf79c3125a697488006a4a4288c38fdc4e9891891",
"cae036d14b83ff1523749d4fabf5c91e8d455dce2f14eae3408dce22f901efc7",
"858ccad1a32af9e9796d3026ba18925103cad44cba4bdc1f3d3c23be125bba18",
"11f1e08405d5d180444147397ea0d4aebf12edff5cebc52cb05983c8d4bd2d4a",
"93d66676459ab2c5ca9d553a5c5599cc6992ed90edc939c51cc99d1820b56919",
"14bfcab6eb8016c5177e9e8f006e7893ea46b232b91b1f923b05273a927cd6d0",
"aa14720bc149ce68f20809d6fe55816acf09e72c14b54637dea24eb961558a7a",
"c726d03ced287a817fa8fea71c90bd89955b093d7c5908305177efa828945719",
"0435298b2d5b2b67543e4dceaf2c8b7fdbdac12836a70ed910c34abcd10b3ddf",
"53f640c85e35fef7e7ba4ab8c561fe9f1d763a32c65a1fbad57566bda1352362",
"57aa502116cb72c9347d10dca1b64a342b41a829cc7ba95e71499f57be2be3cd",
]
# Check eth1Block.
check($snapshot.eth1Block == "eeea1373d4aa9e099d7c9deddb694db9aeb4577755ef83f9b6345ce4357d9abf")
# Check branch.
for i in 0..want.high():
check($snapshot.depositContractState.branch[i] == want[i])
for i in (want.high() + 1)..31:
check(snapshot.depositContractState.branch[i] == zero)
# Check deposit_count.
check(snapshot.getDepositCountU64() == 21073)
# Check deposit root.
check(snapshot.getDepositRoot == root)
proc inspectDCS(snapshot: DepositTreeSnapshot, wantedBlockHeight: uint64) =
inspectDCS(snapshot)
check(snapshot.blockHeight == wantedBlockHeight)
suite "DepositTreeSnapshot":
setup:
randomize()
teardown:
# removeDir(databaseRoot)
discard
test "SSZ":
var snapshot = OldDepositContractSnapshot()
check(decodeSSZ(ds1, snapshot))
inspectDCS(snapshot)
test "Migration":
# Start with a fresh database.
removeDir(databaseRoot)
createDir(databaseRoot)
# Make sure there's no DepositTreeSnapshot yet.
let db = BeaconChainDB.new(databaseRoot, inMemory=false)
check(db.getDepositTreeSnapshot().isErr())
# Setup fixture.
fixture1()
# Make sure there's still no DepositTreeSnapshot as
# BeaconChainDB::getDepositTreeSnapshot() checks only for DCSv2.
check(db.getDepositTreeSnapshot().isErr())
# Migrate DB.
db.ifNecessaryMigrateDCS do (d: OldDepositContractSnapshot) -> DepositTreeSnapshot:
d.toDepositTreeSnapshot(11052984)
# Make sure now there actually is a snapshot.
check(db.getDepositTreeSnapshot().isOk())
# Inspect content.
let snapshot = db.getDepositTreeSnapshot().expect("")
inspectDCS(snapshot, 11052984)
test "depositCount":
var rand = initRand(12345678)
for i in 1..1000:
let n = rand.next()
let m = n mod 4294967296'u64
check(depositCountU64(depositCountBytes(m)) == m)
test "isValid":
const ZERO = toDigest("0000000000000000000000000000000000000000000000000000000000000000")
# Use our hard-coded ds1 as a model.
var model: OldDepositContractSnapshot
check(decodeSSZ(ds1, model))
# Check blockHeight.
var dcs = model.toDepositTreeSnapshot(0)
check(not dcs.isValid(ds1Root))
dcs.blockHeight = 11052984
check(dcs.isValid(ds1Root))
# Check eth1Block.
dcs.eth1Block = ZERO
check(not dcs.isValid(ds1Root))
dcs.eth1Block = model.eth1Block
check(dcs.isValid(ds1Root))
# Check branch.
for i in 0..len(dcs.depositContractState.branch)-1:
dcs.depositContractState.branch[i] = ZERO
check(not dcs.isValid(ds1Root))
dcs.depositContractState.branch = model.depositContractState.branch
check(dcs.isValid(ds1Root))
# Check deposit count.
for i in 0..len(dcs.depositContractState.deposit_count)-1:
dcs.depositContractState.deposit_count[i] = 0
check(not dcs.isValid(ds1Root))
dcs.depositContractState.deposit_count = model.depositContractState.deposit_count
check(dcs.isValid(ds1Root))