Skip to content

Commit 813d791

Browse files
committed
gloas block production
1 parent ea95246 commit 813d791

File tree

9 files changed

+1003
-39
lines changed

9 files changed

+1003
-39
lines changed

common/eth2/src/lib.rs

Lines changed: 335 additions & 16 deletions
Large diffs are not rendered by default.

common/eth2/src/types.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,41 @@ pub struct ProduceBlockV3Metadata {
17521752
pub consensus_block_value: Uint256,
17531753
}
17541754

1755+
/// Metadata about a `ExecutionPayloadEnvelope` response which is returned in the headers.
1756+
#[derive(Debug, Deserialize, Serialize)]
1757+
pub struct ExecutionPayloadEnvelopeMetadata {
1758+
// The consensus version is serialized & deserialized by `ForkVersionedResponse`.
1759+
#[serde(
1760+
skip_serializing,
1761+
skip_deserializing,
1762+
default = "dummy_consensus_version"
1763+
)]
1764+
pub consensus_version: ForkName,
1765+
}
1766+
1767+
/// Response from the `/eth/v4/validator/blocks/{slot}` endpoint.
1768+
///
1769+
/// V4 is specific to post-Gloas forks and always returns a BeaconBlock directly.
1770+
/// No blinded/unblinded concept exists in Gloas.
1771+
pub type ProduceBlockV4Response<E> = BeaconBlock<E>;
1772+
1773+
pub type JsonProduceBlockV4Response<E> =
1774+
ForkVersionedResponse<ProduceBlockV4Response<E>, ProduceBlockV4Metadata>;
1775+
1776+
/// Metadata about a `ProduceBlockV4Response` which is returned in the body & headers.
1777+
#[derive(Debug, Deserialize, Serialize)]
1778+
pub struct ProduceBlockV4Metadata {
1779+
// The consensus version is serialized & deserialized by `ForkVersionedResponse`.
1780+
#[serde(
1781+
skip_serializing,
1782+
skip_deserializing,
1783+
default = "dummy_consensus_version"
1784+
)]
1785+
pub consensus_version: ForkName,
1786+
#[serde(with = "serde_utils::u256_dec")]
1787+
pub consensus_block_value: Uint256,
1788+
}
1789+
17551790
impl<E: EthSpec> FullBlockContents<E> {
17561791
pub fn new(block: BeaconBlock<E>, blob_data: Option<(KzgProofs<E>, BlobsList<E>)>) -> Self {
17571792
match blob_data {
@@ -1908,6 +1943,40 @@ impl TryFrom<&HeaderMap> for ProduceBlockV3Metadata {
19081943
}
19091944
}
19101945

1946+
impl TryFrom<&HeaderMap> for ExecutionPayloadEnvelopeMetadata {
1947+
type Error = String;
1948+
1949+
fn try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
1950+
let consensus_version = parse_required_header(headers, CONSENSUS_VERSION_HEADER, |s| {
1951+
s.parse::<ForkName>()
1952+
.map_err(|e| format!("invalid {CONSENSUS_VERSION_HEADER}: {e:?}"))
1953+
})?;
1954+
1955+
Ok(ExecutionPayloadEnvelopeMetadata { consensus_version })
1956+
}
1957+
}
1958+
1959+
impl TryFrom<&HeaderMap> for ProduceBlockV4Metadata {
1960+
type Error = String;
1961+
1962+
fn try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
1963+
let consensus_version = parse_required_header(headers, CONSENSUS_VERSION_HEADER, |s| {
1964+
s.parse::<ForkName>()
1965+
.map_err(|e| format!("invalid {CONSENSUS_VERSION_HEADER}: {e:?}"))
1966+
})?;
1967+
let consensus_block_value =
1968+
parse_required_header(headers, CONSENSUS_BLOCK_VALUE_HEADER, |s| {
1969+
Uint256::from_str_radix(s, 10)
1970+
.map_err(|e| format!("invalid {CONSENSUS_BLOCK_VALUE_HEADER}: {e:?}"))
1971+
})?;
1972+
1973+
Ok(ProduceBlockV4Metadata {
1974+
consensus_version,
1975+
consensus_block_value,
1976+
})
1977+
}
1978+
}
1979+
19111980
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBlockContents`].
19121981
#[derive(Clone, Debug, PartialEq, Encode, Serialize)]
19131982
#[serde(untagged)]

validator_client/beacon_node_fallback/src/lib.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
55
pub mod beacon_node_health;
66
use beacon_node_health::{
7-
BeaconNodeHealth, BeaconNodeSyncDistanceTiers, ExecutionEngineHealth, IsOptimistic,
8-
SyncDistanceTier, check_node_health,
7+
check_node_health, BeaconNodeHealth, BeaconNodeSyncDistanceTiers, ExecutionEngineHealth,
8+
IsOptimistic, SyncDistanceTier,
99
};
1010
use clap::ValueEnum;
1111
use eth2::{BeaconNodeHttpClient, Timeouts};
1212
use futures::future;
1313
use sensitive_url::SensitiveUrl;
14-
use serde::{Deserialize, Serialize, Serializer, ser::SerializeStruct};
14+
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
1515
use slot_clock::SlotClock;
1616
use std::cmp::Ordering;
1717
use std::fmt;
@@ -25,7 +25,7 @@ use task_executor::TaskExecutor;
2525
use tokio::{sync::RwLock, time::sleep};
2626
use tracing::{debug, error, warn};
2727
use types::{ChainSpec, Config as ConfigSpec, EthSpec, Slot};
28-
use validator_metrics::{ENDPOINT_ERRORS, ENDPOINT_REQUESTS, inc_counter_vec};
28+
use validator_metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_REQUESTS};
2929

3030
/// Message emitted when the VC detects the BN is using a different spec.
3131
const UPDATE_REQUIRED_LOG_HINT: &str = "this VC or the remote BN may need updating";
@@ -790,12 +790,10 @@ mod tests {
790790
let mut variants = ApiTopic::VARIANTS.to_vec();
791791
variants.retain(|s| *s != "none");
792792
assert_eq!(all.len(), variants.len());
793-
assert!(
794-
variants
795-
.iter()
796-
.map(|topic| ApiTopic::from_str(topic, true).unwrap())
797-
.eq(all.into_iter())
798-
);
793+
assert!(variants
794+
.iter()
795+
.map(|topic| ApiTopic::from_str(topic, true).unwrap())
796+
.eq(all.into_iter()));
799797
}
800798

801799
#[tokio::test]
@@ -1003,6 +1001,7 @@ mod tests {
10031001
spec.clone(),
10041002
);
10051003

1004+
// TODO(EIP-7732): discuss whether we should replace this with a new `mock_post_beacon__blocks_v2_ssz` for post-gloas blocks since no blinded blocks anymore.
10061005
mock_beacon_node_1.mock_post_beacon_blinded_blocks_v2_ssz(Duration::from_secs(0));
10071006
mock_beacon_node_2.mock_post_beacon_blinded_blocks_v2_ssz(Duration::from_secs(0));
10081007

validator_client/lighthouse_validator_store/src/lib.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ use task_executor::TaskExecutor;
1818
use tracing::{error, info, warn};
1919
use types::{
2020
AbstractExecPayload, Address, AggregateAndProof, Attestation, BeaconBlock, BlindedPayload,
21-
ChainSpec, ContributionAndProof, Domain, Epoch, EthSpec, Fork, Graffiti, Hash256,
22-
PublicKeyBytes, SelectionProof, Signature, SignedAggregateAndProof, SignedBeaconBlock,
23-
SignedContributionAndProof, SignedRoot, SignedValidatorRegistrationData, SignedVoluntaryExit,
24-
Slot, SyncAggregatorSelectionData, SyncCommitteeContribution, SyncCommitteeMessage,
25-
SyncSelectionProof, SyncSubnetId, ValidatorRegistrationData, VoluntaryExit,
26-
graffiti::GraffitiString,
21+
ChainSpec, ContributionAndProof, Domain, Epoch, EthSpec, ExecutionPayloadEnvelope, Fork,
22+
Graffiti, Hash256, PublicKeyBytes, SelectionProof, Signature, SignedAggregateAndProof,
23+
SignedBeaconBlock, SignedContributionAndProof, SignedExecutionPayloadEnvelope, SignedRoot,
24+
SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, SyncAggregatorSelectionData,
25+
SyncCommitteeContribution, SyncCommitteeMessage, SyncSelectionProof, SyncSubnetId,
26+
ValidatorRegistrationData, VoluntaryExit, graffiti::GraffitiString,
2727
};
2828
use validator_store::{
2929
DoppelgangerStatus, Error as ValidatorStoreError, ProposalData, SignedBlock, UnsignedBlock,
@@ -745,6 +745,45 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore for LighthouseValidatorS
745745
}
746746
}
747747

748+
async fn sign_block_gloas(
749+
&self,
750+
validator_pubkey: PublicKeyBytes,
751+
block: &BeaconBlock<E>,
752+
current_slot: Slot,
753+
) -> Result<Arc<SignedBeaconBlock<E>>, Error> {
754+
let beacon_block = block.clone();
755+
self.sign_abstract_block(validator_pubkey, beacon_block, current_slot)
756+
.await
757+
.map(|signed_block| Arc::new(signed_block))
758+
}
759+
760+
async fn sign_execution_payload_envelope(
761+
&self,
762+
validator_pubkey: PublicKeyBytes,
763+
envelope: &ExecutionPayloadEnvelope<E>,
764+
current_slot: Slot,
765+
) -> Result<SignedExecutionPayloadEnvelope<E>, Error> {
766+
let signing_epoch = current_slot.epoch(E::slots_per_epoch());
767+
let signing_context = self.signing_context(Domain::BeaconBuilder, signing_epoch);
768+
769+
let signing_method = self.doppelganger_checked_signing_method(validator_pubkey)?;
770+
771+
let signature = signing_method
772+
.get_signature::<E, BlindedPayload<E>>(
773+
SignableMessage::ExecutionPayloadEnvelope(envelope),
774+
signing_context,
775+
&self.spec,
776+
&self.task_executor,
777+
)
778+
.await
779+
.map_err(Error::SpecificError)?;
780+
781+
let signed_envelope =
782+
SignedExecutionPayloadEnvelope::from_envelope(envelope.clone(), signature);
783+
784+
Ok(signed_envelope)
785+
}
786+
748787
async fn sign_attestation(
749788
&self,
750789
validator_pubkey: PublicKeyBytes,

validator_client/signing_method/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub enum SignableMessage<'a, E: EthSpec, Payload: AbstractExecPayload<E> = FullP
4747
SignedContributionAndProof(&'a ContributionAndProof<E>),
4848
ValidatorRegistration(&'a ValidatorRegistrationData),
4949
VoluntaryExit(&'a VoluntaryExit),
50+
ExecutionPayloadEnvelope(&'a ExecutionPayloadEnvelope<E>),
5051
}
5152

5253
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignableMessage<'_, E, Payload> {
@@ -68,6 +69,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignableMessage<'_, E, Payload
6869
SignableMessage::SignedContributionAndProof(c) => c.signing_root(domain),
6970
SignableMessage::ValidatorRegistration(v) => v.signing_root(domain),
7071
SignableMessage::VoluntaryExit(exit) => exit.signing_root(domain),
72+
SignableMessage::ExecutionPayloadEnvelope(envelope) => envelope.signing_root(domain),
7173
}
7274
}
7375
}
@@ -228,6 +230,9 @@ impl SigningMethod {
228230
Web3SignerObject::ValidatorRegistration(v)
229231
}
230232
SignableMessage::VoluntaryExit(e) => Web3SignerObject::VoluntaryExit(e),
233+
SignableMessage::ExecutionPayloadEnvelope(envelope) => {
234+
Web3SignerObject::ExecutionPayloadEnvelope(envelope)
235+
}
231236
};
232237

233238
// Determine the Web3Signer message type.

validator_client/signing_method/src/web3signer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub enum MessageType {
1818
SyncCommitteeSelectionProof,
1919
SyncCommitteeContributionAndProof,
2020
ValidatorRegistration,
21+
ExecutionPayloadEnvelope,
2122
}
2223

2324
#[derive(Debug, PartialEq, Copy, Clone, Serialize)]
@@ -74,6 +75,7 @@ pub enum Web3SignerObject<'a, E: EthSpec, Payload: AbstractExecPayload<E>> {
7475
SyncAggregatorSelectionData(&'a SyncAggregatorSelectionData),
7576
ContributionAndProof(&'a ContributionAndProof<E>),
7677
ValidatorRegistration(&'a ValidatorRegistrationData),
78+
ExecutionPayloadEnvelope(&'a ExecutionPayloadEnvelope<E>),
7779
}
7880

7981
impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> Web3SignerObject<'a, E, Payload> {
@@ -139,6 +141,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> Web3SignerObject<'a, E, Pa
139141
MessageType::SyncCommitteeContributionAndProof
140142
}
141143
Web3SignerObject::ValidatorRegistration(_) => MessageType::ValidatorRegistration,
144+
Web3SignerObject::ExecutionPayloadEnvelope(_) => MessageType::ExecutionPayloadEnvelope,
142145
}
143146
}
144147
}

validator_client/validator_metrics/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ pub const BEACON_BLOCK: &str = "beacon_block";
99
pub const BEACON_BLOCK_HTTP_GET: &str = "beacon_block_http_get";
1010
pub const BEACON_BLOCK_HTTP_POST: &str = "beacon_block_http_post";
1111
pub const BLINDED_BEACON_BLOCK_HTTP_POST: &str = "blinded_beacon_block_http_post";
12+
pub const EXECUTION_PAYLOAD_ENVELOPE_HTTP_GET: &str = "execution_payload_envelope_http_get";
13+
pub const EXECUTION_PAYLOAD_ENVELOPE_HTTP_POST: &str = "execution_payload_envelope_http_post";
14+
pub const EXECUTION_PAYLOAD_ENVELOPE_SIGN: &str = "execution_payload_envelope_sign";
15+
pub const EXECUTION_PAYLOAD_ENVELOPE: &str = "execution_payload_envelope";
1216
pub const ATTESTATIONS: &str = "attestations";
1317
pub const ATTESTATIONS_HTTP_GET: &str = "attestations_http_get";
1418
pub const ATTESTATIONS_HTTP_POST: &str = "attestations_http_post";
@@ -237,6 +241,12 @@ pub static BLOCK_SIGNING_TIMES: LazyLock<Result<Histogram>> = LazyLock::new(|| {
237241
"Duration to obtain a signature for a block",
238242
)
239243
});
244+
pub static ENVELOPE_SIGNING_TIMES: LazyLock<Result<Histogram>> = LazyLock::new(|| {
245+
try_create_histogram(
246+
"vc_envelope_signing_times_seconds",
247+
"Duration to obtain a signature for an execution payload envelope",
248+
)
249+
});
240250

241251
pub static ATTESTATION_DUTY: LazyLock<Result<IntGaugeVec>> = LazyLock::new(|| {
242252
try_create_int_gauge_vec(

0 commit comments

Comments
 (0)