From 35b1104bea5220f51b97e33a3fb7da5b9739e87e Mon Sep 17 00:00:00 2001 From: tersec Date: Fri, 11 Nov 2022 10:17:27 +0000 Subject: [PATCH] `block_sim` runs capella by default (#4315) --- beacon_chain/beacon_chain_db_immutable.nim | 2 +- .../attestation_pool.nim | 15 +-- beacon_chain/nimbus_beacon_node.nim | 2 +- beacon_chain/spec/beaconstate.nim | 6 +- beacon_chain/spec/datatypes/capella.nim | 9 +- beacon_chain/spec/datatypes/constants.nim | 2 +- beacon_chain/spec/signatures.nim | 2 +- beacon_chain/spec/state_transition.nim | 116 +++++++++++++++--- beacon_chain/validators/validator_pool.nim | 2 +- research/block_sim.nim | 45 ++++++- 10 files changed, 160 insertions(+), 41 deletions(-) diff --git a/beacon_chain/beacon_chain_db_immutable.nim b/beacon_chain/beacon_chain_db_immutable.nim index 00ee335ec..ac2fab137 100644 --- a/beacon_chain/beacon_chain_db_immutable.nim +++ b/beacon_chain/beacon_chain_db_immutable.nim @@ -125,7 +125,7 @@ type current_sync_committee*: SyncCommittee # [New in Altair] next_sync_committee*: SyncCommittee # [New in Altair] - # https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#beaconstate + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/bellatrix/beacon-chain.md#beaconstate # Memory-representation-equivalent to a Bellatrix BeaconState for in-place SSZ # reading and writing BellatrixBeaconStateNoImmutableValidators* = object diff --git a/beacon_chain/consensus_object_pools/attestation_pool.nim b/beacon_chain/consensus_object_pools/attestation_pool.nim index 039f90392..268a9be39 100644 --- a/beacon_chain/consensus_object_pools/attestation_pool.nim +++ b/beacon_chain/consensus_object_pools/attestation_pool.nim @@ -485,7 +485,8 @@ func init(T: type AttestationCache, state: phase0.HashedBeaconState): T = func init( T: type AttestationCache, - state: altair.HashedBeaconState | bellatrix.HashedBeaconState, + state: altair.HashedBeaconState | bellatrix.HashedBeaconState | + capella.HashedBeaconState, cache: var StateCache): T = # Load attestations that are scheduled for being given rewards for let @@ -582,11 +583,9 @@ proc getAttestationsForBlock*(pool: var AttestationPool, attCache = when state is phase0.HashedBeaconState: AttestationCache.init(state) - elif state is altair.HashedBeaconState or state is bellatrix.HashedBeaconState: + elif state is altair.HashedBeaconState or state is bellatrix.HashedBeaconState or + state is capella.HashedBeaconState: AttestationCache.init(state, cache) - elif state is capella.HashedBeaconState: - if true: raiseAssert $capellaImplementationMissing - default(AttestationCache) else: static: doAssert false @@ -646,14 +645,12 @@ proc getAttestationsForBlock*(pool: var AttestationPool, var prevEpoch = state.data.get_previous_epoch() prevEpochSpace = - when state is altair.HashedBeaconState or state is bellatrix.HashedBeaconState: + when state is altair.HashedBeaconState or state is bellatrix.HashedBeaconState or + state is capella.HashedBeaconState: MAX_ATTESTATIONS elif state is phase0.HashedBeaconState: state.data.previous_epoch_attestations.maxLen - state.data.previous_epoch_attestations.len() - elif state is capella.HashedBeaconState: - if true: raiseAssert $capellaImplementationMissing - int(capellaImplementationMissing) else: raiseAssert "invalid HashedBeaconState fork" diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index a69a0f29c..f94ca9138 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -1365,7 +1365,7 @@ proc installRestHandlers(restServer: RestServerRef, node: BeaconNode) = restServer.router.installLightClientApiHandlers(node) proc installMessageValidators(node: BeaconNode) = - # https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/p2p-interface.md#attestations-and-aggregation + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/p2p-interface.md#attestations-and-aggregation # These validators stay around the whole time, regardless of which specific # subnets are subscribed to during any given epoch. let forkDigests = node.dag.forkDigests diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index b8c67cf05..eb68a478e 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -23,7 +23,7 @@ from ./datatypes/capella import BeaconState, ExecutionPayloadHeader, Withdrawal export extras, forks, validator -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#increase_balance +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#increase_balance func increase_balance*(balance: var Gwei, delta: Gwei) = balance += delta @@ -132,7 +132,7 @@ func initiate_validator_exit*( ok() -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#slash_validator +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#slash_validator # https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/beacon-chain.md#modified-slash_validator # https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.1/specs/bellatrix/beacon-chain.md#modified-slash_validator func get_slashing_penalty*(state: ForkyBeaconState, @@ -396,7 +396,7 @@ func get_block_root_at_slot*( withState(state): get_block_root_at_slot(forkyState.data, slot) -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/phase0/beacon-chain.md#get_block_root +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#get_block_root func get_block_root*(state: ForkyBeaconState, epoch: Epoch): Eth2Digest = ## Return the block root at the start of a recent ``epoch``. get_block_root_at_slot(state, epoch.start_slot()) diff --git a/beacon_chain/spec/datatypes/capella.nim b/beacon_chain/spec/datatypes/capella.nim index 1814a6ec1..2dd35618f 100644 --- a/beacon_chain/spec/datatypes/capella.nim +++ b/beacon_chain/spec/datatypes/capella.nim @@ -27,6 +27,9 @@ import export json_serialization, base type + SignedBLSToExecutionChangeList* = + List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#withdrawal Withdrawal* = object index*: WithdrawalIndex @@ -240,7 +243,7 @@ type execution_payload*: ExecutionPayload # Capella operations - bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella] + bls_to_execution_changes*: SignedBLSToExecutionChangeList # [New in Capella] SigVerifiedBeaconBlockBody* = object ## A BeaconBlock body with signatures verified @@ -276,7 +279,7 @@ type execution_payload*: ExecutionPayload # Capella operations - bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella] + bls_to_execution_changes*: SignedBLSToExecutionChangeList # [New in Capella] TrustedBeaconBlockBody* = object ## A full verified block @@ -300,7 +303,7 @@ type execution_payload*: ExecutionPayload # Capella operations - bls_to_execution_changes*: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella] + bls_to_execution_changes*: SignedBLSToExecutionChangeList # [New in Capella] # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/beacon-chain.md#signedbeaconblock SignedBeaconBlock* = object diff --git a/beacon_chain/spec/datatypes/constants.nim b/beacon_chain/spec/datatypes/constants.nim index e6b6f26c6..79a0b9e99 100644 --- a/beacon_chain/spec/datatypes/constants.nim +++ b/beacon_chain/spec/datatypes/constants.nim @@ -39,7 +39,7 @@ const # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/capella/beacon-chain.md#domain-types DOMAIN_BLS_TO_EXECUTION_CHANGE* = DomainType([byte 0x0a, 0x00, 0x00, 0x00]) - # https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/bellatrix/beacon-chain.md#transition-settings + # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/bellatrix/beacon-chain.md#transition-settings TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH* = FAR_FUTURE_EPOCH # https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/phase0/fork-choice.md#configuration diff --git a/beacon_chain/spec/signatures.nim b/beacon_chain/spec/signatures.nim index 1ed0b8e30..d7896d2bf 100644 --- a/beacon_chain/spec/signatures.nim +++ b/beacon_chain/spec/signatures.nim @@ -249,7 +249,7 @@ proc verify_voluntary_exit_signature*( blsVerify(pubkey, signing_root.data, signature) -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/validator.md#prepare-sync-committee-message +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/validator.md#prepare-sync-committee-message func compute_sync_committee_message_signing_root*( fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot, beacon_block_root: Eth2Digest): Eth2Digest = diff --git a/beacon_chain/spec/state_transition.nim b/beacon_chain/spec/state_transition.nim index d764bd7c2..8a791f1a1 100644 --- a/beacon_chain/spec/state_transition.nim +++ b/beacon_chain/spec/state_transition.nim @@ -157,6 +157,13 @@ func noRollback*(state: var altair.HashedBeaconState) = func noRollback*(state: var bellatrix.HashedBeaconState) = trace "Skipping rollback of broken Bellatrix state" +from ./datatypes/capella import + ExecutionPayload, HashedBeaconState, SignedBLSToExecutionChangeList, + asSigVerified + +func noRollback*(state: var capella.HashedBeaconState) = + trace "Skipping rollback of broken Capella state" + func maybeUpgradeStateToAltair( cfg: RuntimeConfig, state: var ForkedHashedBeaconState) = # Both process_slots() and state_transition_block() call this, so only run it @@ -181,9 +188,6 @@ func maybeUpgradeStateToBellatrix( bellatrixData: bellatrix.HashedBeaconState( root: hash_tree_root(newState[]), data: newState[]))[] -from ./datatypes/capella import - ExecutionPayload, HashedBeaconState, asSigVerified - func maybeUpgradeStateToCapella( cfg: RuntimeConfig, state: var ForkedHashedBeaconState) = # Both process_slots() and state_transition_block() call this, so only run it @@ -350,6 +354,7 @@ proc makeBeaconBlock*( exits: BeaconBlockExits, sync_aggregate: SyncAggregate, execution_payload: bellatrix.ExecutionPayload, + bls_to_execution_changes: SignedBLSToExecutionChangeList, rollback: RollbackHashedProc[phase0.HashedBeaconState], cache: var StateCache, # TODO: @@ -364,9 +369,9 @@ proc makeBeaconBlock*( # To create a block, we'll first apply a partial block to the state, skipping # some validations. - var blck = partialBeaconBlock(cfg, state, proposer_index, - randao_reveal, eth1_data, graffiti, attestations, deposits, - exits, sync_aggregate, execution_payload) + var blck = partialBeaconBlock( + cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, + attestations, deposits, exits, sync_aggregate, execution_payload) let res = process_block( cfg, state.data, blck.asSigVerified(), verificationFlags, cache) @@ -420,6 +425,7 @@ proc makeBeaconBlock*( exits: BeaconBlockExits, sync_aggregate: SyncAggregate, execution_payload: bellatrix.ExecutionPayload, + bls_to_execution_changes: SignedBLSToExecutionChangeList, rollback: RollbackHashedProc[altair.HashedBeaconState], cache: var StateCache, # TODO: @@ -434,9 +440,9 @@ proc makeBeaconBlock*( # To create a block, we'll first apply a partial block to the state, skipping # some validations. - var blck = partialBeaconBlock(cfg, state, proposer_index, - randao_reveal, eth1_data, graffiti, attestations, deposits, - exits, sync_aggregate, execution_payload) + var blck = partialBeaconBlock( + cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, + attestations, deposits, exits, sync_aggregate, execution_payload) # Signatures are verified elsewhere, so don't duplicate inefficiently here let res = process_block( @@ -492,6 +498,7 @@ proc makeBeaconBlock*( exits: BeaconBlockExits, sync_aggregate: SyncAggregate, execution_payload: bellatrix.ExecutionPayload, + bls_to_execution_changes: SignedBLSToExecutionChangeList, rollback: RollbackHashedProc[bellatrix.HashedBeaconState], cache: var StateCache, # TODO: @@ -506,9 +513,87 @@ proc makeBeaconBlock*( # To create a block, we'll first apply a partial block to the state, skipping # some validations. - var blck = partialBeaconBlock(cfg, state, proposer_index, - randao_reveal, eth1_data, graffiti, attestations, deposits, - exits, sync_aggregate, execution_payload) + var blck = partialBeaconBlock( + cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, + attestations, deposits, exits, sync_aggregate, execution_payload) + + let res = process_block( + cfg, state.data, blck.asSigVerified(), verificationFlags, cache) + + if res.isErr: + rollback(state) + return err(res.error()) + + state.root = hash_tree_root(state.data) + blck.state_root = state.root + + ok(blck) + +# https://github.com/ethereum/consensus-specs/blob/v1.1.3/specs/merge/validator.md#block-proposal +template partialBeaconBlock( + cfg: RuntimeConfig, + state: var capella.HashedBeaconState, + proposer_index: ValidatorIndex, + randao_reveal: ValidatorSig, + eth1_data: Eth1Data, + graffiti: GraffitiBytes, + attestations: seq[Attestation], + deposits: seq[Deposit], + exits: BeaconBlockExits, + sync_aggregate: SyncAggregate, + execution_payload: capella.ExecutionPayload, + bls_to_execution_changes: SignedBLSToExecutionChangeList + ): + capella.BeaconBlock = + capella.BeaconBlock( + slot: state.data.slot, + proposer_index: proposer_index.uint64, + parent_root: state.latest_block_root, + body: capella.BeaconBlockBody( + randao_reveal: randao_reveal, + eth1_data: eth1data, + graffiti: graffiti, + proposer_slashings: exits.proposer_slashings, + attester_slashings: exits.attester_slashings, + attestations: List[Attestation, Limit MAX_ATTESTATIONS](attestations), + deposits: List[Deposit, Limit MAX_DEPOSITS](deposits), + voluntary_exits: exits.voluntary_exits, + sync_aggregate: sync_aggregate, + execution_payload: execution_payload, + bls_to_execution_changes: bls_to_execution_changes + )) + +proc makeBeaconBlock*( + cfg: RuntimeConfig, + state: var capella.HashedBeaconState, + proposer_index: ValidatorIndex, + randao_reveal: ValidatorSig, + eth1_data: Eth1Data, + graffiti: GraffitiBytes, + attestations: seq[Attestation], + deposits: seq[Deposit], + exits: BeaconBlockExits, + sync_aggregate: SyncAggregate, + execution_payload: capella.ExecutionPayload, + bls_to_execution_changes: SignedBLSToExecutionChangeList, + rollback: RollbackHashedProc[capella.HashedBeaconState], + cache: var StateCache, + # TODO: + # `verificationFlags` is needed only in tests and can be + # removed if we don't use invalid signatures there + verificationFlags: UpdateFlags = {}): Result[capella.BeaconBlock, cstring] = + ## Create a block for the given state. The latest block applied to it will + ## be used for the parent_root value, and the slot will be take from + ## state.slot meaning process_slots must be called up to the slot for which + ## the block is to be created. + + # To create a block, we'll first apply a partial block to the state, skipping + # some validations. + + var blck = partialBeaconBlock( + cfg, state, proposer_index, randao_reveal, eth1_data, graffiti, + attestations, deposits, exits, sync_aggregate, execution_payload, + bls_to_execution_changes) let res = process_block( cfg, state.data, blck.asSigVerified(), verificationFlags, cache) @@ -554,9 +639,10 @@ proc makeBeaconBlock*( var blck = ForkedBeaconBlock.init( - partialBeaconBlock(cfg, state.`kind Data`, proposer_index, - randao_reveal, eth1_data, graffiti, attestations, deposits, - exits, sync_aggregate, executionPayload)) + partialBeaconBlock( + cfg, state.`kind Data`, proposer_index, randao_reveal, eth1_data, + graffiti, attestations, deposits, exits, sync_aggregate, + executionPayload)) let res = process_block( cfg, state.`kind Data`.data, blck.`kind Data`.asSigVerified(), diff --git a/beacon_chain/validators/validator_pool.nim b/beacon_chain/validators/validator_pool.nim index 86c07cf27..eee871b7f 100644 --- a/beacon_chain/validators/validator_pool.nim +++ b/beacon_chain/validators/validator_pool.nim @@ -347,7 +347,7 @@ proc getAggregateAndProofSignature*(v: AttachedValidator, fork, genesis_validators_root, aggregate_and_proof) await v.signData(request) -# https://github.com/ethereum/consensus-specs/blob/v1.2.0/specs/altair/validator.md#prepare-sync-committee-message +# https://github.com/ethereum/consensus-specs/blob/v1.3.0-alpha.0/specs/altair/validator.md#prepare-sync-committee-message proc getSyncCommitteeMessage*(v: AttachedValidator, fork: Fork, genesis_validators_root: Eth2Digest, diff --git a/research/block_sim.nim b/research/block_sim.nim index 75411c123..87eeed502 100644 --- a/research/block_sim.nim +++ b/research/block_sim.nim @@ -32,6 +32,8 @@ import sync_committee_msg_pool], ./simutils +from ../beacon_chain/spec/datatypes/capella import SignedBeaconBlock + type Timers = enum tBlock = "Process non-epoch slot with block" tEpoch = "Process epoch slot with block" @@ -72,7 +74,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6, cfg.ALTAIR_FORK_EPOCH = 1.Epoch cfg.BELLATRIX_FORK_EPOCH = 2.Epoch - cfg.CAPELLA_FORK_EPOCH = FAR_FUTURE_EPOCH + cfg.CAPELLA_FORK_EPOCH = 3.Epoch echo "Starting simulation..." @@ -247,10 +249,9 @@ cli do(slots = SLOTS_PER_EPOCH * 6, sync_aggregate = when T is phase0.SignedBeaconBlock: SyncAggregate.init() - elif T is altair.SignedBeaconBlock or T is bellatrix.SignedBeaconBlock: + elif T is altair.SignedBeaconBlock or T is bellatrix.SignedBeaconBlock or + T is capella.SignedBeaconBlock: syncCommitteePool[].produceSyncAggregate(dag.head.root) - else: - static: doAssert false hashedState = when T is phase0.SignedBeaconBlock: addr state.phase0Data @@ -258,6 +259,8 @@ cli do(slots = SLOTS_PER_EPOCH * 6, addr state.altairData elif T is bellatrix.SignedBeaconBlock: addr state.bellatrixData + elif T is capella.SignedBeaconBlock: + addr state.capellaData else: static: doAssert false message = makeBeaconBlock( @@ -274,7 +277,11 @@ cli do(slots = SLOTS_PER_EPOCH * 6, eth1ProposalData.deposits, BeaconBlockExits(), sync_aggregate, - default(ExecutionPayload), + when T is capella.SignedBeaconBlock: + default(capella.ExecutionPayload) + else: + default(bellatrix.ExecutionPayload), + default(SignedBLSToExecutionChangeList), noRollback, cache) @@ -296,6 +303,10 @@ cli do(slots = SLOTS_PER_EPOCH * 6, newBlock + # TODO when withUpdatedState's state template doesn't conflict with chronos's + # HTTP server's state function, combine all proposeForkBlock functions into a + # single generic function. Until https://github.com/nim-lang/Nim/issues/20811 + # is fixed, that generic function must take `blockRatio` as a parameter. proc proposePhase0Block(slot: Slot) = if rand(r, 1.0) > blockRatio: return @@ -362,6 +373,28 @@ cli do(slots = SLOTS_PER_EPOCH * 6, do: raiseAssert "withUpdatedState failed" + proc proposeCapellaBlock(slot: Slot) = + if rand(r, 1.0) > blockRatio: + return + + dag.withUpdatedState(tmpState[], dag.getBlockIdAtSlot(slot).expect("block")) do: + let + newBlock = getNewBlock[capella.SignedBeaconBlock](state, slot, cache) + added = dag.addHeadBlock(verifier, newBlock) do ( + blckRef: BlockRef, signedBlock: capella.TrustedSignedBeaconBlock, + epochRef: EpochRef, unrealized: FinalityCheckpoints): + # Callback add to fork choice if valid + attPool.addForkChoice( + epochRef, blckRef, unrealized, signedBlock.message, + blckRef.slot.start_beacon_time) + + dag.updateHead(added[], quarantine[]) + if dag.needStateCachesAndForkChoicePruning(): + dag.pruneStateCachesDAG() + attPool.prune() + do: + raiseAssert "withUpdatedState failed" + var lastEth1BlockAt = genesisTime eth1BlockNum = 1000 @@ -402,7 +435,7 @@ cli do(slots = SLOTS_PER_EPOCH * 6, if blockRatio > 0.0: withTimer(timers[t]): case dag.cfg.stateForkAtEpoch(slot.epoch) - of BeaconStateFork.Capella: raiseAssert $capellaImplementationMissing + of BeaconStateFork.Capella: proposeCapellaBlock(slot) of BeaconStateFork.Bellatrix: proposeBellatrixBlock(slot) of BeaconStateFork.Altair: proposeAltairBlock(slot) of BeaconStateFork.Phase0: proposePhase0Block(slot)