updated tests
This commit is contained in:
parent
be592e02fe
commit
5463be58cf
|
@ -75,6 +75,13 @@ proc getElectraStateRef(db: BeaconChainDB, root: Eth2Digest):
|
|||
if db.getState(root, res[], noRollback):
|
||||
return res
|
||||
|
||||
proc getFuluStateRef(db: BeaconChainDB, root: Eth2Digest):
|
||||
fulu.NilableBeaconStateRef =
|
||||
# load beaconstate the way the block pool does it - into an existence instance
|
||||
let res = (fulu.BeaconStateRef)()
|
||||
if db.getState(root, res[], noRollback):
|
||||
return res
|
||||
|
||||
func withDigest(blck: phase0.TrustedBeaconBlock):
|
||||
phase0.TrustedSignedBeaconBlock =
|
||||
phase0.TrustedSignedBeaconBlock(
|
||||
|
@ -117,6 +124,13 @@ func withDigest(blck: electra.TrustedBeaconBlock):
|
|||
root: hash_tree_root(blck)
|
||||
)
|
||||
|
||||
func withDigest(blck: fulu.TrustedBeaconBlock):
|
||||
fulu.TrustedSignedBeaconBlock =
|
||||
fulu.TrustedSignedBeaconBlock(
|
||||
message: blck,
|
||||
root: hash_tree_root(blck)
|
||||
)
|
||||
|
||||
proc getTestStates(consensusFork: ConsensusFork): auto =
|
||||
let
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
|
@ -138,12 +152,15 @@ let
|
|||
testStatesCapella = getTestStates(ConsensusFork.Capella)
|
||||
testStatesDeneb = getTestStates(ConsensusFork.Deneb)
|
||||
testStatesElectra = getTestStates(ConsensusFork.Electra)
|
||||
testStatesFulu = getTestStates(ConsensusFork.Fulu)
|
||||
|
||||
doAssert len(testStatesPhase0) > 8
|
||||
doAssert len(testStatesAltair) > 8
|
||||
doAssert len(testStatesBellatrix) > 8
|
||||
doAssert len(testStatesCapella) > 8
|
||||
doAssert len(testStatesDeneb) > 8
|
||||
doAssert len(testStatesElectra) > 8
|
||||
doAssert len(testStatesFulu) > 8
|
||||
|
||||
suite "Beacon chain DB" & preset():
|
||||
test "empty database" & preset():
|
||||
|
@ -187,6 +204,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, phase0.TrustedSignedBeaconBlock).isErr()
|
||||
not db.getBlockSSZ(root, tmp, phase0.TrustedSignedBeaconBlock)
|
||||
not db.getBlockSZ(root, tmp2, phase0.TrustedSignedBeaconBlock)
|
||||
|
@ -220,6 +238,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, altair.TrustedSignedBeaconBlock).get() == signedBlock
|
||||
db.getBlockSSZ(root, tmp, altair.TrustedSignedBeaconBlock)
|
||||
db.getBlockSZ(root, tmp2, altair.TrustedSignedBeaconBlock)
|
||||
|
@ -236,6 +255,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, altair.TrustedSignedBeaconBlock).isErr()
|
||||
not db.getBlockSSZ(root, tmp, altair.TrustedSignedBeaconBlock)
|
||||
not db.getBlockSZ(root, tmp2, altair.TrustedSignedBeaconBlock)
|
||||
|
@ -269,6 +289,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, bellatrix.TrustedSignedBeaconBlock).get() == signedBlock
|
||||
db.getBlockSSZ(root, tmp, bellatrix.TrustedSignedBeaconBlock)
|
||||
db.getBlockSZ(root, tmp2, bellatrix.TrustedSignedBeaconBlock)
|
||||
|
@ -285,6 +306,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, bellatrix.TrustedSignedBeaconBlock).isErr()
|
||||
not db.getBlockSSZ(root, tmp, bellatrix.TrustedSignedBeaconBlock)
|
||||
not db.getBlockSZ(root, tmp2, bellatrix.TrustedSignedBeaconBlock)
|
||||
|
@ -317,6 +339,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, bellatrix.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, capella.TrustedSignedBeaconBlock).get() == signedBlock
|
||||
db.getBlockSSZ(root, tmp, capella.TrustedSignedBeaconBlock)
|
||||
|
@ -334,6 +357,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, capella.TrustedSignedBeaconBlock).isErr()
|
||||
not db.getBlockSSZ(root, tmp, capella.TrustedSignedBeaconBlock)
|
||||
not db.getBlockSZ(root, tmp2, capella.TrustedSignedBeaconBlock)
|
||||
|
@ -367,6 +391,7 @@ suite "Beacon chain DB" & preset():
|
|||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, deneb.TrustedSignedBeaconBlock).get() == signedBlock
|
||||
db.getBlockSSZ(root, tmp, deneb.TrustedSignedBeaconBlock)
|
||||
db.getBlockSZ(root, tmp2, deneb.TrustedSignedBeaconBlock)
|
||||
|
@ -447,6 +472,57 @@ suite "Beacon chain DB" & preset():
|
|||
|
||||
db.close()
|
||||
|
||||
test "sanity check Fulu blocks" & preset():
|
||||
let db = BeaconChainDB.new("", inMemory = true)
|
||||
|
||||
let
|
||||
signedBlock = withDigest((fulu.TrustedBeaconBlock)())
|
||||
root = hash_tree_root(signedBlock.message)
|
||||
|
||||
db.putBlock(signedBlock)
|
||||
|
||||
var tmp, tmp2: seq[byte]
|
||||
check:
|
||||
db.containsBlock(root)
|
||||
not db.containsBlock(root, phase0.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, altair.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, bellatrix.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, fulu.TrustedSignedBeaconBlock).get() == signedBlock
|
||||
db.getBlockSSZ(root, tmp, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlockSZ(root, tmp2, fulu.TrustedSignedBeaconBlock)
|
||||
tmp == SSZ.encode(signedBlock)
|
||||
tmp2 == encodeFramed(tmp)
|
||||
uncompressedLenFramed(tmp2).isSome
|
||||
|
||||
check:
|
||||
db.delBlock(ConsensusFork.Fulu, root)
|
||||
not db.containsBlock(root)
|
||||
not db.containsBlock(root, phase0.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, altair.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, bellatrix.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, capella.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, deneb.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, electra.TrustedSignedBeaconBlock)
|
||||
not db.containsBlock(root, fulu.TrustedSignedBeaconBlock)
|
||||
db.getBlock(root, fulu.TrustedSignedBeaconBlock).isErr()
|
||||
not db.getBlockSSZ(root, tmp, fulu.TrustedSignedBeaconBlock)
|
||||
not db.getBlockSZ(root, tmp2, fulu.TrustedSignedBeaconBlock)
|
||||
|
||||
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():
|
||||
let db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
|
||||
|
@ -555,6 +631,24 @@ suite "Beacon chain DB" & preset():
|
|||
|
||||
db.close()
|
||||
|
||||
test "sanity check Fulu states" & preset():
|
||||
let db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
|
||||
for state in testStatesFulu:
|
||||
let root = state[].fuluData.root
|
||||
db.putState(root, state[].fuluData.data)
|
||||
|
||||
check:
|
||||
db.containsState(root)
|
||||
hash_tree_root(db.getFuluStateRef(root)[]) == root
|
||||
|
||||
db.delState(ConsensusFork.Fulu, root)
|
||||
check:
|
||||
not db.containsState(root)
|
||||
db.getFuluStateRef(root).isNil
|
||||
|
||||
db.close()
|
||||
|
||||
test "sanity check phase 0 states, reusing buffers" & preset():
|
||||
let db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
let stateBuffer = (phase0.BeaconStateRef)()
|
||||
|
@ -675,6 +769,26 @@ suite "Beacon chain DB" & preset():
|
|||
|
||||
db.close()
|
||||
|
||||
test "sanity check Fulu states, reusing buffers" & preset():
|
||||
let db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
let stateBuffer = (fulu.BeaconStateRef)()
|
||||
|
||||
for state in testStatesFulu:
|
||||
let root = state[].fuluData.root
|
||||
db.putState(root, state[].fuluData.data)
|
||||
|
||||
check:
|
||||
db.getState(root, stateBuffer[], noRollback)
|
||||
db.containsState(root)
|
||||
hash_tree_root(stateBuffer[]) == root
|
||||
|
||||
db.delState(ConsensusFork.Fulu, 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)
|
||||
|
@ -828,6 +942,32 @@ suite "Beacon chain DB" & preset():
|
|||
state[].kind == ConsensusFork.Phase0
|
||||
state[].phase0Data.data.slot != 10.Slot
|
||||
|
||||
test "sanity check Fulu and cross-fork getState rollback" & preset():
|
||||
var
|
||||
db = makeTestDB(SLOTS_PER_EPOCH)
|
||||
validatorMonitor = newClone(ValidatorMonitor.init())
|
||||
dag = init(ChainDAGRef, defaultRuntimeConfig, db, validatorMonitor, {})
|
||||
state = (ref ForkedHashedBeaconState)(
|
||||
kind: ConsensusFork.Fulu,
|
||||
fuluData: fulu.HashedBeaconState(data: fulu.BeaconState(
|
||||
slot: 10.Slot)))
|
||||
root = Eth2Digest()
|
||||
|
||||
db.putCorruptState(ConsensusFork.Fulu, root)
|
||||
|
||||
let restoreAddr = addr dag.headState
|
||||
|
||||
func restore() =
|
||||
assign(state[], restoreAddr[])
|
||||
|
||||
check:
|
||||
state[].fuluData.data.slot == 10.Slot
|
||||
not db.getState(root, state[].fuluData.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)
|
||||
|
||||
|
|
|
@ -25,13 +25,14 @@ suite "Light client" & preset():
|
|||
headPeriod = 4.SyncCommitteePeriod
|
||||
let
|
||||
cfg = block: # Fork schedule so that each `LightClientDataFork` is covered
|
||||
static: doAssert ConsensusFork.high == ConsensusFork.Electra
|
||||
static: doAssert ConsensusFork.high == ConsensusFork.Fulu
|
||||
var res = defaultRuntimeConfig
|
||||
res.ALTAIR_FORK_EPOCH = 1.Epoch
|
||||
res.BELLATRIX_FORK_EPOCH = 2.Epoch
|
||||
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
|
||||
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
|
||||
res.ELECTRA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 3).Epoch
|
||||
res.FULU_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 4).Epoch
|
||||
res
|
||||
altairStartSlot = cfg.ALTAIR_FORK_EPOCH.start_slot
|
||||
|
||||
|
|
|
@ -28,13 +28,14 @@ suite "Light client processor" & preset():
|
|||
highPeriod = 6.SyncCommitteePeriod
|
||||
let
|
||||
cfg = block: # Fork schedule so that each `LightClientDataFork` is covered
|
||||
static: doAssert ConsensusFork.high == ConsensusFork.Electra
|
||||
static: doAssert ConsensusFork.high == ConsensusFork.Fulu
|
||||
var res = defaultRuntimeConfig
|
||||
res.ALTAIR_FORK_EPOCH = 1.Epoch
|
||||
res.BELLATRIX_FORK_EPOCH = 2.Epoch
|
||||
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
|
||||
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
|
||||
res.ELECTRA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 3).Epoch
|
||||
res.FULU_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 4).Epoch
|
||||
res
|
||||
|
||||
const numValidators = SLOTS_PER_EPOCH
|
||||
|
|
|
@ -138,6 +138,7 @@ suite "Remove keystore testing suite":
|
|||
check keystore.provenBlockProperties[0].capellaIndex == some GeneralizedIndex(401)
|
||||
check keystore.provenBlockProperties[0].denebIndex == some GeneralizedIndex(801)
|
||||
check keystore.provenBlockProperties[0].electraIndex == some GeneralizedIndex(801)
|
||||
check keystore.provenBlockProperties[0].fuluIndex == some GeneralizedIndex(801)
|
||||
|
||||
test "Verifying Signer / Many remotes":
|
||||
for version in [3]:
|
||||
|
@ -186,4 +187,5 @@ suite "Remove keystore testing suite":
|
|||
check keystore.provenBlockProperties.len == 1
|
||||
check keystore.provenBlockProperties[0].capellaIndex == some GeneralizedIndex(401)
|
||||
check keystore.provenBlockProperties[0].denebIndex == some GeneralizedIndex(801)
|
||||
check keystore.provenBlockProperties[0].electraIndex == some GeneralizedIndex(801)
|
||||
check keystore.provenBlockProperties[0].electraIndex == some GeneralizedIndex(801)
|
||||
check keystore.provenBlockProperties[0].fuluIndex == some GeneralizedIndex(801)
|
|
@ -105,6 +105,9 @@ proc getBlock(
|
|||
of ConsensusFork.Electra:
|
||||
debugComment "electra test signing node getblock"
|
||||
raiseAssert "electra unsupported"
|
||||
of ConsensusFork.Fulu:
|
||||
debugFuluComment "electra test signing node getblock"
|
||||
raiseAssert "fulu unsupported"
|
||||
except ValueError:
|
||||
# https://github.com/nim-lang/Nim/pull/23356
|
||||
raiseAssert "Arguments match the format string"
|
||||
|
@ -128,6 +131,10 @@ func init(t: typedesc[Web3SignerForkedBeaconBlock],
|
|||
Web3SignerForkedBeaconBlock(
|
||||
kind: ConsensusFork.Electra,
|
||||
data: forked.electraData.toBeaconBlockHeader)
|
||||
of ConsensusFork.Fulu:
|
||||
Web3SignerForkedBeaconBlock(
|
||||
kind: ConsensusFork.Fulu,
|
||||
data: forked.fuluData.toBeaconBlockHeader)
|
||||
|
||||
proc createKeystore(dataDir, pubkey,
|
||||
store, password: string): Result[void, string] =
|
||||
|
@ -260,6 +267,7 @@ func getRemoteKeystoreData(data: string, basePort: int,
|
|||
provenBlockProperties: @[
|
||||
ProvenProperty(
|
||||
path: ".execution_payload.fee_recipient",
|
||||
fuluIndex: some GeneralizedIndex(801),
|
||||
electraIndex: some GeneralizedIndex(801),
|
||||
denebIndex: some GeneralizedIndex(801),
|
||||
capellaIndex: some GeneralizedIndex(401)
|
||||
|
|
|
@ -12,7 +12,8 @@ import
|
|||
# Beacon chain internals
|
||||
../beacon_chain/spec/helpers,
|
||||
../beacon_chain/spec/datatypes/[bellatrix, capella],
|
||||
../beacon_chain/spec/mev/[bellatrix_mev, capella_mev, deneb_mev, electra_mev],
|
||||
../beacon_chain/spec/mev/[bellatrix_mev, capella_mev, deneb_mev, electra_mev,
|
||||
fulu_mev],
|
||||
# Test utilities
|
||||
unittest2
|
||||
|
||||
|
@ -130,6 +131,17 @@ template electra_steps() =
|
|||
default(ConsolidationRequest))
|
||||
do_check
|
||||
|
||||
template fulu_steps() =
|
||||
check: b.message.body.execution_requests.deposits.add(
|
||||
default(DepositRequest))
|
||||
do_check
|
||||
check: b.message.body.execution_requests.withdrawals.add(
|
||||
default(WithdrawalRequest))
|
||||
do_check
|
||||
check: b.message.body.execution_requests.consolidations.add(
|
||||
default(ConsolidationRequest))
|
||||
do_check
|
||||
|
||||
suite "Blinded block conversions":
|
||||
withAll(ConsensusFork):
|
||||
when consensusFork >= ConsensusFork.Bellatrix:
|
||||
|
@ -143,4 +155,6 @@ suite "Blinded block conversions":
|
|||
deneb_steps
|
||||
when consensusFork >= ConsensusFork.Electra:
|
||||
electra_steps
|
||||
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
|
||||
when consensusFork >= ConsensusFork.Fulu:
|
||||
fulu_steps
|
||||
static: doAssert high(ConsensusFork) == ConsensusFork.Fulu
|
||||
|
|
|
@ -79,6 +79,7 @@ suite "Validator change pool testing suite":
|
|||
tmp.CAPELLA_FORK_EPOCH = Epoch(tmp.SHARD_COMMITTEE_PERIOD) + 2
|
||||
tmp.DENEB_FORK_EPOCH = Epoch(tmp.SHARD_COMMITTEE_PERIOD) + 3
|
||||
tmp.ELECTRA_FORK_EPOCH = Epoch(tmp.SHARD_COMMITTEE_PERIOD) + 4
|
||||
tmp.FULU_FORK_EPOCH = Epoch(tmp.SHARD_COMMITTEE_PERIOD) + 5
|
||||
tmp
|
||||
|
||||
validatorMonitor = newClone(ValidatorMonitor.init())
|
||||
|
|
|
@ -31,6 +31,11 @@ proc makeTestDB*(
|
|||
cfg.CAPELLA_FORK_EPOCH = 90000.Epoch
|
||||
if cfg.DENEB_FORK_EPOCH == FAR_FUTURE_EPOCH:
|
||||
cfg.DENEB_FORK_EPOCH = 100000.Epoch
|
||||
if cfg.ELECTRA_FORK_EPOCH == FAR_FUTURE_EPOCH:
|
||||
cfg.ELECTRA_FORK_EPOCH = 110000.Epoch
|
||||
if cfg.FULU_FORK_EPOCH == FAR_FUTURE_EPOCH:
|
||||
cfg.FULU_FORK_EPOCH = 120000.Epoch
|
||||
|
||||
|
||||
var genState = (ref ForkedHashedBeaconState)(
|
||||
kind: ConsensusFork.Phase0,
|
||||
|
|
|
@ -91,7 +91,7 @@ proc getTestStates*(
|
|||
if consensusFork >= ConsensusFork.Electra:
|
||||
cfg.ELECTRA_FORK_EPOCH = 5.Epoch
|
||||
if consensusFork >= ConsensusFork.Fulu:
|
||||
cfg.ELECTRA_FORK_EPOCH = 6.Epoch
|
||||
cfg.FULU_FORK_EPOCH = 6.Epoch
|
||||
|
||||
for i, epoch in stateEpochs:
|
||||
let slot = epoch.Epoch.start_slot
|
||||
|
|
Loading…
Reference in New Issue