split state_transition() into slots/block parts and use only block where appropriate (#2630)
This commit is contained in:
parent
141c39cfaa
commit
28a5bca71a
|
@ -60,15 +60,7 @@ template asTrusted(x: SignedBeaconBlock or SigVerifiedBeaconBlock): TrustedSigne
|
|||
|
||||
cast[ptr TrustedSignedBeaconBlock](signedBlock.unsafeAddr)[]
|
||||
|
||||
func getOrResolve*(dag: ChainDAGRef, quarantine: QuarantineRef, root: Eth2Digest): BlockRef =
|
||||
## Fetch a block ref, or nil if not found (will be added to list of
|
||||
## blocks-to-resolve)
|
||||
result = dag.getRef(root)
|
||||
|
||||
if result.isNil:
|
||||
quarantine.addMissing(root)
|
||||
|
||||
proc batchVerify(quarantine: QuarantineRef, sigs: openArray[SignatureSet]): bool =
|
||||
func batchVerify(quarantine: QuarantineRef, sigs: openArray[SignatureSet]): bool =
|
||||
var secureRandomBytes: array[32, byte]
|
||||
quarantine.rng[].brHmacDrbgGenerate(secureRandomBytes)
|
||||
|
||||
|
@ -181,8 +173,9 @@ proc checkStateTransition(
|
|||
blockRoot = shortLog(signedBlock.root)
|
||||
|
||||
var rewards: RewardInfo
|
||||
if not state_transition(dag.runtimePreset, dag.clearanceState.data, signedBlock,
|
||||
cache, rewards, dag.updateFlags + {slotProcessed}, restore):
|
||||
if not state_transition_block(
|
||||
dag.runtimePreset, dag.clearanceState.data, signedBlock,
|
||||
cache, rewards, dag.updateFlags, restore):
|
||||
info "Invalid block"
|
||||
|
||||
return (ValidationResult.Reject, Invalid)
|
||||
|
@ -323,7 +316,7 @@ proc addRawBlockUnresolved(
|
|||
|
||||
return err((ValidationResult.Ignore, MissingParent))
|
||||
|
||||
proc addRawBlock*(
|
||||
proc addRawBlock(
|
||||
dag: ChainDAGRef, quarantine: QuarantineRef,
|
||||
signedBlock: SignedBeaconBlock,
|
||||
onBlockAdded: OnBlockAdded
|
||||
|
|
|
@ -13,12 +13,13 @@ import
|
|||
metrics, snappy, chronicles,
|
||||
../ssz/[ssz_serialization, merkleization], ../beacon_chain_db, ../extras,
|
||||
../spec/[
|
||||
crypto, datatypes, digest, helpers, validator, state_transition,
|
||||
crypto, digest, helpers, validator, state_transition,
|
||||
beaconstate],
|
||||
../spec/datatypes/[phase0, altair],
|
||||
../beacon_clock,
|
||||
"."/[block_pools_types, block_quarantine, statedata_helpers]
|
||||
|
||||
export block_pools_types, helpers, datatypes
|
||||
export block_pools_types, helpers, phase0
|
||||
|
||||
# https://github.com/ethereum/eth2.0-metrics/blob/master/metrics.md#interop-metrics
|
||||
declareGauge beacon_head_root, "Root of the head block of the beacon chain"
|
||||
|
@ -44,7 +45,7 @@ declareGauge beacon_processed_deposits_total, "Number of total deposits included
|
|||
logScope: topics = "chaindag"
|
||||
|
||||
proc putBlock*(
|
||||
dag: ChainDAGRef, signedBlock: TrustedSignedBeaconBlock) =
|
||||
dag: ChainDAGRef, signedBlock: phase0.TrustedSignedBeaconBlock) =
|
||||
dag.db.putBlock(signedBlock)
|
||||
|
||||
proc updateStateData*(
|
||||
|
@ -233,10 +234,6 @@ func atEpochStart*(blck: BlockRef, epoch: Epoch): BlockSlot =
|
|||
## Return the BlockSlot corresponding to the first slot in the given epoch
|
||||
atSlot(blck, epoch.compute_start_slot_at_epoch)
|
||||
|
||||
func atEpochEnd(blck: BlockRef, epoch: Epoch): BlockSlot =
|
||||
## Return the BlockSlot corresponding to the last slot in the given epoch
|
||||
atSlot(blck, (epoch + 1).compute_start_slot_at_epoch - 1)
|
||||
|
||||
func epochAncestor*(blck: BlockRef, epoch: Epoch): BlockSlot =
|
||||
## The state transition works by storing information from blocks in a
|
||||
## "working" area until the epoch transition, then batching work collected
|
||||
|
@ -291,7 +288,8 @@ func init(T: type BlockRef, root: Eth2Digest, slot: Slot): BlockRef =
|
|||
slot: slot
|
||||
)
|
||||
|
||||
func init*(T: type BlockRef, root: Eth2Digest, blck: SomeBeaconBlock): BlockRef =
|
||||
func init*(T: type BlockRef, root: Eth2Digest, blck: SomeSomeBeaconBlock):
|
||||
BlockRef =
|
||||
BlockRef.init(root, blck.slot)
|
||||
|
||||
func contains*(dag: ChainDAGRef, root: Eth2Digest): bool =
|
||||
|
@ -506,7 +504,7 @@ proc getState(
|
|||
else:
|
||||
unsafeAddr dag.headState
|
||||
|
||||
func restore(v: var BeaconState) =
|
||||
func restore(v: var phase0.BeaconState) =
|
||||
assign(v, restoreAddr[].data.data)
|
||||
|
||||
if not dag.db.getState(stateRoot, state.data.data, restore):
|
||||
|
@ -681,7 +679,7 @@ proc applyBlock(
|
|||
doAssert state.blck == blck.refs.parent
|
||||
|
||||
var statePtr = unsafeAddr state # safe because `restore` is locally scoped
|
||||
func restore(v: var HashedBeaconState) =
|
||||
func restore(v: var phase0.HashedBeaconState) =
|
||||
doAssert (addr(statePtr.data) == addr v)
|
||||
statePtr[] = dag.headState
|
||||
|
||||
|
@ -1095,7 +1093,7 @@ proc isInitialized*(T: type ChainDAGRef, db: BeaconChainDB): bool =
|
|||
|
||||
proc preInit*(
|
||||
T: type ChainDAGRef, db: BeaconChainDB,
|
||||
genesisState, tailState: var BeaconState, tailBlock: TrustedSignedBeaconBlock) =
|
||||
genesisState, tailState: var phase0.BeaconState, tailBlock: phase0.TrustedSignedBeaconBlock) =
|
||||
# write a genesis state, the way the ChainDAGRef expects it to be stored in
|
||||
# database
|
||||
# TODO probably should just init a block pool with the freshly written
|
||||
|
@ -1125,8 +1123,8 @@ proc preInit*(
|
|||
db.putGenesisBlockRoot(genesisBlock.root)
|
||||
|
||||
func setTailState*(dag: ChainDAGRef,
|
||||
checkpointState: BeaconState,
|
||||
checkpointBlock: TrustedSignedBeaconBlock) =
|
||||
checkpointState: phase0.BeaconState,
|
||||
checkpointBlock: phase0.TrustedSignedBeaconBlock) =
|
||||
# TODO(zah)
|
||||
# Delete all records up to the tail node. If the tail node is not
|
||||
# in the database, init the dabase in a way similar to `preInit`.
|
||||
|
|
|
@ -53,7 +53,7 @@ import
|
|||
type Foo = phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock | phase0.SignedBeaconBlock | altair.SignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.TrustedSignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | altair.SigVerifiedSignedBeaconBlock
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function
|
||||
proc verify_block_signature*(
|
||||
proc verify_block_signature(
|
||||
#state: SomeBeaconState, signed_block: SomeSomeSignedBeaconBlock): bool {.nbench.} =
|
||||
state: SomeBeaconState, signed_block: Foo): bool {.nbench.} =
|
||||
#state: SomeBeaconState, signed_block: phase0.SomeSignedBeaconBlock | altair.SomeSignedBeaconBlock): bool {.nbench.} =
|
||||
|
@ -85,14 +85,14 @@ proc verifyStateRoot(state: SomeBeaconState, blck: phase0.BeaconBlock or phase0.
|
|||
else:
|
||||
true
|
||||
|
||||
proc verifyStateRoot(state: phase0.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
func verifyStateRoot(state: phase0.BeaconState, blck: phase0.TrustedBeaconBlock): bool =
|
||||
# This is inlined in state_transition(...) in spec.
|
||||
true
|
||||
|
||||
type
|
||||
RollbackProc* = proc(v: var phase0.BeaconState) {.gcsafe, raises: [Defect].}
|
||||
|
||||
proc noRollback*(state: var phase0.BeaconState) =
|
||||
func noRollback*(state: var phase0.BeaconState) =
|
||||
trace "Skipping rollback of broken state"
|
||||
|
||||
type
|
||||
|
@ -176,16 +176,14 @@ proc process_slots*(state: var SomeHashedBeaconState, slot: Slot,
|
|||
|
||||
true
|
||||
|
||||
proc noRollback*(state: var phase0.HashedBeaconState) =
|
||||
func noRollback*(state: var phase0.HashedBeaconState) =
|
||||
trace "Skipping rollback of broken state"
|
||||
|
||||
proc state_transition*(
|
||||
proc state_transition_slots(
|
||||
preset: RuntimePreset,
|
||||
# TODO this will be StateData
|
||||
#state: var phase0.HashedBeaconState, signedBlock: phase0.SomeSignedBeaconBlock,
|
||||
state: var (phase0.HashedBeaconState | altair.HashedBeaconState), signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
|
||||
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
|
||||
rollback: RollbackHashedProc): bool {.nbench.} =
|
||||
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags): bool {.nbench.} =
|
||||
## Apply a block to the state, advancing the slot counter as necessary. The
|
||||
## given state must be of a lower slot, or, in case the `slotProcessed` flag
|
||||
## is set, can be the slot state of the same slot as the block (where the
|
||||
|
@ -201,8 +199,6 @@ proc state_transition*(
|
|||
## it is safe to use `noRollback` and leave it broken, else the state
|
||||
## object should be rolled back to a consistent state. If the transition fails
|
||||
## before the state has been updated, `rollback` will not be called.
|
||||
doAssert not rollback.isNil, "use noRollback if it's ok to mess up state"
|
||||
|
||||
let slot = signedBlock.message.slot
|
||||
if not (state.data.slot < slot):
|
||||
if slotProcessed notin flags or state.data.slot != slot:
|
||||
|
@ -220,10 +216,20 @@ proc state_transition*(
|
|||
# Don't update state root for the slot of the block
|
||||
state.root = hash_tree_root(state.data)
|
||||
|
||||
true
|
||||
|
||||
proc state_transition_block*(
|
||||
preset: RuntimePreset,
|
||||
#state: var phase0.HashedBeaconState, signedBlock: phase0.SomeSignedBeaconBlock,
|
||||
state: var (phase0.HashedBeaconState | altair.HashedBeaconState), signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
|
||||
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
|
||||
rollback: RollbackHashedProc): bool {.nbench.} =
|
||||
# Block updates - these happen when there's a new block being suggested
|
||||
# by the block proposer. Every actor in the network will update its state
|
||||
# according to the contents of this block - but first they will validate
|
||||
# that the block is sane.
|
||||
doAssert not rollback.isNil, "use noRollback if it's ok to mess up state"
|
||||
|
||||
if not (skipBLSValidation in flags or
|
||||
verify_block_signature(state.data, signedBlock)):
|
||||
when not (state is altair.HashedBeaconState):
|
||||
|
@ -264,6 +270,16 @@ proc state_transition*(
|
|||
|
||||
true
|
||||
|
||||
proc state_transition*(
|
||||
preset: RuntimePreset,
|
||||
#state: var phase0.HashedBeaconState, signedBlock: phase0.SomeSignedBeaconBlock,
|
||||
state: var (phase0.HashedBeaconState | altair.HashedBeaconState), signedBlock: phase0.SignedBeaconBlock | phase0.SigVerifiedSignedBeaconBlock | phase0.TrustedSignedBeaconBlock | altair.SignedBeaconBlock,
|
||||
cache: var StateCache, rewards: var RewardInfo, flags: UpdateFlags,
|
||||
rollback: RollbackHashedProc): bool {.nbench.} =
|
||||
if not state_transition_slots(preset, state, signedBlock, cache, rewards, flags):
|
||||
return false
|
||||
state_transition_block(preset, state, signedBlock, cache, rewards, flags, rollback)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/validator.md#preparing-for-a-beaconblock
|
||||
proc makeBeaconBlock*(
|
||||
preset: RuntimePreset,
|
||||
|
|
|
@ -177,7 +177,7 @@ proc process_proposer_slashing*(
|
|||
ok()
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#is_slashable_attestation_data
|
||||
func is_slashable_attestation_data*(
|
||||
func is_slashable_attestation_data(
|
||||
data_1: AttestationData, data_2: AttestationData): bool =
|
||||
## Check if ``data_1`` and ``data_2`` are slashable according to Casper FFG
|
||||
## rules.
|
||||
|
|
|
@ -667,7 +667,7 @@ func process_rewards_and_penalties(
|
|||
decrease_balance(state.balances.asSeq()[idx], v.delta.penalties)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#rewards-and-penalties
|
||||
proc process_rewards_and_penalties(
|
||||
func process_rewards_and_penalties(
|
||||
state: var altair.BeaconState, total_active_balance: Gwei) {.nbench.} =
|
||||
if get_current_epoch(state) == GENESIS_EPOCH:
|
||||
return
|
||||
|
@ -828,17 +828,6 @@ func process_inactivity_updates*(state: var altair.BeaconState) =
|
|||
if not is_in_inactivity_leak(state):
|
||||
state.inactivity_scores[index] -= min(INACTIVITY_SCORE_RECOVERY_RATE.uint64, state.inactivity_scores[index])
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates
|
||||
func process_final_updates*(state: var phase0.BeaconState) {.nbench.} =
|
||||
# This function's a wrapper over the HF1 split/refactored HF1 version. TODO
|
||||
# remove once test vectors become available for each HF1 function.
|
||||
process_eth1_data_reset(state)
|
||||
process_effective_balance_updates(state)
|
||||
process_slashings_reset(state)
|
||||
process_randao_mixes_reset(state)
|
||||
process_historical_roots_update(state)
|
||||
process_participation_record_updates(state)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#epoch-processing
|
||||
proc process_epoch*(
|
||||
state: var phase0.BeaconState, flags: UpdateFlags, cache: var StateCache,
|
||||
|
@ -873,7 +862,12 @@ proc process_epoch*(
|
|||
process_slashings(state, rewards.total_balances.current_epoch)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates
|
||||
process_final_updates(state)
|
||||
process_eth1_data_reset(state)
|
||||
process_effective_balance_updates(state)
|
||||
process_slashings_reset(state)
|
||||
process_randao_mixes_reset(state)
|
||||
process_historical_roots_update(state)
|
||||
process_participation_record_updates(state)
|
||||
|
||||
# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#epoch-processing
|
||||
proc process_epoch*(
|
||||
|
|
|
@ -41,9 +41,6 @@ build/nbench cmdEpochProcessing --epochProcessingCat=catRegistryUpdates -d="${SC
|
|||
# Slashings
|
||||
build/nbench cmdEpochProcessing --epochProcessingCat=catSlashings -d="${SCENARIOS}"/epoch_processing/slashings/pyspec_tests/max_penalties/
|
||||
|
||||
# Final updates
|
||||
build/nbench cmdEpochProcessing --epochProcessingCat=catFinalUpdates -d="${SCENARIOS}"/epoch_processing/final_updates/pyspec_tests/effective_balance_hysteresis/
|
||||
|
||||
# Block header processing
|
||||
build/nbench cmdBlockProcessing --blockProcessingCat=catBlockHeader -d="${SCENARIOS}"/operations/block_header/pyspec_tests/proposer_slashed/
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2021 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).
|
||||
|
@ -117,11 +117,6 @@ proc main() =
|
|||
scenario.scenarioDir.string,
|
||||
scenario.preState
|
||||
)
|
||||
of catFinalUpdates:
|
||||
runProcessFinalUpdates(
|
||||
scenario.scenarioDir.string,
|
||||
scenario.preState
|
||||
)
|
||||
else:
|
||||
quit "Unsupported"
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2021 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).
|
||||
|
@ -62,9 +62,6 @@ proc collectBenchTargets(nbench, basePath: string): CmdLists =
|
|||
block: # Slashings
|
||||
let path = basePath/"phase0"/"epoch_processing"/"slashings"/"pyspec_tests"
|
||||
result.collectTarget(nbench, "slashings", "cmdEpochProcessing", "catSlashings", path)
|
||||
block: # Justification-Finalization
|
||||
let path = basePath/"phase0"/"epoch_processing"/"final_updates"/"pyspec_tests"
|
||||
result.collectTarget(nbench, "final_updates", "cmdEpochProcessing", "catFinalUpdates", path)
|
||||
# Block processing
|
||||
# -------------------------------------------------------------------------
|
||||
block: # Attestation
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2018-2020 Status Research & Development GmbH
|
||||
# Copyright (c) 2018-2021 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).
|
||||
|
@ -40,7 +40,6 @@ type
|
|||
catVoluntaryExits
|
||||
|
||||
EpochProcessingCat* = enum
|
||||
catFinalUpdates
|
||||
catJustificationFinalization
|
||||
catRegistryUpdates
|
||||
catSlashings
|
||||
|
@ -270,10 +269,6 @@ genProcessEpochScenario(runProcessSlashings,
|
|||
process_slashings,
|
||||
needCache = false)
|
||||
|
||||
genProcessEpochScenario(runProcessFinalUpdates,
|
||||
process_final_updates,
|
||||
needCache = false)
|
||||
|
||||
genProcessBlockScenario(runProcessBlockHeader,
|
||||
process_block_header,
|
||||
block_header,
|
||||
|
|
|
@ -207,8 +207,8 @@ proc cmdBench(conf: DbConf, runtimePreset: RuntimePreset) =
|
|||
withTimer(timers[tApplyBlock]):
|
||||
if conf.resetCache:
|
||||
cache = StateCache()
|
||||
if not state_transition(
|
||||
runtimePreset, state[].data, b, cache, rewards, {slotProcessed}, noRollback):
|
||||
if not state_transition_block(
|
||||
runtimePreset, state[].data, b, cache, rewards, {}, noRollback):
|
||||
dump("./", b)
|
||||
echo "State transition failed (!)"
|
||||
quit 1
|
||||
|
@ -529,8 +529,8 @@ proc cmdValidatorPerf(conf: DbConf, runtimePreset: RuntimePreset) =
|
|||
if getStateField(state[], slot).isEpoch():
|
||||
processEpoch()
|
||||
|
||||
if not state_transition(
|
||||
runtimePreset, state[].data, blck, cache, rewards, {slotProcessed}, noRollback):
|
||||
if not state_transition_block(
|
||||
runtimePreset, state[].data, blck, cache, rewards, {}, noRollback):
|
||||
echo "State transition failed (!)"
|
||||
quit 1
|
||||
|
||||
|
@ -756,8 +756,8 @@ proc cmdValidatorDb(conf: DbConf, runtimePreset: RuntimePreset) =
|
|||
if getStateField(state[], slot).isEpoch():
|
||||
processEpoch()
|
||||
|
||||
if not state_transition(
|
||||
runtimePreset, state[].data, blck, cache, rewards, {slotProcessed}, noRollback):
|
||||
if not state_transition_block(
|
||||
runtimePreset, state[].data, blck, cache, rewards, {}, noRollback):
|
||||
echo "State transition failed (!)"
|
||||
quit 1
|
||||
|
||||
|
|
|
@ -43,7 +43,6 @@ template withTimerRet*(stats: var RunningStat, body: untyped): untyped =
|
|||
|
||||
var testTimes: seq[TestDuration]
|
||||
var status = initOrderedTable[string, OrderedTable[string, Status]]()
|
||||
var last: string
|
||||
|
||||
type TimingCollector = ref object of OutputFormatter
|
||||
|
||||
|
|
Loading…
Reference in New Issue