Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 65 additions & 84 deletions validator_client/validator_services/src/block_service.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, Error as FallbackError, Errors};
use bls::SignatureBytes;
use eth2::{BeaconNodeHttpClient, StatusCode};
use graffiti_file::{GraffitiFile, determine_graffiti};
use logging::crit;
Expand Down Expand Up @@ -298,7 +297,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> BlockService<S, T> {
self.inner.executor.spawn(
async move {
let result = service
.publish_block(slot, validator_pubkey, builder_boost_factor)
.get_validator_block_and_publish_block(slot, validator_pubkey, builder_boost_factor)
.await;

match result {
Expand Down Expand Up @@ -389,7 +388,7 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> BlockService<S, T> {
Ok(())
}

async fn publish_block(
async fn get_validator_block_and_publish_block(
self,
slot: Slot,
validator_pubkey: PublicKeyBytes,
Expand Down Expand Up @@ -446,29 +445,75 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> BlockService<S, T> {
//
// Try the proposer nodes last, since it's likely that they don't have a
// great view of attestations on the network.
let unsigned_block = proposer_fallback
let ssz_block_response = proposer_fallback
.request_proposers_last(|beacon_node| async move {
let _get_timer = validator_metrics::start_timer_vec(
&validator_metrics::BLOCK_SERVICE_TIMES,
&[validator_metrics::BEACON_BLOCK_HTTP_GET],
);
Self::get_validator_block(
&beacon_node,
slot,
randao_reveal_ref,
graffiti,
proposer_index,
builder_boost_factor,
)
.await
.map_err(|e| {
BlockError::Recoverable(format!(
"Error from beacon node when producing block: {:?}",
e
))
})
beacon_node
.get_validator_blocks_v3_ssz::<S::E>(
slot,
randao_reveal_ref,
graffiti.as_ref(),
builder_boost_factor,
)
.await
})
.await?;
.await;

let block_response = match ssz_block_response {
Ok((ssz_block_response, _metadata)) => ssz_block_response,
Err(e) => {
warn!(
slot = slot.as_u64(),
error = %e,
"SSZ block production failed, falling back to JSON"
);

proposer_fallback
.request_proposers_last(|beacon_node| async move {
let _get_timer = validator_metrics::start_timer_vec(
&validator_metrics::BLOCK_SERVICE_TIMES,
&[validator_metrics::BEACON_BLOCK_HTTP_GET],
);
let (json_block_response, _metadata) = beacon_node
.get_validator_blocks_v3::<S::E>(
slot,
randao_reveal_ref,
graffiti.as_ref(),
builder_boost_factor,
)
.await
.map_err(|e| {
BlockError::Recoverable(format!(
"Error from beacon node when producing block: {:?}",
e
))
})?;

Ok(json_block_response.data)
})
.await
.map_err(BlockError::from)?
}
};

let (block_proposer, unsigned_block) = match block_response {
eth2::types::ProduceBlockV3Response::Full(block) => {
(block.block().proposer_index(), UnsignedBlock::Full(block))
}
eth2::types::ProduceBlockV3Response::Blinded(block) => {
(block.proposer_index(), UnsignedBlock::Blinded(block))
}
};

info!(slot = slot.as_u64(), "Received unsigned block");
if proposer_index != Some(block_proposer) {
return Err(BlockError::Recoverable(
"Proposer index does not match block proposer. Beacon chain re-orged".to_string(),
));
}

self_ref
.sign_and_publish_block(
Expand Down Expand Up @@ -517,70 +562,6 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> BlockService<S, T> {
}
Ok::<_, BlockError>(())
}

async fn get_validator_block(
beacon_node: &BeaconNodeHttpClient,
slot: Slot,
randao_reveal_ref: &SignatureBytes,
graffiti: Option<Graffiti>,
proposer_index: Option<u64>,
builder_boost_factor: Option<u64>,
) -> Result<UnsignedBlock<S::E>, BlockError> {
let block_response = match beacon_node
.get_validator_blocks_v3_ssz::<S::E>(
slot,
randao_reveal_ref,
graffiti.as_ref(),
builder_boost_factor,
)
.await
{
Ok((ssz_block_response, _)) => ssz_block_response,
Err(e) => {
warn!(
slot = slot.as_u64(),
error = %e,
"Beacon node does not support SSZ in block production, falling back to JSON"
);

let (json_block_response, _) = beacon_node
.get_validator_blocks_v3::<S::E>(
slot,
randao_reveal_ref,
graffiti.as_ref(),
builder_boost_factor,
)
.await
.map_err(|e| {
BlockError::Recoverable(format!(
"Error from beacon node when producing block: {:?}",
e
))
})?;

// Extract ProduceBlockV3Response (data field of the struct ForkVersionedResponse)
json_block_response.data
}
};

let (block_proposer, unsigned_block) = match block_response {
eth2::types::ProduceBlockV3Response::Full(block) => {
(block.block().proposer_index(), UnsignedBlock::Full(block))
}
eth2::types::ProduceBlockV3Response::Blinded(block) => {
(block.proposer_index(), UnsignedBlock::Blinded(block))
}
};

info!(slot = slot.as_u64(), "Received unsigned block");
if proposer_index != Some(block_proposer) {
return Err(BlockError::Recoverable(
"Proposer index does not match block proposer. Beacon chain re-orged".to_string(),
));
}

Ok::<_, BlockError>(unsigned_block)
}
}

/// Wrapper for values we want to log about a block we signed, for easy extraction from the possible
Expand Down
Loading