diff --git a/beacon_chain/consensus_object_pools/block_clearance.nim b/beacon_chain/consensus_object_pools/block_clearance.nim index 8207f5b59..6afb9fc0b 100644 --- a/beacon_chain/consensus_object_pools/block_clearance.nim +++ b/beacon_chain/consensus_object_pools/block_clearance.nim @@ -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 diff --git a/beacon_chain/consensus_object_pools/blockchain_dag.nim b/beacon_chain/consensus_object_pools/blockchain_dag.nim index c49b4796b..8c6fc3ff8 100644 --- a/beacon_chain/consensus_object_pools/blockchain_dag.nim +++ b/beacon_chain/consensus_object_pools/blockchain_dag.nim @@ -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`. diff --git a/beacon_chain/spec/state_transition.nim b/beacon_chain/spec/state_transition.nim index 9e6800800..c52224e85 100644 --- a/beacon_chain/spec/state_transition.nim +++ b/beacon_chain/spec/state_transition.nim @@ -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, diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index 649467447..745b6b90e 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -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. diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 052f19e49..7c1893e7c 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -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*( diff --git a/nbench/README.md b/nbench/README.md index 71f857ef8..432c2b56f 100644 --- a/nbench/README.md +++ b/nbench/README.md @@ -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/ diff --git a/nbench/nbench.nim b/nbench/nbench.nim index 92489e510..fccb51136 100644 --- a/nbench/nbench.nim +++ b/nbench/nbench.nim @@ -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" diff --git a/nbench/nbench_spec_scenarios.nim b/nbench/nbench_spec_scenarios.nim index 66756f58e..380538265 100644 --- a/nbench/nbench_spec_scenarios.nim +++ b/nbench/nbench_spec_scenarios.nim @@ -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 diff --git a/nbench/scenarios.nim b/nbench/scenarios.nim index 95237b3a3..45f31736f 100644 --- a/nbench/scenarios.nim +++ b/nbench/scenarios.nim @@ -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, diff --git a/ncli/ncli_db.nim b/ncli/ncli_db.nim index e456a6b0e..21c87be70 100644 --- a/ncli/ncli_db.nim +++ b/ncli/ncli_db.nim @@ -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 diff --git a/tests/testutil.nim b/tests/testutil.nim index ee737e81b..505d91767 100644 --- a/tests/testutil.nim +++ b/tests/testutil.nim @@ -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