Skip to content

Commit

Permalink
Fix block building in /eth/v3/validator/blocks/{slot}:
Browse files Browse the repository at this point in the history
- return block proposal even if consensus_block_value calculation fails
- fix consensus_block_value calculation by providing real execution payload
- convert consensus_block_value to Wei
  • Loading branch information
Tumas committed Apr 19, 2024
1 parent c7ea853 commit d1ec94b
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 48 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions http_api/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,13 @@ impl<P: Preset> From<WithBlobsAndMev<ValidatorBlindedBlock<P>, P>>
} = block;

match validator_blinded_block {
ValidatorBlindedBlock::BlindedBeaconBlock(blinded_block) => {
Self::Other(ValidatorBlindedBlock::BlindedBeaconBlock(blinded_block))
}
ValidatorBlindedBlock::BlindedBeaconBlock {
blinded_block,
execution_payload,
} => Self::Other(ValidatorBlindedBlock::BlindedBeaconBlock {
blinded_block,
execution_payload,
}),
ValidatorBlindedBlock::BeaconBlock(combined_block) => match combined_block {
BeaconBlock::Phase0(block) => {
Self::Other(ValidatorBlindedBlock::BeaconBlock(block.into()))
Expand Down
4 changes: 2 additions & 2 deletions http_api/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ impl<T, M, F> EthResponse<T, M, F> {
self
}

pub const fn consensus_block_value(mut self, consensus_block_value: Wei) -> Self {
self.consensus_block_value = Some(consensus_block_value);
pub const fn consensus_block_value(mut self, consensus_block_value: Option<Wei>) -> Self {
self.consensus_block_value = consensus_block_value;
self
}

Expand Down
30 changes: 21 additions & 9 deletions http_api/src/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ use types::{
containers::{SignedContributionAndProof, SyncCommitteeContribution, SyncCommitteeMessage},
primitives::SubcommitteeIndex,
},
bellatrix::primitives::Wei,
capella::containers::{SignedBlsToExecutionChange, Withdrawal},
combined::{BeaconBlock, BeaconState, SignedBeaconBlock, SignedBlindedBeaconBlock},
config::Config as ChainConfig,
Expand All @@ -65,6 +64,7 @@ use types::{
},
nonstandard::{
Phase, RelativeEpoch, SlashingKind, ValidationOutcome, WithBlobsAndMev, WithStatus,
WEI_IN_GWEI,
},
phase0::{
consts::{GENESIS_EPOCH, GENESIS_SLOT},
Expand All @@ -73,8 +73,8 @@ use types::{
SignedAggregateAndProof, SignedBeaconBlockHeader, SignedVoluntaryExit, Validator,
},
primitives::{
ChainId, CommitteeIndex, Epoch, ExecutionAddress, Gwei, Slot, SubnetId, UnixSeconds,
ValidatorIndex, Version, H256,
ChainId, CommitteeIndex, Epoch, ExecutionAddress, Gwei, Slot, SubnetId, Uint256,
UnixSeconds, ValidatorIndex, Version, H256,
},
},
preset::Preset,
Expand Down Expand Up @@ -1939,21 +1939,33 @@ pub async fn validator_block_v3<P: Preset, W: Wait>(
let version = validator_block.value.phase();
let blinded = validator_block.value.is_blinded();

// 'Uplift' validator block to default signed beacon block for consensus reward calculation
// 'Uplift' validator block to signed beacon block for consensus reward calculation
let signed_beacon_block = match validator_block.value.clone() {
ValidatorBlindedBlock::BeaconBlock(beacon_block) => beacon_block.into(),
ValidatorBlindedBlock::BlindedBeaconBlock(blinded_block) => {
let beacon_block = blinded_block.with_default_execution_payload()?;
ValidatorBlindedBlock::BlindedBeaconBlock {
blinded_block,
execution_payload,
} => {
let beacon_block = blinded_block
.with_execution_payload(*execution_payload)
.map_err(AnyhowError::new)?;

beacon_block.into()
}
};

let rewards =
calculate_block_rewards(&chain_config, &controller, &Arc::new(signed_beacon_block))?;
let consensus_block_value =
match calculate_block_rewards(&chain_config, &controller, &Arc::new(signed_beacon_block)) {
Ok(rewards) => Some(Uint256::from_u64(rewards.total) * WEI_IN_GWEI),
Err(error) => {
warn!("unable to calculate block rewards for validator block: {error:?}");
None
}
};

Ok(EthResponse::json_or_ssz(validator_block.into(), &headers)
.version(version)
.consensus_block_value(Wei::from_u64(rewards.total))
.consensus_block_value(consensus_block_value)
.execution_payload_blinded(blinded)
.execution_payload_value(mev.unwrap_or_default()))
}
Expand Down
1 change: 0 additions & 1 deletion types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ authors = ["Grandine <[email protected]>"]
workspace = true

[dependencies]
anyhow = { workspace = true }
arithmetic = { workspace = true }
bit_field = { workspace = true }
bls = { workspace = true }
Expand Down
28 changes: 11 additions & 17 deletions types/src/combined.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use anyhow::{bail, Error as AnyhowError, Result as AnyhowResult};
use bls::SignatureBytes;
use derive_more::From;
use duplicate::duplicate_item;
Expand Down Expand Up @@ -573,6 +572,17 @@ impl<P: Preset> BeaconBlock<P> {
}
}

pub fn execution_payload(self) -> Option<ExecutionPayload<P>> {
match self {
Self::Phase0(_) | Self::Altair(_) => None,
Self::Bellatrix(block) => {
Some(ExecutionPayload::Bellatrix(block.body.execution_payload))
}
Self::Capella(block) => Some(ExecutionPayload::Capella(block.body.execution_payload)),
Self::Deneb(block) => Some(ExecutionPayload::Deneb(block.body.execution_payload)),
}
}

pub const fn phase(&self) -> Phase {
match self {
Self::Phase0(_) => Phase::Phase0,
Expand Down Expand Up @@ -766,22 +776,6 @@ impl<P: Preset> BlindedBeaconBlock<P> {
self
}

pub fn with_default_execution_payload(self) -> AnyhowResult<BeaconBlock<P>> {
let execution_payload = match self.phase() {
Phase::Bellatrix => ExecutionPayload::Bellatrix(BellatrixExecutionPayload::default()),
Phase::Capella => ExecutionPayload::Capella(CapellaExecutionPayload::default()),
Phase::Deneb => ExecutionPayload::Deneb(DenebExecutionPayload::default()),
_ => {
bail!(ExecutionPayloadPhaseError {
payload_phase: self.phase(),
});
}
};

self.with_execution_payload(execution_payload)
.map_err(AnyhowError::new)
}

pub fn with_execution_payload(
self,
execution_payload: ExecutionPayload<P>,
Expand Down
4 changes: 3 additions & 1 deletion types/src/nonstandard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ use crate::{
},
phase0::{
containers::Attestation,
primitives::{UnixSeconds, ValidatorIndex, H256},
primitives::{Uint256, UnixSeconds, ValidatorIndex, H256},
},
preset::Preset,
};

pub use smallvec::smallvec;

pub const WEI_IN_GWEI: Uint256 = Uint256::from_u64(1_000_000_000);

#[derive(
Clone,
Copy,
Expand Down
37 changes: 28 additions & 9 deletions validator/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use ssz::{BitVector, Size, SszHash, SszSize, SszWrite, WriteError, H256};
use typenum::U1;
use types::{
altair::consts::SyncCommitteeSubnetCount,
combined::{BeaconBlock, BlindedBeaconBlock},
combined::{BeaconBlock, BlindedBeaconBlock, ExecutionPayload},
nonstandard::Phase,
phase0::primitives::{ValidatorIndex, H160},
preset::Preset,
traits::BeaconBlock as _,
traits::{BeaconBlock as _, PostDenebBeaconBlockBody},
};

#[allow(clippy::struct_field_names)]
Expand All @@ -35,7 +35,12 @@ pub struct ProposerData {
#[derive(Clone, Serialize)]
#[serde(bound = "", untagged)]
pub enum ValidatorBlindedBlock<P: Preset> {
BlindedBeaconBlock(BlindedBeaconBlock<P>),
BlindedBeaconBlock {
#[serde(flatten)]
blinded_block: BlindedBeaconBlock<P>,
#[serde(skip)]
execution_payload: Box<ExecutionPayload<P>>,
},
BeaconBlock(BeaconBlock<P>),
}

Expand All @@ -51,7 +56,7 @@ impl<P: Preset> SszHash for ValidatorBlindedBlock<P> {

fn hash_tree_root(&self) -> H256 {
match self {
Self::BlindedBeaconBlock(block) => block.hash_tree_root(),
Self::BlindedBeaconBlock { blinded_block, .. } => blinded_block.hash_tree_root(),
Self::BeaconBlock(block) => block.hash_tree_root(),
}
}
Expand All @@ -60,7 +65,7 @@ impl<P: Preset> SszHash for ValidatorBlindedBlock<P> {
impl<P: Preset> SszWrite for ValidatorBlindedBlock<P> {
fn write_variable(&self, bytes: &mut Vec<u8>) -> Result<(), WriteError> {
match self {
Self::BlindedBeaconBlock(block) => block.write_variable(bytes),
Self::BlindedBeaconBlock { blinded_block, .. } => blinded_block.write_variable(bytes),
Self::BeaconBlock(block) => block.write_variable(bytes),
}
}
Expand All @@ -77,24 +82,38 @@ impl<P: Preset> ValidatorBlindedBlock<P> {
return Self::BeaconBlock(block);
};

let execution_payload = block
.clone()
.execution_payload()
.expect("post-Bellatrix blocks should have execution payload");

let kzg_commitments = block
.body()
.post_deneb()
.map(PostDenebBeaconBlockBody::blob_kzg_commitments)
.cloned();

let payload_header = body.execution_payload().to_header();
let blinded_block = block
.into_blinded(payload_header, None)
.into_blinded(payload_header, kzg_commitments)
.expect("phases should match because payload header was taken from block");

Self::BlindedBeaconBlock(blinded_block)
Self::BlindedBeaconBlock {
blinded_block,
execution_payload: Box::new(execution_payload),
}
}

#[must_use]
pub const fn phase(&self) -> Phase {
match self {
Self::BlindedBeaconBlock(block) => block.phase(),
Self::BlindedBeaconBlock { blinded_block, .. } => blinded_block.phase(),
Self::BeaconBlock(block) => block.phase(),
}
}

#[must_use]
pub const fn is_blinded(&self) -> bool {
matches!(self, Self::BlindedBeaconBlock(_))
matches!(self, Self::BlindedBeaconBlock { .. })
}
}
20 changes: 16 additions & 4 deletions validator/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,14 @@ impl<P: Preset, W: Wait + Sync> Validator<P, W> {
blob_kzg_commitments,
skip_randao_verification,
) {
let block = ValidatorBlindedBlock::BlindedBeaconBlock(blinded_block);
let block = ValidatorBlindedBlock::BlindedBeaconBlock {
blinded_block,
execution_payload: Box::new(
beacon_block.value.execution_payload().expect(
"post-Bellatrix blocks should have execution payload",
),
),
};

return Ok(Some(WithBlobsAndMev::new(
block,
Expand Down Expand Up @@ -1381,15 +1388,20 @@ impl<P: Preset, W: Wait + Sync> Validator<P, W> {
};

let beacon_block = match validator_blinded_block {
ValidatorBlindedBlock::BlindedBeaconBlock(message) => {
ValidatorBlindedBlock::BlindedBeaconBlock { blinded_block, .. } => {
let Some(signature) = slot_head
.sign_beacon_block(&self.signer, &message, (&message).into(), public_key)
.sign_beacon_block(
&self.signer,
&blinded_block,
(&blinded_block).into(),
public_key,
)
.await
else {
return Ok(());
};

let signed_blinded_block = message.with_signature(signature);
let signed_blinded_block = blinded_block.with_signature(signature);

let builder_api = self.builder_api.as_ref().expect(
"Builder API should be present as it was used to query ExecutionPayloadHeader",
Expand Down

0 comments on commit d1ec94b

Please sign in to comment.