Pass the test suite with a BeaconState ref type
This commit is contained in:
parent
740b76d152
commit
fdcbfdff05
|
@ -1,7 +1,7 @@
|
||||||
{.push raises: [Defect].}
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
import
|
import
|
||||||
options, typetraits, stew/endians2,
|
options, typetraits, stew/[results, endians2],
|
||||||
serialization, chronicles,
|
serialization, chronicles,
|
||||||
spec/[datatypes, digest, crypto],
|
spec/[datatypes, digest, crypto],
|
||||||
kvstore, ssz
|
kvstore, ssz
|
||||||
|
@ -68,11 +68,11 @@ proc init*(T: type BeaconChainDB, backend: KVStoreRef): BeaconChainDB =
|
||||||
proc put(db: BeaconChainDB, key: openArray[byte], v: auto) =
|
proc put(db: BeaconChainDB, key: openArray[byte], v: auto) =
|
||||||
db.backend.put(key, SSZ.encode(v)).expect("working database")
|
db.backend.put(key, SSZ.encode(v)).expect("working database")
|
||||||
|
|
||||||
proc get(db: BeaconChainDB, key: openArray[byte], T: typedesc): Option[T] =
|
proc get(db: BeaconChainDB, key: openArray[byte], T: typedesc): Opt[T] =
|
||||||
var res: Option[T]
|
var res: Opt[T]
|
||||||
proc decode(data: openArray[byte]) =
|
proc decode(data: openArray[byte]) =
|
||||||
try:
|
try:
|
||||||
res = some(SSZ.decode(data, T))
|
res.ok SSZ.decode(data, T)
|
||||||
except SerializationError as e:
|
except SerializationError as e:
|
||||||
# If the data can't be deserialized, it could be because it's from a
|
# If the data can't be deserialized, it could be because it's from a
|
||||||
# version of the software that uses a different SSZ encoding
|
# version of the software that uses a different SSZ encoding
|
||||||
|
@ -119,20 +119,21 @@ proc putHeadBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||||
proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
|
||||||
db.backend.put(subkey(kTailBlock), key.data).expect("working database")
|
db.backend.put(subkey(kTailBlock), key.data).expect("working database")
|
||||||
|
|
||||||
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Option[SignedBeaconBlock] =
|
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[SignedBeaconBlock] =
|
||||||
db.get(subkey(SignedBeaconBlock, key), SignedBeaconBlock)
|
db.get(subkey(SignedBeaconBlock, key), SignedBeaconBlock)
|
||||||
|
|
||||||
proc getState*(db: BeaconChainDB, key: Eth2Digest): Option[BeaconState] =
|
proc getState*(db: BeaconChainDB, key: Eth2Digest): Opt[BeaconState] =
|
||||||
db.get(subkey(BeaconState, key), BeaconState)
|
db.get(subkey(BeaconState, key), BeaconState)
|
||||||
|
|
||||||
proc getStateRoot*(db: BeaconChainDB, root: Eth2Digest, slot: Slot):
|
proc getStateRoot*(db: BeaconChainDB,
|
||||||
Option[Eth2Digest] =
|
root: Eth2Digest,
|
||||||
|
slot: Slot): Opt[Eth2Digest] =
|
||||||
db.get(subkey(root, slot), Eth2Digest)
|
db.get(subkey(root, slot), Eth2Digest)
|
||||||
|
|
||||||
proc getHeadBlock*(db: BeaconChainDB): Option[Eth2Digest] =
|
proc getHeadBlock*(db: BeaconChainDB): Opt[Eth2Digest] =
|
||||||
db.get(subkey(kHeadBlock), Eth2Digest)
|
db.get(subkey(kHeadBlock), Eth2Digest)
|
||||||
|
|
||||||
proc getTailBlock*(db: BeaconChainDB): Option[Eth2Digest] =
|
proc getTailBlock*(db: BeaconChainDB): Opt[Eth2Digest] =
|
||||||
db.get(subkey(kTailBlock), Eth2Digest)
|
db.get(subkey(kTailBlock), Eth2Digest)
|
||||||
|
|
||||||
proc containsBlock*(
|
proc containsBlock*(
|
||||||
|
@ -151,7 +152,7 @@ iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
|
||||||
## The search will go on until the ancestor cannot be found.
|
## The search will go on until the ancestor cannot be found.
|
||||||
|
|
||||||
var root = root
|
var root = root
|
||||||
while (let blck = db.getBlock(root); blck.isSome()):
|
while (let blck = db.getBlock(root); blck.isOk()):
|
||||||
yield (root, blck.get())
|
yield (root, blck.get())
|
||||||
|
|
||||||
root = blck.get().message.parent_root
|
root = blck.get().message.parent_root
|
||||||
|
|
|
@ -86,7 +86,7 @@ proc saveValidatorKey(keyName, key: string, conf: BeaconNodeConf) =
|
||||||
writeFile(outputFile, key)
|
writeFile(outputFile, key)
|
||||||
info "Imported validator key", file = outputFile
|
info "Imported validator key", file = outputFile
|
||||||
|
|
||||||
proc getStateFromSnapshot(conf: BeaconNodeConf, state: var BeaconState): bool =
|
proc getStateFromSnapshot(conf: BeaconNodeConf): NilableBeaconState =
|
||||||
var
|
var
|
||||||
genesisPath = conf.dataDir/genesisFile
|
genesisPath = conf.dataDir/genesisFile
|
||||||
snapshotContents: TaintedString
|
snapshotContents: TaintedString
|
||||||
|
@ -122,7 +122,7 @@ proc getStateFromSnapshot(conf: BeaconNodeConf, state: var BeaconState): bool =
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
state = SSZ.decode(snapshotContents, BeaconState)
|
result = SSZ.decode(snapshotContents, BeaconState)
|
||||||
except SerializationError:
|
except SerializationError:
|
||||||
error "Failed to import genesis file", path = genesisPath
|
error "Failed to import genesis file", path = genesisPath
|
||||||
quit 1
|
quit 1
|
||||||
|
@ -138,8 +138,6 @@ proc getStateFromSnapshot(conf: BeaconNodeConf, state: var BeaconState): bool =
|
||||||
err = err.msg, genesisFile = conf.dataDir/genesisFile
|
err = err.msg, genesisFile = conf.dataDir/genesisFile
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
result = true
|
|
||||||
|
|
||||||
proc enrForkIdFromState(state: BeaconState): ENRForkID =
|
proc enrForkIdFromState(state: BeaconState): ENRForkID =
|
||||||
let
|
let
|
||||||
forkVer = state.fork.current_version
|
forkVer = state.fork.current_version
|
||||||
|
@ -161,10 +159,10 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
|
||||||
|
|
||||||
if not BlockPool.isInitialized(db):
|
if not BlockPool.isInitialized(db):
|
||||||
# Fresh start - need to load a genesis state from somewhere
|
# Fresh start - need to load a genesis state from somewhere
|
||||||
var genesisState = new BeaconState
|
var genesisState = conf.getStateFromSnapshot()
|
||||||
|
|
||||||
# Try file from command line first
|
# Try file from command line first
|
||||||
if not conf.getStateFromSnapshot(genesisState[]):
|
if genesisState.isNil:
|
||||||
# Didn't work, try creating a genesis state using main chain monitor
|
# Didn't work, try creating a genesis state using main chain monitor
|
||||||
# TODO Could move this to a separate "GenesisMonitor" process or task
|
# TODO Could move this to a separate "GenesisMonitor" process or task
|
||||||
# that would do only this - see
|
# that would do only this - see
|
||||||
|
@ -178,23 +176,27 @@ proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async
|
||||||
error "No initial state, need genesis state or deposit contract address"
|
error "No initial state, need genesis state or deposit contract address"
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
genesisState[] = await mainchainMonitor.getGenesis()
|
genesisState = await mainchainMonitor.getGenesis()
|
||||||
|
|
||||||
if genesisState[].slot != GENESIS_SLOT:
|
# This is needed to prove the not nil property from here on
|
||||||
# TODO how to get a block from a non-genesis state?
|
if genesisState == nil:
|
||||||
error "Starting from non-genesis state not supported",
|
doAssert false
|
||||||
stateSlot = genesisState[].slot,
|
else:
|
||||||
stateRoot = hash_tree_root(genesisState[])
|
if genesisState.slot != GENESIS_SLOT:
|
||||||
quit 1
|
# TODO how to get a block from a non-genesis state?
|
||||||
|
error "Starting from non-genesis state not supported",
|
||||||
|
stateSlot = genesisState.slot,
|
||||||
|
stateRoot = hash_tree_root(genesisState)
|
||||||
|
quit 1
|
||||||
|
|
||||||
let tailBlock = get_initial_beacon_block(genesisState[])
|
let tailBlock = get_initial_beacon_block(genesisState)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
BlockPool.preInit(db, genesisState[], tailBlock)
|
BlockPool.preInit(db, genesisState, tailBlock)
|
||||||
doAssert BlockPool.isInitialized(db), "preInit should have initialized db"
|
doAssert BlockPool.isInitialized(db), "preInit should have initialized db"
|
||||||
except CatchableError as e:
|
except CatchableError as e:
|
||||||
error "Failed to initialize database", err = e.msg
|
error "Failed to initialize database", err = e.msg
|
||||||
quit 1
|
quit 1
|
||||||
|
|
||||||
# TODO check that genesis given on command line (if any) matches database
|
# TODO check that genesis given on command line (if any) matches database
|
||||||
let
|
let
|
||||||
|
@ -1057,7 +1059,7 @@ proc installBeaconApiHandlers(rpcServer: RpcServer, node: BeaconNode) =
|
||||||
requireOneOf(slot, root)
|
requireOneOf(slot, root)
|
||||||
if slot.isSome:
|
if slot.isSome:
|
||||||
let blk = node.blockPool.head.blck.atSlot(slot.get)
|
let blk = node.blockPool.head.blck.atSlot(slot.get)
|
||||||
var tmpState: StateData
|
var tmpState = emptyStateData()
|
||||||
node.blockPool.withState(tmpState, blk):
|
node.blockPool.withState(tmpState, blk):
|
||||||
return jsonResult(state)
|
return jsonResult(state)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -225,6 +225,20 @@ type
|
||||||
root*: Eth2Digest
|
root*: Eth2Digest
|
||||||
historySlots*: uint64
|
historySlots*: uint64
|
||||||
|
|
||||||
|
func emptyStateData*: StateData =
|
||||||
|
StateData(
|
||||||
|
data: HashedBeaconState(
|
||||||
|
# Please note that this initialization is needed in order
|
||||||
|
# to allocate memory for the BeaconState:
|
||||||
|
data: BeaconState(),
|
||||||
|
root: default(Eth2Digest)
|
||||||
|
),
|
||||||
|
blck: default(BlockRef))
|
||||||
|
|
||||||
|
func clone*(other: StateData): StateData =
|
||||||
|
StateData(data: clone(other.data),
|
||||||
|
blck: other.blck)
|
||||||
|
|
||||||
proc shortLog*(v: AttachedValidator): string = shortLog(v.pubKey)
|
proc shortLog*(v: AttachedValidator): string = shortLog(v.pubKey)
|
||||||
|
|
||||||
chronicles.formatIt BlockSlot:
|
chronicles.formatIt BlockSlot:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
bitops, chronicles, options, tables,
|
bitops, chronicles, options, tables,
|
||||||
ssz, beacon_chain_db, state_transition, extras, kvstore,
|
stew/results, ssz, beacon_chain_db, state_transition, extras, kvstore,
|
||||||
beacon_node_types, metrics,
|
beacon_node_types, metrics,
|
||||||
spec/[crypto, datatypes, digest, helpers, validator]
|
spec/[crypto, datatypes, digest, helpers, validator]
|
||||||
|
|
||||||
|
@ -204,21 +204,20 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
"state data missing for tail block, database corrupt?"
|
"state data missing for tail block, database corrupt?"
|
||||||
latestStateRoot = some((tailBlock.message.state_root, tailRef))
|
latestStateRoot = some((tailBlock.message.state_root, tailRef))
|
||||||
|
|
||||||
# TODO can't do straight init because in mainnet config, there are too
|
|
||||||
# many live beaconstates on the stack...
|
|
||||||
var tmpState = new Option[BeaconState]
|
|
||||||
|
|
||||||
# We're only saving epoch boundary states in the database right now, so when
|
# We're only saving epoch boundary states in the database right now, so when
|
||||||
# we're loading the head block, the corresponding state does not necessarily
|
# we're loading the head block, the corresponding state does not necessarily
|
||||||
# exist in the database - we'll load this latest state we know about and use
|
# exist in the database - we'll load this latest state we know about and use
|
||||||
# that as finalization point.
|
# that as finalization point.
|
||||||
tmpState[] = db.getState(latestStateRoot.get().stateRoot)
|
let stateOpt = db.getState(latestStateRoot.get().stateRoot)
|
||||||
|
doAssert stateOpt.isSome, "failed to obtain latest state. database corrupt?"
|
||||||
|
let tmpState = stateOpt.get
|
||||||
|
|
||||||
let
|
let
|
||||||
finalizedSlot =
|
finalizedSlot =
|
||||||
tmpState[].get().finalized_checkpoint.epoch.compute_start_slot_at_epoch()
|
tmpState.finalized_checkpoint.epoch.compute_start_slot_at_epoch()
|
||||||
finalizedHead = headRef.findAncestorBySlot(finalizedSlot)
|
finalizedHead = headRef.findAncestorBySlot(finalizedSlot)
|
||||||
justifiedSlot =
|
justifiedSlot =
|
||||||
tmpState[].get().current_justified_checkpoint.epoch.compute_start_slot_at_epoch()
|
tmpState.current_justified_checkpoint.epoch.compute_start_slot_at_epoch()
|
||||||
justifiedHead = headRef.findAncestorBySlot(justifiedSlot)
|
justifiedHead = headRef.findAncestorBySlot(justifiedSlot)
|
||||||
head = Head(blck: headRef, justified: justifiedHead)
|
head = Head(blck: headRef, justified: justifiedHead)
|
||||||
justifiedBlock = db.getBlock(justifiedHead.blck.root).get()
|
justifiedBlock = db.getBlock(justifiedHead.blck.root).get()
|
||||||
|
@ -231,6 +230,18 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
head = head.blck, finalizedHead, tail = tailRef,
|
head = head.blck, finalizedHead, tail = tailRef,
|
||||||
totalBlocks = blocks.len
|
totalBlocks = blocks.len
|
||||||
|
|
||||||
|
let headState = StateData(
|
||||||
|
data: HashedBeaconState(
|
||||||
|
data: tmpState, root: latestStateRoot.get().stateRoot),
|
||||||
|
blck: latestStateRoot.get().blckRef)
|
||||||
|
|
||||||
|
let justifiedState = db.getState(justifiedStateRoot)
|
||||||
|
doAssert justifiedState.isSome,
|
||||||
|
"failed to obtain latest justified state. database corrupt?"
|
||||||
|
|
||||||
|
# For the initialization of `tmpState` below.
|
||||||
|
# Please note that it's initialized few lines below
|
||||||
|
{.push warning[UnsafeDefault]: off.}
|
||||||
let res = BlockPool(
|
let res = BlockPool(
|
||||||
pending: initTable[Eth2Digest, SignedBeaconBlock](),
|
pending: initTable[Eth2Digest, SignedBeaconBlock](),
|
||||||
missing: initTable[Eth2Digest, MissingBlock](),
|
missing: initTable[Eth2Digest, MissingBlock](),
|
||||||
|
@ -249,21 +260,17 @@ proc init*(T: type BlockPool, db: BeaconChainDB): BlockPool =
|
||||||
finalizedHead: finalizedHead,
|
finalizedHead: finalizedHead,
|
||||||
db: db,
|
db: db,
|
||||||
heads: @[head],
|
heads: @[head],
|
||||||
|
headState: headState,
|
||||||
|
justifiedState: StateData(
|
||||||
|
data: HashedBeaconState(data: justifiedState.get, root: justifiedStateRoot),
|
||||||
|
blck: justifiedHead.blck),
|
||||||
|
tmpState: default(StateData)
|
||||||
)
|
)
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
res.headState = StateData(
|
res.updateStateData(res.headState, BlockSlot(blck: head.blck,
|
||||||
data: HashedBeaconState(
|
slot: head.blck.slot))
|
||||||
data: tmpState[].get(), root: latestStateRoot.get().stateRoot),
|
res.tmpState = clone(res.headState)
|
||||||
blck: latestStateRoot.get().blckRef)
|
|
||||||
|
|
||||||
res.updateStateData(res.headState, BlockSlot(blck: head.blck, slot: head.blck.slot))
|
|
||||||
res.tmpState = res.headState
|
|
||||||
|
|
||||||
tmpState[] = db.getState(justifiedStateRoot)
|
|
||||||
res.justifiedState = StateData(
|
|
||||||
data: HashedBeaconState(data: tmpState[].get(), root: justifiedStateRoot),
|
|
||||||
blck: justifiedHead.blck)
|
|
||||||
|
|
||||||
res
|
res
|
||||||
|
|
||||||
proc addResolvedBlock(
|
proc addResolvedBlock(
|
||||||
|
@ -568,7 +575,7 @@ proc skipAndUpdateState(
|
||||||
|
|
||||||
skipAndUpdateState(state, signedBlock.message.slot - 1, afterUpdate)
|
skipAndUpdateState(state, signedBlock.message.slot - 1, afterUpdate)
|
||||||
|
|
||||||
let ok = state_transition(state, signedBlock, flags)
|
let ok = state_transition(state, signedBlock, flags)
|
||||||
|
|
||||||
afterUpdate(state)
|
afterUpdate(state)
|
||||||
|
|
||||||
|
@ -653,7 +660,7 @@ proc rewindState(pool: BlockPool, state: var StateData, bs: BlockSlot):
|
||||||
# writing and deleting state+root mappings in a single transaction, it's
|
# writing and deleting state+root mappings in a single transaction, it's
|
||||||
# likely to happen and we guard against it here.
|
# likely to happen and we guard against it here.
|
||||||
if stateRoot.isSome() and not pool.db.containsState(stateRoot.get()):
|
if stateRoot.isSome() and not pool.db.containsState(stateRoot.get()):
|
||||||
stateRoot = none(type(stateRoot.get()))
|
stateRoot.err()
|
||||||
|
|
||||||
while stateRoot.isNone():
|
while stateRoot.isNone():
|
||||||
let parBs = curBs.parent()
|
let parBs = curBs.parent()
|
||||||
|
@ -718,7 +725,7 @@ proc rewindState(pool: BlockPool, state: var StateData, bs: BlockSlot):
|
||||||
ancestors = ancestors.len,
|
ancestors = ancestors.len,
|
||||||
cat = "replay_state"
|
cat = "replay_state"
|
||||||
|
|
||||||
state.data.data = ancestorState.get()
|
state.data.data[] = ancestorState.get()[]
|
||||||
state.data.root = stateRoot.get()
|
state.data.root = stateRoot.get()
|
||||||
state.blck = ancestor.refs
|
state.blck = ancestor.refs
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ type
|
||||||
depositContractAddress: Address
|
depositContractAddress: Address
|
||||||
dataProviderFactory*: DataProviderFactory
|
dataProviderFactory*: DataProviderFactory
|
||||||
|
|
||||||
genesisState: ref BeaconState
|
genesisState: NilableBeaconState
|
||||||
genesisStateFut: Future[void]
|
genesisStateFut: Future[void]
|
||||||
|
|
||||||
eth1Chain: Eth1Chain
|
eth1Chain: Eth1Chain
|
||||||
|
@ -87,6 +87,10 @@ type
|
||||||
const
|
const
|
||||||
reorgDepthLimit = 1000
|
reorgDepthLimit = 1000
|
||||||
|
|
||||||
|
# TODO Nim's analysis on the lock level of the methods in this
|
||||||
|
# module seems broken. Investigate and file this as an issue.
|
||||||
|
{.push warning[LockLevel]: off.}
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#get_eth1_data
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/validator.md#get_eth1_data
|
||||||
func compute_time_at_slot(state: BeaconState, slot: Slot): uint64 =
|
func compute_time_at_slot(state: BeaconState, slot: Slot): uint64 =
|
||||||
return state.genesis_time + slot * SECONDS_PER_SLOT
|
return state.genesis_time + slot * SECONDS_PER_SLOT
|
||||||
|
@ -346,8 +350,7 @@ proc checkForGenesisEvent(m: MainchainMonitor) =
|
||||||
# https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start#create-genesis-state
|
# https://github.com/ethereum/eth2.0-pm/tree/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start#create-genesis-state
|
||||||
s.genesis_time = startTime
|
s.genesis_time = startTime
|
||||||
|
|
||||||
m.genesisState.new()
|
m.genesisState = clone(s)
|
||||||
m.genesisState[] = s
|
|
||||||
if not m.genesisStateFut.isNil:
|
if not m.genesisStateFut.isNil:
|
||||||
m.genesisStateFut.complete()
|
m.genesisStateFut.complete()
|
||||||
m.genesisStateFut = nil
|
m.genesisStateFut = nil
|
||||||
|
@ -436,8 +439,11 @@ proc getGenesis*(m: MainchainMonitor): Future[BeaconState] {.async.} =
|
||||||
await m.genesisStateFut
|
await m.genesisStateFut
|
||||||
m.genesisStateFut = nil
|
m.genesisStateFut = nil
|
||||||
|
|
||||||
doAssert(not m.genesisState.isNil)
|
if m.genesisState == nil:
|
||||||
return m.genesisState[]
|
doAssert(false)
|
||||||
|
return BeaconState()
|
||||||
|
else:
|
||||||
|
return m.genesisState
|
||||||
|
|
||||||
method getBlockByHash*(p: Web3DataProviderRef, hash: BlockHash): Future[BlockObject] =
|
method getBlockByHash*(p: Web3DataProviderRef, hash: BlockHash): Future[BlockObject] =
|
||||||
discard
|
discard
|
||||||
|
@ -585,7 +591,11 @@ proc stop*(m: MainchainMonitor) =
|
||||||
|
|
||||||
proc getLatestEth1BlockHash*(url: string): Future[Eth2Digest] {.async.} =
|
proc getLatestEth1BlockHash*(url: string): Future[Eth2Digest] {.async.} =
|
||||||
let web3 = await newWeb3(url)
|
let web3 = await newWeb3(url)
|
||||||
defer: await web3.close()
|
try:
|
||||||
let blk = await web3.provider.eth_getBlockByNumber("latest", false)
|
let blk = await web3.provider.eth_getBlockByNumber("latest", false)
|
||||||
return Eth2Digest(data: array[32, byte](blk.hash))
|
return Eth2Digest(data: array[32, byte](blk.hash))
|
||||||
|
finally:
|
||||||
|
await web3.close()
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
# TODO report compiler crash when this is uncommented
|
# TODO report compiler crash when this is uncommented
|
||||||
# {.push raises: [Defect].}
|
# {.push raises: [Defect].}
|
||||||
|
|
||||||
|
{.experimental: "notnil".}
|
||||||
|
|
||||||
import
|
import
|
||||||
macros, hashes, json, strutils, tables,
|
macros, hashes, json, strutils, tables,
|
||||||
stew/[byteutils, bitseqs], chronicles,
|
stew/[byteutils, bitseqs], chronicles,
|
||||||
|
@ -242,7 +244,7 @@ type
|
||||||
voluntary_exits*: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
|
voluntary_exits*: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS]
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconstate
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconstate
|
||||||
BeaconState* = object
|
BeaconStateObj* = object
|
||||||
# Versioning
|
# Versioning
|
||||||
genesis_time*: uint64
|
genesis_time*: uint64
|
||||||
genesis_validators_root*: Eth2Digest
|
genesis_validators_root*: Eth2Digest
|
||||||
|
@ -294,6 +296,9 @@ type
|
||||||
current_justified_checkpoint*: Checkpoint
|
current_justified_checkpoint*: Checkpoint
|
||||||
finalized_checkpoint*: Checkpoint
|
finalized_checkpoint*: Checkpoint
|
||||||
|
|
||||||
|
BeaconState* = ref BeaconStateObj not nil
|
||||||
|
NilableBeaconState* = ref BeaconStateObj
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#validator
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#validator
|
||||||
Validator* = object
|
Validator* = object
|
||||||
pubkey*: ValidatorPubKey
|
pubkey*: ValidatorPubKey
|
||||||
|
@ -565,6 +570,15 @@ template readValue*(reader: var JsonReader, value: var BitList) =
|
||||||
template writeValue*(writer: var JsonWriter, value: BitList) =
|
template writeValue*(writer: var JsonWriter, value: BitList) =
|
||||||
writeValue(writer, BitSeq value)
|
writeValue(writer, BitSeq value)
|
||||||
|
|
||||||
|
func clone*[T](x: ref T): ref T not nil =
|
||||||
|
new result
|
||||||
|
result[] = x[]
|
||||||
|
|
||||||
|
func clone*(other: HashedBeaconState): HashedBeaconState =
|
||||||
|
HashedBeaconState(
|
||||||
|
data: clone(other.data),
|
||||||
|
root: other.root)
|
||||||
|
|
||||||
template init*(T: type BitList, len: int): auto = T init(BitSeq, len)
|
template init*(T: type BitList, len: int): auto = T init(BitSeq, len)
|
||||||
template len*(x: BitList): auto = len(BitSeq(x))
|
template len*(x: BitList): auto = len(BitSeq(x))
|
||||||
template bytes*(x: BitList): auto = bytes(BitSeq(x))
|
template bytes*(x: BitList): auto = bytes(BitSeq(x))
|
||||||
|
|
|
@ -170,7 +170,7 @@ func get_domain*(
|
||||||
state: BeaconState, domain_type: DomainType, epoch: Epoch): Domain =
|
state: BeaconState, domain_type: DomainType, epoch: Epoch): Domain =
|
||||||
## Return the signature domain (fork version concatenated with domain type)
|
## Return the signature domain (fork version concatenated with domain type)
|
||||||
## of a message.
|
## of a message.
|
||||||
get_domain(state.fork, domain_type, epoch, state. genesis_validators_root)
|
get_domain(state.fork, domain_type, epoch, state.genesis_validators_root)
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_signing_root
|
# https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_signing_root
|
||||||
func compute_signing_root*(ssz_object: auto, domain: Domain): Eth2Digest =
|
func compute_signing_root*(ssz_object: auto, domain: Domain): Eth2Digest =
|
||||||
|
|
|
@ -485,7 +485,7 @@ proc makeBeaconBlock*(
|
||||||
deposits: deposits)
|
deposits: deposits)
|
||||||
)
|
)
|
||||||
|
|
||||||
var tmpState = state
|
var tmpState = clone(state)
|
||||||
let ok = process_block(tmpState, blck, {skipBlsValidation}, cache)
|
let ok = process_block(tmpState, blck, {skipBlsValidation}, cache)
|
||||||
|
|
||||||
if not ok:
|
if not ok:
|
||||||
|
|
|
@ -148,7 +148,7 @@ template writeFixedSized(s: OutputStream, x: auto) =
|
||||||
|
|
||||||
template supports*(_: type SSZ, T: type): bool =
|
template supports*(_: type SSZ, T: type): bool =
|
||||||
mixin toSszType
|
mixin toSszType
|
||||||
anonConst compiles(fixedPortionSize toSszType(default(T)))
|
anonConst compiles(fixedPortionSize toSszType(declval T))
|
||||||
|
|
||||||
func init*(T: type SszWriter, stream: OutputStream): T {.raises: [Defect].} =
|
func init*(T: type SszWriter, stream: OutputStream): T {.raises: [Defect].} =
|
||||||
result.stream = stream
|
result.stream = stream
|
||||||
|
|
|
@ -84,9 +84,8 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} =
|
||||||
result = T readSszValue(input, seq[ElemType])
|
result = T readSszValue(input, seq[ElemType])
|
||||||
|
|
||||||
elif result is ptr|ref:
|
elif result is ptr|ref:
|
||||||
if input.len > 0:
|
new result
|
||||||
new result
|
result[] = readSszValue(input, type(result[]))
|
||||||
result[] = readSszValue(input, type(result[]))
|
|
||||||
|
|
||||||
elif result is Option:
|
elif result is Option:
|
||||||
if input.len > 0:
|
if input.len > 0:
|
||||||
|
@ -161,8 +160,8 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} =
|
||||||
const boundingOffsets = T.getFieldBoundingOffsets(fieldName)
|
const boundingOffsets = T.getFieldBoundingOffsets(fieldName)
|
||||||
trs "BOUNDING OFFSET FOR FIELD ", fieldName, " = ", boundingOffsets
|
trs "BOUNDING OFFSET FOR FIELD ", fieldName, " = ", boundingOffsets
|
||||||
|
|
||||||
type FieldType = type field
|
type FieldType = type maybeDeref(field)
|
||||||
type SszType = type toSszType(default(FieldType))
|
type SszType = type toSszType(declval FieldType)
|
||||||
|
|
||||||
when isFixedSize(SszType):
|
when isFixedSize(SszType):
|
||||||
const
|
const
|
||||||
|
@ -185,13 +184,21 @@ func readSszValue*(input: openarray[byte], T: type): T {.raisesssz.} =
|
||||||
# TODO The extra type escaping here is a work-around for a Nim issue:
|
# TODO The extra type escaping here is a work-around for a Nim issue:
|
||||||
when type(FieldType) is type(SszType):
|
when type(FieldType) is type(SszType):
|
||||||
trs "READING NATIVE ", fieldName, ": ", name(SszType)
|
trs "READING NATIVE ", fieldName, ": ", name(SszType)
|
||||||
field = readSszValue(input.toOpenArray(startOffset, endOffset - 1), SszType)
|
maybeDeref(field) = readSszValue(
|
||||||
|
input.toOpenArray(startOffset, endOffset - 1),
|
||||||
|
SszType)
|
||||||
trs "READING COMPLETE ", fieldName
|
trs "READING COMPLETE ", fieldName
|
||||||
|
|
||||||
elif useListType and FieldType is List:
|
elif useListType and FieldType is List:
|
||||||
field = readSszValue(input.toOpenArray(startOffset, endOffset - 1), FieldType)
|
maybeDeref(field) = readSszValue(
|
||||||
|
input.toOpenArray(startOffset, endOffset - 1),
|
||||||
|
FieldType)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
trs "READING FOREIGN ", fieldName, ": ", name(SszType)
|
trs "READING FOREIGN ", fieldName, ": ", name(SszType)
|
||||||
field = fromSszBytes(FieldType, input.toOpenArray(startOffset, endOffset - 1))
|
maybeDeref(field) = fromSszBytes(
|
||||||
|
FieldType,
|
||||||
|
input.toOpenArray(startOffset, endOffset - 1))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
unsupported T
|
unsupported T
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, parseutils,
|
strutils, parseutils,
|
||||||
faststreams/output_stream, json_serialization/writer,
|
stew/objects, faststreams/output_stream, json_serialization/writer,
|
||||||
../spec/datatypes,
|
../spec/datatypes,
|
||||||
types, bytes_reader, navigator
|
types, bytes_reader, navigator
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ proc typeInfo*(T: type): TypeInfo =
|
||||||
|
|
||||||
func genTypeInfo(T: type): TypeInfo =
|
func genTypeInfo(T: type): TypeInfo =
|
||||||
mixin toSszType, enumAllSerializedFields
|
mixin toSszType, enumAllSerializedFields
|
||||||
type SszType = type(toSszType default(T))
|
type SszType = type toSszType(declval T)
|
||||||
result = when type(SszType) isnot T:
|
result = when type(SszType) isnot T:
|
||||||
TypeInfo(kind: LeafValue)
|
TypeInfo(kind: LeafValue)
|
||||||
elif T is object:
|
elif T is object:
|
||||||
|
|
|
@ -40,7 +40,7 @@ func navigateToField*[T](n: SszNavigator[T],
|
||||||
fieldName: static string,
|
fieldName: static string,
|
||||||
FieldType: type): SszNavigator[FieldType] {.raisesssz.} =
|
FieldType: type): SszNavigator[FieldType] {.raisesssz.} =
|
||||||
mixin toSszType
|
mixin toSszType
|
||||||
type SszFieldType = type toSszType(default FieldType)
|
type SszFieldType = type toSszType(declval FieldType)
|
||||||
|
|
||||||
const boundingOffsets = getFieldBoundingOffsets(T, fieldName)
|
const boundingOffsets = getFieldBoundingOffsets(T, fieldName)
|
||||||
checkBounds(n.m, boundingOffsets[1])
|
checkBounds(n.m, boundingOffsets[1])
|
||||||
|
@ -101,7 +101,7 @@ func indexVarSizeList(m: MemRange, idx: int): MemRange {.raisesssz.} =
|
||||||
template indexList(n, idx, T: untyped): untyped =
|
template indexList(n, idx, T: untyped): untyped =
|
||||||
type R = T
|
type R = T
|
||||||
mixin toSszType
|
mixin toSszType
|
||||||
type ElemType = type toSszType(default R)
|
type ElemType = type toSszType(declval R)
|
||||||
when isFixedSize(ElemType):
|
when isFixedSize(ElemType):
|
||||||
const elemSize = fixedPortionSize(ElemType)
|
const elemSize = fixedPortionSize(ElemType)
|
||||||
let elemPos = idx * elemSize
|
let elemPos = idx * elemSize
|
||||||
|
@ -119,11 +119,16 @@ template `[]`*[R, T](n: SszNavigator[array[R, T]], idx: int): SszNavigator[T] =
|
||||||
|
|
||||||
func `[]`*[T](n: SszNavigator[T]): T {.raisesssz.} =
|
func `[]`*[T](n: SszNavigator[T]): T {.raisesssz.} =
|
||||||
mixin toSszType, fromSszBytes
|
mixin toSszType, fromSszBytes
|
||||||
type SszRepr = type(toSszType default(T))
|
when T is ref:
|
||||||
when type(SszRepr) is type(T):
|
type ObjectType = type(result[])
|
||||||
readSszValue(toOpenArray(n.m), T)
|
new result
|
||||||
|
result[] = SszNavigator[ObjectType](n)[]
|
||||||
else:
|
else:
|
||||||
fromSszBytes(T, toOpenArray(n.m))
|
type SszRepr = type toSszType(declval T)
|
||||||
|
when type(SszRepr) is type(T):
|
||||||
|
readSszValue(toOpenArray(n.m), T)
|
||||||
|
else:
|
||||||
|
fromSszBytes(T, toOpenArray(n.m))
|
||||||
|
|
||||||
converter derefNavigator*[T](n: SszNavigator[T]): T {.raisesssz.} =
|
converter derefNavigator*[T](n: SszNavigator[T]): T {.raisesssz.} =
|
||||||
n[]
|
n[]
|
||||||
|
|
|
@ -84,13 +84,19 @@ template ElemType*[T](A: type[openarray[T]]): untyped =
|
||||||
template ElemType*(T: type[seq|string|List]): untyped =
|
template ElemType*(T: type[seq|string|List]): untyped =
|
||||||
type(default(T)[0])
|
type(default(T)[0])
|
||||||
|
|
||||||
|
template maybeDeref*(x: auto): auto =
|
||||||
|
when type(x) is ref|ptr:
|
||||||
|
x[]
|
||||||
|
else:
|
||||||
|
x
|
||||||
|
|
||||||
func isFixedSize*(T0: type): bool {.compileTime.} =
|
func isFixedSize*(T0: type): bool {.compileTime.} =
|
||||||
mixin toSszType, enumAllSerializedFields
|
mixin toSszType, enumAllSerializedFields
|
||||||
|
|
||||||
when T0 is openarray|Option|ref|ptr:
|
when T0 is openarray|Option|ref|ptr:
|
||||||
return false
|
return false
|
||||||
else:
|
else:
|
||||||
type T = type toSszType(default T0)
|
type T = type toSszType(declval T0)
|
||||||
|
|
||||||
when T is BasicType:
|
when T is BasicType:
|
||||||
return true
|
return true
|
||||||
|
@ -104,7 +110,7 @@ func isFixedSize*(T0: type): bool {.compileTime.} =
|
||||||
|
|
||||||
func fixedPortionSize*(T0: type): int {.compileTime.} =
|
func fixedPortionSize*(T0: type): int {.compileTime.} =
|
||||||
mixin enumAllSerializedFields, toSszType
|
mixin enumAllSerializedFields, toSszType
|
||||||
type T = type toSszType(default T0)
|
type T = type toSszType(declval T0)
|
||||||
|
|
||||||
when T is BasicType: sizeof(T)
|
when T is BasicType: sizeof(T)
|
||||||
elif T is array:
|
elif T is array:
|
||||||
|
@ -123,7 +129,7 @@ func fixedPortionSize*(T0: type): int {.compileTime.} =
|
||||||
|
|
||||||
func sszSchemaType*(T0: type): SszType {.compileTime.} =
|
func sszSchemaType*(T0: type): SszType {.compileTime.} =
|
||||||
mixin toSszType, enumAllSerializedFields
|
mixin toSszType, enumAllSerializedFields
|
||||||
type T = type toSszType(default T0)
|
type T = type toSszType(declval T0)
|
||||||
|
|
||||||
when T is bool:
|
when T is bool:
|
||||||
SszType(kind: sszBool)
|
SszType(kind: sszBool)
|
||||||
|
|
|
@ -170,7 +170,7 @@ proc state_transition*(
|
||||||
|
|
||||||
## TODO, of cacheState/processEpoch/processSlot/processBloc, only the last
|
## TODO, of cacheState/processEpoch/processSlot/processBloc, only the last
|
||||||
## might fail, so should this bother capturing here, or?
|
## might fail, so should this bother capturing here, or?
|
||||||
var old_state = state
|
var old_state = clone(state)
|
||||||
|
|
||||||
# These should never fail.
|
# These should never fail.
|
||||||
process_slots(state, signedBlock.message.slot)
|
process_slots(state, signedBlock.message.slot)
|
||||||
|
@ -194,7 +194,7 @@ proc state_transition*(
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Block processing failed, roll back changes
|
# Block processing failed, roll back changes
|
||||||
state = old_state
|
state[] = old_state[]
|
||||||
false
|
false
|
||||||
|
|
||||||
# Hashed-state transition functions
|
# Hashed-state transition functions
|
||||||
|
@ -253,7 +253,7 @@ proc process_slots*(state: var HashedBeaconState, slot: Slot) =
|
||||||
proc state_transition*(
|
proc state_transition*(
|
||||||
state: var HashedBeaconState, signedBlock: SignedBeaconBlock, flags: UpdateFlags): bool =
|
state: var HashedBeaconState, signedBlock: SignedBeaconBlock, flags: UpdateFlags): bool =
|
||||||
# Save for rollback
|
# Save for rollback
|
||||||
var old_state = state
|
var old_state = clone(state)
|
||||||
|
|
||||||
process_slots(state, signedBlock.message.slot)
|
process_slots(state, signedBlock.message.slot)
|
||||||
|
|
||||||
|
@ -275,5 +275,6 @@ proc state_transition*(
|
||||||
return true
|
return true
|
||||||
|
|
||||||
# Block processing failed, roll back changes
|
# Block processing failed, roll back changes
|
||||||
state = old_state
|
state.data[] = old_state.data[]
|
||||||
|
state.root = old_state.root
|
||||||
false
|
false
|
||||||
|
|
|
@ -139,10 +139,8 @@ proc parseSSZ(path: string, T: typedesc): T =
|
||||||
proc runFullTransition*(dir, preState, blocksPrefix: string, blocksQty: int, skipBLS: bool) =
|
proc runFullTransition*(dir, preState, blocksPrefix: string, blocksQty: int, skipBLS: bool) =
|
||||||
let prePath = dir / preState & ".ssz"
|
let prePath = dir / preState & ".ssz"
|
||||||
|
|
||||||
var state: ref BeaconState
|
|
||||||
new state
|
|
||||||
echo "Running: ", prePath
|
echo "Running: ", prePath
|
||||||
state[] = parseSSZ(prePath, BeaconState)
|
var state = parseSSZ(prePath, BeaconState)
|
||||||
|
|
||||||
for i in 0 ..< blocksQty:
|
for i in 0 ..< blocksQty:
|
||||||
let blockPath = dir / blocksPrefix & $i & ".ssz"
|
let blockPath = dir / blocksPrefix & $i & ".ssz"
|
||||||
|
@ -151,18 +149,16 @@ proc runFullTransition*(dir, preState, blocksPrefix: string, blocksQty: int, ski
|
||||||
let signedBlock = parseSSZ(blockPath, SignedBeaconBlock)
|
let signedBlock = parseSSZ(blockPath, SignedBeaconBlock)
|
||||||
let flags = if skipBLS: {skipBlsValidation}
|
let flags = if skipBLS: {skipBlsValidation}
|
||||||
else: {}
|
else: {}
|
||||||
let success = state_transition(state[], signedBlock.message, flags)
|
let success = state_transition(state, signedBlock.message, flags)
|
||||||
echo "State transition status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
echo "State transition status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
||||||
|
|
||||||
proc runProcessSlots*(dir, preState: string, numSlots: uint64) =
|
proc runProcessSlots*(dir, preState: string, numSlots: uint64) =
|
||||||
let prePath = dir / preState & ".ssz"
|
let prePath = dir / preState & ".ssz"
|
||||||
|
|
||||||
var state: ref BeaconState
|
|
||||||
new state
|
|
||||||
echo "Running: ", prePath
|
echo "Running: ", prePath
|
||||||
state[] = parseSSZ(prePath, BeaconState)
|
var state = parseSSZ(prePath, BeaconState)
|
||||||
|
|
||||||
process_slots(state[], state.slot + numSlots)
|
process_slots(state, state.slot + numSlots)
|
||||||
|
|
||||||
template processEpochScenarioImpl(
|
template processEpochScenarioImpl(
|
||||||
dir, preState: string,
|
dir, preState: string,
|
||||||
|
@ -170,19 +166,17 @@ template processEpochScenarioImpl(
|
||||||
needCache: static bool): untyped =
|
needCache: static bool): untyped =
|
||||||
let prePath = dir/preState & ".ssz"
|
let prePath = dir/preState & ".ssz"
|
||||||
|
|
||||||
var state: ref BeaconState
|
|
||||||
new state
|
|
||||||
echo "Running: ", prePath
|
echo "Running: ", prePath
|
||||||
state[] = parseSSZ(prePath, BeaconState)
|
var state = parseSSZ(prePath, BeaconState)
|
||||||
|
|
||||||
when needCache:
|
when needCache:
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
# Epoch transitions can't fail (TODO is this true?)
|
# Epoch transitions can't fail (TODO is this true?)
|
||||||
when needCache:
|
when needCache:
|
||||||
transitionFn(state[], cache)
|
transitionFn(state, cache)
|
||||||
else:
|
else:
|
||||||
transitionFn(state[])
|
transitionFn(state)
|
||||||
|
|
||||||
echo astToStr(transitionFn) & " status: ", "Done" # if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
echo astToStr(transitionFn) & " status: ", "Done" # if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
||||||
|
|
||||||
|
@ -197,10 +191,8 @@ template processBlockScenarioImpl(
|
||||||
needFlags, needCache: static bool): untyped =
|
needFlags, needCache: static bool): untyped =
|
||||||
let prePath = dir/preState & ".ssz"
|
let prePath = dir/preState & ".ssz"
|
||||||
|
|
||||||
var state: ref BeaconState
|
|
||||||
new state
|
|
||||||
echo "Running: ", prePath
|
echo "Running: ", prePath
|
||||||
state[] = parseSSZ(prePath, BeaconState)
|
var state = parseSSZ(prePath, BeaconState)
|
||||||
|
|
||||||
var consObj: ref `ConsensusObject`
|
var consObj: ref `ConsensusObject`
|
||||||
new consObj
|
new consObj
|
||||||
|
@ -215,13 +207,13 @@ template processBlockScenarioImpl(
|
||||||
consObj[] = parseSSZ(consObjPath, ConsensusObject)
|
consObj[] = parseSSZ(consObjPath, ConsensusObject)
|
||||||
|
|
||||||
when needFlags and needCache:
|
when needFlags and needCache:
|
||||||
let success = transitionFn(state[], consObj[], flags, cache)
|
let success = transitionFn(state, consObj[], flags, cache)
|
||||||
elif needFlags:
|
elif needFlags:
|
||||||
let success = transitionFn(state[], consObj[], flags)
|
let success = transitionFn(state, consObj[], flags)
|
||||||
elif needCache:
|
elif needCache:
|
||||||
let success = transitionFn(state[], consObj[], flags, cache)
|
let success = transitionFn(state, consObj[], flags, cache)
|
||||||
else:
|
else:
|
||||||
let success = transitionFn(state[], consObj[])
|
let success = transitionFn(state, consObj[])
|
||||||
|
|
||||||
echo astToStr(transitionFn) & " status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
echo astToStr(transitionFn) & " status: ", if success: "SUCCESS ✓" else: "FAILURE ⚠️"
|
||||||
|
|
||||||
|
|
|
@ -37,28 +37,20 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & identifier:
|
timedTest prefix & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
|
||||||
var attestationRef: ref Attestation
|
|
||||||
new attestationRef
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
attestationRef[] = parseTest(testDir/"attestation.ssz", SSZ, Attestation)
|
let attestation = parseTest(testDir/"attestation.ssz", SSZ, Attestation)
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
if existsFile(testDir/"post.ssz"):
|
||||||
new postRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
let done = process_attestation(preState, attestation, {}, cache)
|
||||||
|
|
||||||
if postRef.isNil:
|
|
||||||
let done = process_attestation(stateRef[], attestationRef[], {}, cache)
|
|
||||||
doAssert done == false, "We didn't expect this invalid attestation to be processed."
|
|
||||||
else:
|
|
||||||
let done = process_attestation(stateRef[], attestationRef[], {}, cache)
|
|
||||||
doAssert done, "Valid attestation not processed"
|
doAssert done, "Valid attestation not processed"
|
||||||
check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
else:
|
||||||
|
let done = process_attestation(preState, attestation, {}, cache)
|
||||||
|
doAssert done == false, "We didn't expect this invalid attestation to be processed."
|
||||||
|
|
||||||
`testImpl _ operations_attestations _ identifier`()
|
`testImpl _ operations_attestations _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -37,30 +37,22 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & identifier:
|
timedTest prefix & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
|
||||||
var attesterSlashingRef: ref AttesterSlashing
|
|
||||||
new attesterSlashingRef
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
attesterSlashingRef[] = parseTest(testDir/"attester_slashing.ssz", SSZ, AttesterSlashing)
|
let attesterSlashing = parseTest(testDir/"attester_slashing.ssz", SSZ, AttesterSlashing)
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
if existsFile(testDir/"post.ssz"):
|
||||||
new postRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
let done = process_attester_slashing(preState, attesterSlashing,
|
||||||
|
{}, cache)
|
||||||
if postRef.isNil:
|
|
||||||
let done = process_attester_slashing(stateRef[], attesterSlashingRef[],
|
|
||||||
{}, cache)
|
|
||||||
doAssert done == false, "We didn't expect this invalid attester slashing to be processed."
|
|
||||||
else:
|
|
||||||
let done = process_attester_slashing(stateRef[], attesterSlashingRef[],
|
|
||||||
{}, cache)
|
|
||||||
doAssert done, "Valid attestater slashing not processed"
|
doAssert done, "Valid attestater slashing not processed"
|
||||||
check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
else:
|
||||||
|
let done = process_attester_slashing(preState, attesterSlashing,
|
||||||
|
{}, cache)
|
||||||
|
doAssert done == false, "We didn't expect this invalid attester slashing to be processed."
|
||||||
|
|
||||||
`testImpl _ operations_attester_slashing _ identifier`()
|
`testImpl _ operations_attester_slashing _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -37,28 +37,20 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & identifier:
|
timedTest prefix & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
|
||||||
var blck: ref BeaconBlock
|
|
||||||
new blck
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
blck[] = parseTest(testDir/"block.ssz", SSZ, BeaconBlock)
|
let blck = parseTest(testDir/"block.ssz", SSZ, BeaconBlock)
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
if existsFile(testDir/"post.ssz"):
|
||||||
new postRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
let done = process_block_header(preState, blck, {}, cache)
|
||||||
|
|
||||||
if postRef.isNil:
|
|
||||||
let done = process_block_header(stateRef[], blck[], {}, cache)
|
|
||||||
doAssert done == false, "We didn't expect this invalid block header to be processed."
|
|
||||||
else:
|
|
||||||
let done = process_block_header(stateRef[], blck[], {}, cache)
|
|
||||||
doAssert done, "Valid block header not processed"
|
doAssert done, "Valid block header not processed"
|
||||||
check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
else:
|
||||||
|
let done = process_block_header(preState, blck, {}, cache)
|
||||||
|
doAssert done == false, "We didn't expect this invalid block header to be processed."
|
||||||
|
|
||||||
`testImpl _ blockheader _ identifier`()
|
`testImpl _ blockheader _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -40,23 +40,15 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & " " & identifier:
|
timedTest prefix & " " & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
let deposit = parseTest(testDir/"deposit.ssz", SSZ, Deposit)
|
||||||
var depositRef: ref Deposit
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
new depositRef
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
depositRef[] = parseTest(testDir/"deposit.ssz", SSZ, Deposit)
|
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
if existsFile(testDir/"post.ssz"):
|
||||||
new postRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
discard process_deposit(preState, deposit, flags)
|
||||||
|
reportDiff(preState, postState)
|
||||||
if postRef.isNil:
|
|
||||||
check not process_deposit(stateRef[], depositRef[], flags)
|
|
||||||
else:
|
else:
|
||||||
discard process_deposit(stateRef[], depositRef[], flags)
|
check not process_deposit(preState, deposit, flags)
|
||||||
reportDiff(stateRef, postRef)
|
|
||||||
|
|
||||||
`testImpl _ operations_deposits _ identifier`()
|
`testImpl _ operations_deposits _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -37,28 +37,20 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & astToStr(identifier):
|
timedTest prefix & astToStr(identifier):
|
||||||
var stateRef, postRef: ref BeaconState
|
let proposerSlashing = parseTest(testDir/"proposer_slashing.ssz", SSZ, ProposerSlashing)
|
||||||
var proposerSlashing: ref ProposerSlashing
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
new proposerSlashing
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
proposerSlashing[] = parseTest(testDir/"proposer_slashing.ssz", SSZ, ProposerSlashing)
|
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
|
||||||
new postRef
|
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
if postRef.isNil:
|
if existsFile(testDir/"post.ssz"):
|
||||||
let done = process_proposer_slashing(stateRef[], proposerSlashing[], {}, cache)
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
doAssert done == false, "We didn't expect this invalid proposer slashing to be processed."
|
let done = process_proposer_slashing(preState, proposerSlashing, {}, cache)
|
||||||
else:
|
|
||||||
let done = process_proposer_slashing(stateRef[], proposerSlashing[], {}, cache)
|
|
||||||
doAssert done, "Valid proposer slashing not processed"
|
doAssert done, "Valid proposer slashing not processed"
|
||||||
check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
else:
|
||||||
|
let done = process_proposer_slashing(preState, proposerSlashing, {}, cache)
|
||||||
|
doAssert done == false, "We didn't expect this invalid proposer slashing to be processed."
|
||||||
|
|
||||||
`testImpl_proposer_slashing _ identifier`()
|
`testImpl_proposer_slashing _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -37,26 +37,18 @@ proc runTest(identifier: string) =
|
||||||
prefix = "[Invalid] "
|
prefix = "[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & identifier:
|
timedTest prefix & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
let voluntaryExit = parseTest(testDir/"voluntary_exit.ssz", SSZ, SignedVoluntaryExit)
|
||||||
var voluntaryExit: ref SignedVoluntaryExit
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
new voluntaryExit
|
|
||||||
new stateRef
|
|
||||||
|
|
||||||
voluntaryExit[] = parseTest(testDir/"voluntary_exit.ssz", SSZ, SignedVoluntaryExit)
|
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
if existsFile(testDir/"post.ssz"):
|
||||||
new postRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
let done = process_voluntary_exit(preState, voluntaryExit, {})
|
||||||
|
|
||||||
if postRef.isNil:
|
|
||||||
let done = process_voluntary_exit(stateRef[], voluntaryExit[], {})
|
|
||||||
doAssert done == false, "We didn't expect this invalid voluntary exit to be processed."
|
|
||||||
else:
|
|
||||||
let done = process_voluntary_exit(stateRef[], voluntaryExit[], {})
|
|
||||||
doAssert done, "Valid voluntary exit not processed"
|
doAssert done, "Valid voluntary exit not processed"
|
||||||
check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
else:
|
||||||
|
let done = process_voluntary_exit(preState, voluntaryExit, {})
|
||||||
|
doAssert done == false, "We didn't expect this invalid voluntary exit to be processed."
|
||||||
|
|
||||||
`testImpl _ voluntary_exit _ identifier`()
|
`testImpl _ voluntary_exit _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -34,32 +34,28 @@ proc runTest(identifier: string) =
|
||||||
"[Invalid] "
|
"[Invalid] "
|
||||||
|
|
||||||
timedTest prefix & identifier:
|
timedTest prefix & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
new stateRef
|
var hasPostState = existsFile(testDir/"post.ssz")
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
if existsFile(testDir/"post.ssz"):
|
|
||||||
new postRef
|
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
# In test cases with more than 10 blocks the first 10 aren't 0-prefixed,
|
# In test cases with more than 10 blocks the first 10 aren't 0-prefixed,
|
||||||
# so purely lexicographic sorting wouldn't sort properly.
|
# so purely lexicographic sorting wouldn't sort properly.
|
||||||
for i in 0 ..< toSeq(walkPattern(testDir/"blocks_*.ssz")).len:
|
for i in 0 ..< toSeq(walkPattern(testDir/"blocks_*.ssz")).len:
|
||||||
let blck = parseTest(testDir/"blocks_" & $i & ".ssz", SSZ, SignedBeaconBlock)
|
let blck = parseTest(testDir/"blocks_" & $i & ".ssz", SSZ, SignedBeaconBlock)
|
||||||
|
|
||||||
if postRef.isNil:
|
if hasPostState:
|
||||||
let success = state_transition(stateRef[], blck, flags = {})
|
|
||||||
doAssert not success, "We didn't expect this invalid block to be processed"
|
|
||||||
else:
|
|
||||||
# TODO: The EF is using invalid BLS keys so we can't verify them
|
# TODO: The EF is using invalid BLS keys so we can't verify them
|
||||||
let success = state_transition(stateRef[], blck, flags = {skipBlsValidation})
|
let success = state_transition(preState, blck, flags = {skipBlsValidation})
|
||||||
doAssert success, "Failure when applying block " & $i
|
doAssert success, "Failure when applying block " & $i
|
||||||
|
else:
|
||||||
|
let success = state_transition(preState, blck, flags = {})
|
||||||
|
doAssert not success, "We didn't expect this invalid block to be processed"
|
||||||
|
|
||||||
# check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
# check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
if not postRef.isNil:
|
if hasPostState:
|
||||||
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
when false:
|
when false:
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
doAssert stateRef.hash_tree_root() == postRef.hash_tree_root()
|
doAssert preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
|
|
||||||
`testImpl _ blck _ identifier`()
|
`testImpl _ blck _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -31,16 +31,13 @@ proc runTest(identifier: string) =
|
||||||
|
|
||||||
proc `testImpl _ slots _ identifier`() =
|
proc `testImpl _ slots _ identifier`() =
|
||||||
timedTest "Slots - " & identifier:
|
timedTest "Slots - " & identifier:
|
||||||
var stateRef, postRef: ref BeaconState
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
new stateRef
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
new postRef
|
|
||||||
stateRef[] = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
|
||||||
postRef[] = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
|
||||||
|
|
||||||
process_slots(stateRef[], stateRef.slot + num_slots)
|
process_slots(preState, preState.slot + num_slots)
|
||||||
|
|
||||||
# check: stateRef.hash_tree_root() == postRef.hash_tree_root()
|
# check: preState.hash_tree_root() == postState.hash_tree_root()
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
|
||||||
`testImpl _ slots _ identifier`()
|
`testImpl _ slots _ identifier`()
|
||||||
|
|
||||||
|
|
|
@ -82,11 +82,7 @@ proc checkBasic(T: typedesc,
|
||||||
var fileContents = readFile(dir/"serialized.ssz")
|
var fileContents = readFile(dir/"serialized.ssz")
|
||||||
var stream = memoryInput(fileContents)
|
var stream = memoryInput(fileContents)
|
||||||
var reader = init(SszReader, stream)
|
var reader = init(SszReader, stream)
|
||||||
|
var deserialized = reader.readValue(T)
|
||||||
# We are using heap allocation to avoid stack overflow
|
|
||||||
# issues caused by large objects such as `BeaconState`:
|
|
||||||
var deserialized = new T
|
|
||||||
reader.readValue(deserialized[])
|
|
||||||
|
|
||||||
if stream.readable:
|
if stream.readable:
|
||||||
raise newException(UnconsumedInput, "Remaining bytes in the input")
|
raise newException(UnconsumedInput, "Remaining bytes in the input")
|
||||||
|
|
|
@ -38,16 +38,16 @@ template runSuite(suiteDir, testName: string, transitionProc: untyped{ident}, us
|
||||||
|
|
||||||
let unitTestName = testDir.rsplit(DirSep, 1)[1]
|
let unitTestName = testDir.rsplit(DirSep, 1)[1]
|
||||||
timedTest testName & " - " & unitTestName & preset():
|
timedTest testName & " - " & unitTestName & preset():
|
||||||
let stateRef = parseTest(testDir/"pre.ssz", SSZ, ref BeaconState)
|
var preState = parseTest(testDir/"pre.ssz", SSZ, BeaconState)
|
||||||
let postRef = parseTest(testDir/"post.ssz", SSZ, ref BeaconState)
|
let postState = parseTest(testDir/"post.ssz", SSZ, BeaconState)
|
||||||
|
|
||||||
when useCache:
|
when useCache:
|
||||||
var cache = get_empty_per_epoch_cache()
|
var cache = get_empty_per_epoch_cache()
|
||||||
transitionProc(stateRef[], cache)
|
transitionProc(preState, cache)
|
||||||
else:
|
else:
|
||||||
transitionProc(stateRef[])
|
transitionProc(preState)
|
||||||
|
|
||||||
reportDiff(stateRef, postRef)
|
reportDiff(preState, postState)
|
||||||
|
|
||||||
`suiteImpl _ transitionProc`()
|
`suiteImpl _ transitionProc`()
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,7 @@ suiteReport "[Unit - Spec - Block processing] Attestations " & preset():
|
||||||
# The attestation to process must be named "attestation" in the calling context
|
# The attestation to process must be named "attestation" in the calling context
|
||||||
|
|
||||||
timedTest name:
|
timedTest name:
|
||||||
var state{.inject.}: BeaconState
|
var state {.inject.} = clone(genesisState)
|
||||||
deepCopy(state, genesisState)
|
|
||||||
|
|
||||||
# Attestation setup body
|
# Attestation setup body
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
|
|
@ -33,8 +33,7 @@ suiteReport "[Unit - Spec - Block processing] Deposits " & preset():
|
||||||
# TODO: BLS signature
|
# TODO: BLS signature
|
||||||
timedTest "Deposit " & name & " MAX_EFFECTIVE_BALANCE balance (" &
|
timedTest "Deposit " & name & " MAX_EFFECTIVE_BALANCE balance (" &
|
||||||
$(MAX_EFFECTIVE_BALANCE div 10'u64^9) & " ETH)":
|
$(MAX_EFFECTIVE_BALANCE div 10'u64^9) & " ETH)":
|
||||||
var state: BeaconState
|
var state = clone(genesisState)
|
||||||
deepCopy(state, genesisState)
|
|
||||||
|
|
||||||
# Test configuration
|
# Test configuration
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
@ -75,9 +74,7 @@ suiteReport "[Unit - Spec - Block processing] Deposits " & preset():
|
||||||
valid_deposit(MAX_EFFECTIVE_BALANCE + 1, "over")
|
valid_deposit(MAX_EFFECTIVE_BALANCE + 1, "over")
|
||||||
|
|
||||||
timedTest "Validator top-up":
|
timedTest "Validator top-up":
|
||||||
|
var state = clone(genesisState)
|
||||||
var state: BeaconState
|
|
||||||
deepCopy(state, genesisState)
|
|
||||||
|
|
||||||
# Test configuration
|
# Test configuration
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
|
|
@ -212,46 +212,39 @@ proc finalizeOn12(state: var BeaconState, epoch: Epoch, sufficient_support: bool
|
||||||
doAssert state.current_justified_checkpoint == c2 # still old current
|
doAssert state.current_justified_checkpoint == c2 # still old current
|
||||||
doAssert state.finalized_checkpoint == old_finalized # no new finalized checkpoint
|
doAssert state.finalized_checkpoint == old_finalized # no new finalized checkpoint
|
||||||
|
|
||||||
suiteReport "[Unit - Spec - Epoch processing] Justification and Finalization " & preset():
|
proc payload =
|
||||||
echo " Finalization rules are detailed at https://github.com/protolambda/eth2-docs#justification-and-finalization"
|
suiteReport "[Unit - Spec - Epoch processing] Justification and Finalization " & preset():
|
||||||
|
echo " Finalization rules are detailed at https://github.com/protolambda/eth2-docs#justification-and-finalization"
|
||||||
|
|
||||||
const NumValidators = uint64(8) * SLOTS_PER_EPOCH
|
const NumValidators = uint64(8) * SLOTS_PER_EPOCH
|
||||||
let genesisState = initGenesisState(NumValidators)
|
let genesisState = initGenesisState(NumValidators)
|
||||||
doAssert genesisState.validators.len == int NumValidators
|
doAssert genesisState.validators.len == int NumValidators
|
||||||
|
|
||||||
var state: BeaconState
|
setup:
|
||||||
template resetState: untyped =
|
var state = clone(genesisState)
|
||||||
deepCopy(state, genesisState)
|
|
||||||
|
|
||||||
timedTest " Rule I - 234 finalization with enough support":
|
timedTest " Rule I - 234 finalization with enough support":
|
||||||
resetState()
|
finalizeOn234(state, Epoch 5, sufficient_support = true)
|
||||||
finalizeOn234(state, Epoch 5, sufficient_support = true)
|
|
||||||
|
|
||||||
timedTest " Rule I - 234 finalization without support":
|
timedTest " Rule I - 234 finalization without support":
|
||||||
resetState()
|
finalizeOn234(state, Epoch 5, sufficient_support = false)
|
||||||
finalizeOn234(state, Epoch 5, sufficient_support = false)
|
|
||||||
|
|
||||||
timedTest " Rule II - 23 finalization with enough support":
|
timedTest " Rule II - 23 finalization with enough support":
|
||||||
resetState()
|
finalizeOn23(state, Epoch 4, sufficient_support = true)
|
||||||
finalizeOn23(state, Epoch 4, sufficient_support = true)
|
|
||||||
|
|
||||||
timedTest " Rule II - 23 finalization without support":
|
timedTest " Rule II - 23 finalization without support":
|
||||||
resetState()
|
finalizeOn23(state, Epoch 4, sufficient_support = false)
|
||||||
finalizeOn23(state, Epoch 4, sufficient_support = false)
|
|
||||||
|
|
||||||
|
timedTest " Rule III - 123 finalization with enough support":
|
||||||
|
finalizeOn123(state, Epoch 6, sufficient_support = true)
|
||||||
|
|
||||||
timedTest " Rule III - 123 finalization with enough support":
|
timedTest " Rule III - 123 finalization without support":
|
||||||
resetState()
|
finalizeOn123(state, Epoch 6, sufficient_support = false)
|
||||||
finalizeOn123(state, Epoch 6, sufficient_support = true)
|
|
||||||
|
|
||||||
timedTest " Rule III - 123 finalization without support":
|
timedTest " Rule IV - 12 finalization with enough support":
|
||||||
resetState()
|
finalizeOn12(state, Epoch 3, sufficient_support = true)
|
||||||
finalizeOn123(state, Epoch 6, sufficient_support = false)
|
|
||||||
|
|
||||||
timedTest " Rule IV - 12 finalization with enough support":
|
timedTest " Rule IV - 12 finalization without support":
|
||||||
resetState()
|
finalizeOn12(state, Epoch 3, sufficient_support = false)
|
||||||
finalizeOn12(state, Epoch 3, sufficient_support = true)
|
|
||||||
|
|
||||||
timedTest " Rule IV - 12 finalization without support":
|
payload()
|
||||||
resetState()
|
|
||||||
finalizeOn12(state, Epoch 3, sufficient_support = false)
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ suiteReport "Beacon chain DB" & preset():
|
||||||
|
|
||||||
check:
|
check:
|
||||||
db.containsState(root)
|
db.containsState(root)
|
||||||
db.getState(root).get() == state
|
db.getState(root).get[] == state[]
|
||||||
|
|
||||||
timedTest "find ancestors" & preset():
|
timedTest "find ancestors" & preset():
|
||||||
var
|
var
|
||||||
|
@ -106,4 +106,4 @@ suiteReport "Beacon chain DB" & preset():
|
||||||
|
|
||||||
check:
|
check:
|
||||||
db.containsState(root)
|
db.containsState(root)
|
||||||
db.getState(root).get() == state
|
db.getState(root).get[] == state[]
|
||||||
|
|
|
@ -242,7 +242,7 @@ when const_preset == "minimal": # Too much stack space used on mainnet
|
||||||
bs1_3 = b1Add.atSlot(3.Slot)
|
bs1_3 = b1Add.atSlot(3.Slot)
|
||||||
bs2_3 = b2Add.atSlot(3.Slot)
|
bs2_3 = b2Add.atSlot(3.Slot)
|
||||||
|
|
||||||
var tmpState = pool.headState
|
var tmpState = clone(pool.headState)
|
||||||
|
|
||||||
# move to specific block
|
# move to specific block
|
||||||
pool.updateStateData(tmpState, bs1)
|
pool.updateStateData(tmpState, bs1)
|
||||||
|
|
|
@ -26,8 +26,7 @@ suiteReport "Block processing" & preset():
|
||||||
genesisRoot = hash_tree_root(genesisBlock.message)
|
genesisRoot = hash_tree_root(genesisBlock.message)
|
||||||
|
|
||||||
timedTest "Passes from genesis state, no block" & preset():
|
timedTest "Passes from genesis state, no block" & preset():
|
||||||
var
|
var state = clone(genesisState)
|
||||||
state = genesisState
|
|
||||||
|
|
||||||
process_slots(state, state.slot + 1)
|
process_slots(state, state.slot + 1)
|
||||||
check:
|
check:
|
||||||
|
@ -35,7 +34,7 @@ suiteReport "Block processing" & preset():
|
||||||
|
|
||||||
timedTest "Passes from genesis state, empty block" & preset():
|
timedTest "Passes from genesis state, empty block" & preset():
|
||||||
var
|
var
|
||||||
state = genesisState
|
state = clone(genesisState)
|
||||||
previous_block_root = hash_tree_root(genesisBlock.message)
|
previous_block_root = hash_tree_root(genesisBlock.message)
|
||||||
new_block = makeTestBlock(state, previous_block_root)
|
new_block = makeTestBlock(state, previous_block_root)
|
||||||
|
|
||||||
|
@ -47,8 +46,7 @@ suiteReport "Block processing" & preset():
|
||||||
state.slot == genesisState.slot + 1
|
state.slot == genesisState.slot + 1
|
||||||
|
|
||||||
timedTest "Passes through epoch update, no block" & preset():
|
timedTest "Passes through epoch update, no block" & preset():
|
||||||
var
|
var state = clone(genesisState)
|
||||||
state = genesisState
|
|
||||||
|
|
||||||
process_slots(state, Slot(SLOTS_PER_EPOCH))
|
process_slots(state, Slot(SLOTS_PER_EPOCH))
|
||||||
|
|
||||||
|
@ -57,7 +55,7 @@ suiteReport "Block processing" & preset():
|
||||||
|
|
||||||
timedTest "Passes through epoch update, empty block" & preset():
|
timedTest "Passes through epoch update, empty block" & preset():
|
||||||
var
|
var
|
||||||
state = genesisState
|
state = clone(genesisState)
|
||||||
previous_block_root = genesisRoot
|
previous_block_root = genesisRoot
|
||||||
|
|
||||||
for i in 1..SLOTS_PER_EPOCH.int:
|
for i in 1..SLOTS_PER_EPOCH.int:
|
||||||
|
@ -75,7 +73,7 @@ suiteReport "Block processing" & preset():
|
||||||
|
|
||||||
timedTest "Attestation gets processed at epoch" & preset():
|
timedTest "Attestation gets processed at epoch" & preset():
|
||||||
var
|
var
|
||||||
state = genesisState
|
state = clone(genesisState)
|
||||||
previous_block_root = genesisRoot
|
previous_block_root = genesisRoot
|
||||||
cache = get_empty_per_epoch_cache()
|
cache = get_empty_per_epoch_cache()
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ proc makeTestBlock*(
|
||||||
# It's a bit awkward - in order to produce a block for N+1, we need to
|
# It's a bit awkward - in order to produce a block for N+1, we need to
|
||||||
# calculate what the state will look like after that block has been applied,
|
# calculate what the state will look like after that block has been applied,
|
||||||
# because the block includes the state root.
|
# because the block includes the state root.
|
||||||
var tmpState = state
|
var tmpState = clone(state)
|
||||||
addTestBlock(
|
addTestBlock(
|
||||||
tmpState, parent_root, eth1_data, attestations, deposits, graffiti, flags)
|
tmpState, parent_root, eth1_data, attestations, deposits, graffiti, flags)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue