From 3f972a2ca5ae156624dfe24ed669e0c16b92a6b3 Mon Sep 17 00:00:00 2001 From: tersec Date: Tue, 14 May 2024 07:12:35 +0300 Subject: [PATCH] add some support for electra aggregated attestations (#6283) --- .../gossip_processing/batch_validation.nim | 2 +- .../gossip_processing/eth2_processor.nim | 2 +- .../gossip_processing/gossip_validation.nim | 2 +- beacon_chain/networking/eth2_network.nim | 4 ++-- beacon_chain/nimbus_beacon_node.nim | 18 +++++++++++++++--- beacon_chain/rpc/rest_validator_api.nim | 2 +- beacon_chain/spec/datatypes/electra.nim | 11 +++++++++++ .../spec/eth2_apis/eth2_rest_serialization.nim | 8 ++++---- beacon_chain/spec/eth2_apis/rest_types.nim | 4 ++-- .../spec/eth2_apis/rest_validator_calls.nim | 2 +- beacon_chain/spec/signatures.nim | 6 +++--- beacon_chain/spec/signatures_batch.nim | 2 +- beacon_chain/validator_client/api.nim | 2 +- .../validator_client/attestation_service.nim | 8 ++++---- beacon_chain/validators/beacon_validators.nim | 4 ++-- beacon_chain/validators/message_router.nim | 2 +- beacon_chain/validators/validator_monitor.nim | 2 +- beacon_chain/validators/validator_pool.nim | 2 +- tests/test_message_signatures.nim | 2 +- tests/test_signing_node.nim | 2 +- 20 files changed, 55 insertions(+), 32 deletions(-) diff --git a/beacon_chain/gossip_processing/batch_validation.nim b/beacon_chain/gossip_processing/batch_validation.nim index 60e5abd2f..39e0743a9 100644 --- a/beacon_chain/gossip_processing/batch_validation.nim +++ b/beacon_chain/gossip_processing/batch_validation.nim @@ -414,7 +414,7 @@ proc scheduleAttestationCheck*( proc scheduleAggregateChecks*( batchCrypto: ref BatchCrypto, fork: Fork, - signedAggregateAndProof: SignedAggregateAndProof, dag: ChainDAGRef, + signedAggregateAndProof: phase0.SignedAggregateAndProof, dag: ChainDAGRef, attesting_indices: openArray[ValidatorIndex] ): Result[tuple[ aggregatorFut, slotFut, aggregateFut: FutureBatchResult, diff --git a/beacon_chain/gossip_processing/eth2_processor.nim b/beacon_chain/gossip_processing/eth2_processor.nim index 7410b23cc..d22f7dce9 100644 --- a/beacon_chain/gossip_processing/eth2_processor.nim +++ b/beacon_chain/gossip_processing/eth2_processor.nim @@ -412,7 +412,7 @@ proc processAttestation*( proc processSignedAggregateAndProof*( self: ref Eth2Processor, src: MsgSource, - signedAggregateAndProof: SignedAggregateAndProof, + signedAggregateAndProof: phase0.SignedAggregateAndProof, checkSignature = true, checkCover = true): Future[ValidationRes] {.async: (raises: [CancelledError]).} = var wallTime = self.getCurrentBeaconTime() let (afterGenesis, wallSlot) = wallTime.toSlot() diff --git a/beacon_chain/gossip_processing/gossip_validation.nim b/beacon_chain/gossip_processing/gossip_validation.nim index 8e6a8fbdc..593c95a94 100644 --- a/beacon_chain/gossip_processing/gossip_validation.nim +++ b/beacon_chain/gossip_processing/gossip_validation.nim @@ -822,7 +822,7 @@ proc validateAttestation*( proc validateAggregate*( pool: ref AttestationPool, batchCrypto: ref BatchCrypto, - signedAggregateAndProof: SignedAggregateAndProof, + signedAggregateAndProof: phase0.SignedAggregateAndProof, wallTime: BeaconTime, checkSignature = true, checkCover = true): Future[Result[ diff --git a/beacon_chain/networking/eth2_network.nim b/beacon_chain/networking/eth2_network.nim index cbea656ed..d5d754ba6 100644 --- a/beacon_chain/networking/eth2_network.nim +++ b/beacon_chain/networking/eth2_network.nim @@ -838,7 +838,7 @@ template gossipMaxSize(T: untyped): uint32 = # have lists bounded at MAX_VALIDATORS_PER_COMMITTEE (2048) items, thus # having max sizes significantly smaller than GOSSIP_MAX_SIZE. elif T is phase0.Attestation or T is phase0.AttesterSlashing or - T is SignedAggregateAndProof or T is phase0.SignedBeaconBlock or + T is phase0.SignedAggregateAndProof or T is phase0.SignedBeaconBlock or T is altair.SignedBeaconBlock or T is SomeForkyLightClientObject: GOSSIP_MAX_SIZE else: @@ -2611,7 +2611,7 @@ proc broadcastBlsToExecutionChange*( node.broadcast(topic, bls_to_execution_change) proc broadcastAggregateAndProof*( - node: Eth2Node, proof: SignedAggregateAndProof): + node: Eth2Node, proof: phase0.SignedAggregateAndProof): Future[SendResult] {.async: (raises: [CancelledError], raw: true).} = let topic = getAggregateAndProofsTopic( node.forkDigestAtEpoch(node.getWallEpoch)) diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index e202e9446..faefb772c 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -1111,6 +1111,10 @@ proc addDenebMessageHandlers( for topic in blobSidecarTopics(forkDigest): node.network.subscribe(topic, basicParams) +proc addElectraMessageHandlers( + node: BeaconNode, forkDigest: ForkDigest, slot: Slot) = + node.addDenebMessageHandlers(forkDigest, slot) + proc removeAltairMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) = node.removePhase0MessageHandlers(forkDigest) @@ -1131,6 +1135,9 @@ proc removeDenebMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) = for topic in blobSidecarTopics(forkDigest): node.network.unsubscribe(topic) +proc removeElectraMessageHandlers(node: BeaconNode, forkDigest: ForkDigest) = + node.removeDenebMessageHandlers(forkDigest) + proc updateSyncCommitteeTopics(node: BeaconNode, slot: Slot) = template lastSyncUpdate: untyped = node.consensusManager[].actionTracker.lastSyncUpdate @@ -1359,7 +1366,7 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} = removeAltairMessageHandlers, # bellatrix (altair handlers, different forkDigest) removeCapellaMessageHandlers, removeDenebMessageHandlers, - removeDenebMessageHandlers # maybe duplicate is correct, don't know yet + removeElectraMessageHandlers ] for gossipFork in oldGossipForks: @@ -1372,7 +1379,7 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} = addAltairMessageHandlers, # bellatrix (altair handlers, different forkDigest) addCapellaMessageHandlers, addDenebMessageHandlers, - addDenebMessageHandlers # repeat is probably correct + addElectraMessageHandlers ] for gossipFork in newGossipForks: @@ -1750,6 +1757,7 @@ proc installMessageValidators(node: BeaconNode) = # beacon_attestation_{subnet_id} # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id for it in SubnetId: + debugRaiseAssert "allow for electra.Attestation" closureScope: # Needed for inner `proc`; don't lift it out of loop. let subnet_id = it node.network.addAsyncValidator( @@ -1762,9 +1770,10 @@ proc installMessageValidators(node: BeaconNode) = # beacon_aggregate_and_proof # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.4/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof + debugRaiseAssert "allow for electra.SignedAggregateAndProof" node.network.addAsyncValidator( getAggregateAndProofsTopic(digest), proc ( - signedAggregateAndProof: SignedAggregateAndProof + signedAggregateAndProof: phase0.SignedAggregateAndProof ): Future[ValidationResult] {.async: (raises: [CancelledError]).} = return toValidationResult( await node.processor.processSignedAggregateAndProof( @@ -1848,6 +1857,9 @@ proc installMessageValidators(node: BeaconNode) = node.processor[].processBlobSidecar( MsgSource.gossip, blobSidecar, subnet_id))) + when consensusFork >= ConsensusFork.Electra: + discard + node.installLightClientMessageValidators() proc stop(node: BeaconNode) = diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index f468e88c4..b1b1c17e7 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -801,7 +801,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = block: if contentBody.isNone(): return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) - let dres = decodeBody(seq[SignedAggregateAndProof], contentBody.get()) + let dres = decodeBody(seq[phase0.SignedAggregateAndProof], contentBody.get()) if dres.isErr(): return RestApiResponse.jsonError(Http400, InvalidAggregateAndProofObjectError, diff --git a/beacon_chain/spec/datatypes/electra.nim b/beacon_chain/spec/datatypes/electra.nim index a7966bd9e..cefbf23fb 100644 --- a/beacon_chain/spec/datatypes/electra.nim +++ b/beacon_chain/spec/datatypes/electra.nim @@ -196,6 +196,17 @@ type NextSyncCommitteeBranch = array[log2trunc(NEXT_SYNC_COMMITTEE_GINDEX), Eth2Digest] + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#aggregateandproof + AggregateAndProof* = object + aggregator_index*: uint64 # `ValidatorIndex` after validation + aggregate*: Attestation + selection_proof*: ValidatorSig + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#signedaggregateandproof + SignedAggregateAndProof* = object + message*: AggregateAndProof + signature*: ValidatorSig + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/light-client/sync-protocol.md#modified-lightclientheader LightClientHeader* = object beacon*: BeaconBlockHeader diff --git a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim index f20fb4078..cf1af3677 100644 --- a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim +++ b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim @@ -44,7 +44,6 @@ type createJsonFlavor RestJson RestJson.useDefaultSerializationFor( - AggregateAndProof, AttestationData, BLSToExecutionChange, BeaconBlockHeader, @@ -168,7 +167,6 @@ RestJson.useDefaultSerializationFor( SetFeeRecipientRequest, SetGasLimitRequest, SetGraffitiRequest, - SignedAggregateAndProof, SignedBLSToExecutionChange, SignedBeaconBlockHeader, SignedConsolidation, @@ -263,12 +261,14 @@ RestJson.useDefaultSerializationFor( electra_mev.ExecutionPayloadAndBlobsBundle, electra_mev.SignedBlindedBeaconBlock, electra_mev.SignedBuilderBid, + phase0.AggregateAndProof, phase0.Attestation, phase0.AttesterSlashing, phase0.BeaconBlock, phase0.BeaconBlockBody, phase0.BeaconState, phase0.IndexedAttestation, + phase0.SignedAggregateAndProof, phase0.SignedBeaconBlock, phase0.TrustedAttestation ) @@ -365,7 +365,7 @@ type seq[RestSignedContributionAndProof] | seq[RestSyncCommitteeMessage] | seq[RestSyncCommitteeSubscription] | - seq[SignedAggregateAndProof] | + seq[phase0.SignedAggregateAndProof] | seq[SignedValidatorRegistrationV1] | seq[ValidatorIndex] | seq[RestBeaconCommitteeSelection] | @@ -2743,7 +2743,7 @@ proc readValue*(reader: var JsonReader[RestJson], reader.raiseUnexpectedValue("Field `fork_info` is missing") let data = block: - let res = decodeJsonString(AggregateAndProof, data.get()) + let res = decodeJsonString(phase0.AggregateAndProof, data.get()) if res.isErr(): reader.raiseUnexpectedValue( "Incorrect field `aggregate_and_proof` format") diff --git a/beacon_chain/spec/eth2_apis/rest_types.nim b/beacon_chain/spec/eth2_apis/rest_types.nim index e8d9acf43..13c9ed7fd 100644 --- a/beacon_chain/spec/eth2_apis/rest_types.nim +++ b/beacon_chain/spec/eth2_apis/rest_types.nim @@ -477,7 +477,7 @@ type serializedFieldName: "aggregation_slot".}: Web3SignerAggregationSlotData of Web3SignerRequestKind.AggregateAndProof: aggregateAndProof* {. - serializedFieldName: "aggregate_and_proof".}: AggregateAndProof + serializedFieldName: "aggregate_and_proof".}: phase0.AggregateAndProof of Web3SignerRequestKind.Attestation: attestation*: AttestationData of Web3SignerRequestKind.BlockV2: @@ -799,7 +799,7 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork, ) func init*(t: typedesc[Web3SignerRequest], fork: Fork, - genesis_validators_root: Eth2Digest, data: AggregateAndProof, + genesis_validators_root: Eth2Digest, data: phase0.AggregateAndProof, signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest) ): Web3SignerRequest = Web3SignerRequest( diff --git a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim index 5b63474fa..e7c907079 100644 --- a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim +++ b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim @@ -80,7 +80,7 @@ proc getAggregatedAttestationPlain*( ## https://ethereum.github.io/beacon-APIs/#/Validator/getAggregatedAttestation proc publishAggregateAndProofs*( - body: seq[SignedAggregateAndProof] + body: seq[phase0.SignedAggregateAndProof] ): RestPlainResponse {. rest, endpoint: "/eth/v1/validator/aggregate_and_proofs", meth: MethodPost.} diff --git a/beacon_chain/spec/signatures.nim b/beacon_chain/spec/signatures.nim index ff326ddb7..12f2a0c72 100644 --- a/beacon_chain/spec/signatures.nim +++ b/beacon_chain/spec/signatures.nim @@ -108,7 +108,7 @@ proc verify_block_signature*( func compute_aggregate_and_proof_signing_root*( fork: Fork, genesis_validators_root: Eth2Digest, - aggregate_and_proof: AggregateAndProof): Eth2Digest = + aggregate_and_proof: phase0.AggregateAndProof): Eth2Digest = let epoch = epoch(aggregate_and_proof.aggregate.data.slot) domain = get_domain( @@ -117,7 +117,7 @@ func compute_aggregate_and_proof_signing_root*( # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#broadcast-aggregate func get_aggregate_and_proof_signature*(fork: Fork, genesis_validators_root: Eth2Digest, - aggregate_and_proof: AggregateAndProof, + aggregate_and_proof: phase0.AggregateAndProof, privkey: ValidatorPrivKey): CookedSig = let signing_root = compute_aggregate_and_proof_signing_root( fork, genesis_validators_root, aggregate_and_proof) @@ -126,7 +126,7 @@ func get_aggregate_and_proof_signature*(fork: Fork, genesis_validators_root: Eth proc verify_aggregate_and_proof_signature*( fork: Fork, genesis_validators_root: Eth2Digest, - aggregate_and_proof: AggregateAndProof, + aggregate_and_proof: phase0.AggregateAndProof, pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool = withTrust(signature): let signing_root = compute_aggregate_and_proof_signing_root( diff --git a/beacon_chain/spec/signatures_batch.nim b/beacon_chain/spec/signatures_batch.nim index f8d6f3dd1..60ef3fd07 100644 --- a/beacon_chain/spec/signatures_batch.nim +++ b/beacon_chain/spec/signatures_batch.nim @@ -164,7 +164,7 @@ func block_signature_set*( # See also: verify_aggregate_and_proof_signature func aggregate_and_proof_signature_set*( fork: Fork, genesis_validators_root: Eth2Digest, - aggregate_and_proof: AggregateAndProof, + aggregate_and_proof: phase0.AggregateAndProof, pubkey: CookedPubKey, signature: CookedSig): SignatureSet = let signing_root = compute_aggregate_and_proof_signing_root( fork, genesis_validators_root, aggregate_and_proof) diff --git a/beacon_chain/validator_client/api.nim b/beacon_chain/validator_client/api.nim index 73bc18478..ceb43b923 100644 --- a/beacon_chain/validator_client/api.nim +++ b/beacon_chain/validator_client/api.nim @@ -1890,7 +1890,7 @@ proc produceSyncCommitteeContribution*( proc publishAggregateAndProofs*( vc: ValidatorClientRef, - data: seq[SignedAggregateAndProof], + data: seq[phase0.SignedAggregateAndProof], strategy: ApiStrategyKind ): Future[bool] {.async.} = const diff --git a/beacon_chain/validator_client/attestation_service.nim b/beacon_chain/validator_client/attestation_service.nim index 1cfd587c7..33feb85dd 100644 --- a/beacon_chain/validator_client/attestation_service.nim +++ b/beacon_chain/validator_client/attestation_service.nim @@ -85,7 +85,7 @@ proc serveAttestation( return res proc serveAggregateAndProof*(service: AttestationServiceRef, - proof: AggregateAndProof, + proof: phase0.AggregateAndProof, validator: AttachedValidator): Future[bool] {. async.} = let @@ -117,8 +117,8 @@ proc serveAggregateAndProof*(service: AttestationServiceRef, err_name = exc.name, err_msg = exc.msg return false - let signedProof = SignedAggregateAndProof(message: proof, - signature: signature) + let signedProof = phase0.SignedAggregateAndProof( + message: proof, signature: signature) logScope: delay = vc.getDelay(slot.aggregate_deadline()) @@ -306,7 +306,7 @@ proc produceAndPublishAggregates(service: AttestationServiceRef, block: var res: seq[Future[bool]] for item in aggregateItems: - let proof = AggregateAndProof( + let proof = phase0.AggregateAndProof( aggregator_index: item.aggregator_index, aggregate: aggAttestation, selection_proof: item.selection_proof diff --git a/beacon_chain/validators/beacon_validators.nim b/beacon_chain/validators/beacon_validators.nim index c0263909a..f11498de0 100644 --- a/beacon_chain/validators/beacon_validators.nim +++ b/beacon_chain/validators/beacon_validators.nim @@ -1537,8 +1537,8 @@ proc signAndSendAggregate( # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#construct-aggregate # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/validator.md#aggregateandproof var - msg = SignedAggregateAndProof( - message: AggregateAndProof( + msg = phase0.SignedAggregateAndProof( + message: phase0.AggregateAndProof( aggregator_index: uint64 validator_index, selection_proof: selectionProof)) diff --git a/beacon_chain/validators/message_router.nim b/beacon_chain/validators/message_router.nim index 50a6ec059..d19c3d360 100644 --- a/beacon_chain/validators/message_router.nim +++ b/beacon_chain/validators/message_router.nim @@ -252,7 +252,7 @@ proc routeAttestation*( attestation, subnet_id, checkSignature = true) proc routeSignedAggregateAndProof*( - router: ref MessageRouter, proof: SignedAggregateAndProof, + router: ref MessageRouter, proof: phase0.SignedAggregateAndProof, checkSignature = true): Future[SendResult] {.async: (raises: [CancelledError]).} = ## Validate and broadcast aggregate diff --git a/beacon_chain/validators/validator_monitor.nim b/beacon_chain/validators/validator_monitor.nim index bc7c79696..98b552c4e 100644 --- a/beacon_chain/validators/validator_monitor.nim +++ b/beacon_chain/validators/validator_monitor.nim @@ -685,7 +685,7 @@ proc registerAggregate*( self: var ValidatorMonitor, src: MsgSource, seen_timestamp: BeaconTime, - aggregate_and_proof: AggregateAndProof, + aggregate_and_proof: phase0.AggregateAndProof, attesting_indices: openArray[ValidatorIndex]) = let slot = aggregate_and_proof.aggregate.data.slot diff --git a/beacon_chain/validators/validator_pool.nim b/beacon_chain/validators/validator_pool.nim index e7855fd1a..52a4d0741 100644 --- a/beacon_chain/validators/validator_pool.nim +++ b/beacon_chain/validators/validator_pool.nim @@ -735,7 +735,7 @@ proc getAttestationSignature*(v: AttachedValidator, fork: Fork, proc getAggregateAndProofSignature*(v: AttachedValidator, fork: Fork, genesis_validators_root: Eth2Digest, - aggregate_and_proof: AggregateAndProof + aggregate_and_proof: phase0.AggregateAndProof ): Future[SignatureResult] {.async: (raises: [CancelledError]).} = case v.kind diff --git a/tests/test_message_signatures.nim b/tests/test_message_signatures.nim index 41b9031bc..86ade21ba 100644 --- a/tests/test_message_signatures.nim +++ b/tests/test_message_signatures.nim @@ -60,7 +60,7 @@ suite "Message signatures": fork0, genesis_validators_root1, slot, root, privkey0).toValidatorSig) test "Aggregate and proof signatures": - let aggregate_and_proof = AggregateAndProof( + let aggregate_and_proof = phase0.AggregateAndProof( aggregate: phase0.Attestation( aggregation_bits: CommitteeValidatorsBits.init(8))) diff --git a/tests/test_signing_node.nim b/tests/test_signing_node.nim index 3555d078d..6805aac89 100644 --- a/tests/test_signing_node.nim +++ b/tests/test_signing_node.nim @@ -678,7 +678,7 @@ block: GetAggregatedAttestationResponse, AgAttestation.toOpenArrayByte(0, len(AgAttestation) - 1), Opt.some(contentType)).tryGet().data - agProof = AggregateAndProof( + agProof = phase0.AggregateAndProof( aggregator_index: 1'u64, aggregate: agAttestation, selection_proof: ValidatorSig.fromHex(SomeSignature).get())