mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 10:22:38 +00:00
Merge remote-tracking branch 'origin/unstable' into tree-states
This commit is contained in:
@@ -46,6 +46,9 @@ pub const EXECUTION_PAYLOAD_BLINDED_HEADER: &str = "Eth-Execution-Payload-Blinde
|
||||
pub const EXECUTION_PAYLOAD_VALUE_HEADER: &str = "Eth-Execution-Payload-Value";
|
||||
pub const CONSENSUS_BLOCK_VALUE_HEADER: &str = "Eth-Consensus-Block-Value";
|
||||
|
||||
pub const CONTENT_TYPE_HEADER: &str = "Content-Type";
|
||||
pub const SSZ_CONTENT_TYPE_HEADER: &str = "application/octet-stream";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The `reqwest` client raised an error.
|
||||
@@ -374,25 +377,6 @@ impl BeaconNodeHttpClient {
|
||||
ok_or_error(response).await
|
||||
}
|
||||
|
||||
/// Generic POST function supporting arbitrary responses and timeouts.
|
||||
async fn post_generic_with_ssz_body<T: Into<Body>, U: IntoUrl>(
|
||||
&self,
|
||||
url: U,
|
||||
body: T,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<Response, Error> {
|
||||
let mut builder = self.client.post(url);
|
||||
if let Some(timeout) = timeout {
|
||||
builder = builder.timeout(timeout);
|
||||
}
|
||||
let response = builder
|
||||
.header("Content-Type", "application/octet-stream")
|
||||
.body(body)
|
||||
.send()
|
||||
.await?;
|
||||
ok_or_error(response).await
|
||||
}
|
||||
|
||||
/// Generic POST function supporting arbitrary responses and timeouts.
|
||||
async fn post_generic_with_consensus_version<T: Serialize, U: IntoUrl>(
|
||||
&self,
|
||||
@@ -863,10 +847,11 @@ impl BeaconNodeHttpClient {
|
||||
.push("beacon")
|
||||
.push("blocks");
|
||||
|
||||
self.post_generic_with_ssz_body(
|
||||
self.post_generic_with_consensus_version_and_ssz_body(
|
||||
path,
|
||||
block_contents.as_ssz_bytes(),
|
||||
Some(self.timeouts.proposal),
|
||||
block_contents.signed_block().fork_name_unchecked(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -907,8 +892,13 @@ impl BeaconNodeHttpClient {
|
||||
.push("beacon")
|
||||
.push("blinded_blocks");
|
||||
|
||||
self.post_generic_with_ssz_body(path, block.as_ssz_bytes(), Some(self.timeouts.proposal))
|
||||
.await?;
|
||||
self.post_generic_with_consensus_version_and_ssz_body(
|
||||
path,
|
||||
block.as_ssz_bytes(),
|
||||
Some(self.timeouts.proposal),
|
||||
block.fork_name_unchecked(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1074,8 +1064,18 @@ impl BeaconNodeHttpClient {
|
||||
pub async fn get_blobs<T: EthSpec>(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
indices: Option<&[u64]>,
|
||||
) -> Result<Option<GenericResponse<BlobSidecarList<T>>>, Error> {
|
||||
let path = self.get_blobs_path(block_id)?;
|
||||
let mut path = self.get_blobs_path(block_id)?;
|
||||
if let Some(indices) = indices {
|
||||
let indices_string = indices
|
||||
.iter()
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
path.query_pairs_mut()
|
||||
.append_pair("indices", &indices_string);
|
||||
}
|
||||
let Some(response) = self.get_response(path, |b| b).await.optional()? else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
@@ -483,12 +483,15 @@ impl ValidatorClientHttpClient {
|
||||
}
|
||||
|
||||
/// `PATCH lighthouse/validators/{validator_pubkey}`
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn patch_lighthouse_validators(
|
||||
&self,
|
||||
voting_pubkey: &PublicKeyBytes,
|
||||
enabled: Option<bool>,
|
||||
gas_limit: Option<u64>,
|
||||
builder_proposals: Option<bool>,
|
||||
builder_boost_factor: Option<u64>,
|
||||
prefer_builder_proposals: Option<bool>,
|
||||
graffiti: Option<GraffitiString>,
|
||||
) -> Result<(), Error> {
|
||||
let mut path = self.server.full.clone();
|
||||
@@ -505,6 +508,8 @@ impl ValidatorClientHttpClient {
|
||||
enabled,
|
||||
gas_limit,
|
||||
builder_proposals,
|
||||
builder_boost_factor,
|
||||
prefer_builder_proposals,
|
||||
graffiti,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -32,6 +32,12 @@ pub struct ValidatorRequest {
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_proposals: Option<bool>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prefer_builder_proposals: Option<bool>,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub deposit_gwei: u64,
|
||||
}
|
||||
@@ -86,6 +92,12 @@ pub struct ValidatorPatchRequest {
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub graffiti: Option<GraffitiString>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prefer_builder_proposals: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -105,6 +117,12 @@ pub struct KeystoreValidatorsPostRequest {
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_proposals: Option<bool>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prefer_builder_proposals: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
@@ -135,6 +153,12 @@ pub struct Web3SignerValidatorRequest {
|
||||
pub client_identity_path: Option<PathBuf>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub client_identity_password: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prefer_builder_proposals: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
|
||||
@@ -15,6 +15,7 @@ use ssz_derive::{Decode, Encode};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::{from_utf8, FromStr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use types::beacon_block_body::KzgCommitments;
|
||||
pub use types::*;
|
||||
@@ -1480,15 +1481,15 @@ mod tests {
|
||||
type E = MainnetEthSpec;
|
||||
let spec = ForkName::Capella.make_genesis_spec(E::default_spec());
|
||||
|
||||
let block: PublishBlockRequest<E> = SignedBeaconBlock::from_block(
|
||||
let block: PublishBlockRequest<E> = Arc::new(SignedBeaconBlock::from_block(
|
||||
BeaconBlock::<E>::Capella(BeaconBlockCapella::empty(&spec)),
|
||||
Signature::empty(),
|
||||
)
|
||||
))
|
||||
.try_into()
|
||||
.expect("should convert into signed block contents");
|
||||
|
||||
let decoded: PublishBlockRequest<E> =
|
||||
PublishBlockRequest::from_ssz_bytes(&block.as_ssz_bytes(), &spec)
|
||||
PublishBlockRequest::from_ssz_bytes(&block.as_ssz_bytes(), ForkName::Capella)
|
||||
.expect("should decode Block");
|
||||
assert!(matches!(decoded, PublishBlockRequest::Block(_)));
|
||||
}
|
||||
@@ -1504,11 +1505,14 @@ mod tests {
|
||||
);
|
||||
let blobs = BlobsList::<E>::from(vec![Blob::<E>::default()]);
|
||||
let kzg_proofs = KzgProofs::<E>::from(vec![KzgProof::empty()]);
|
||||
let signed_block_contents = PublishBlockRequest::new(block, Some((kzg_proofs, blobs)));
|
||||
let signed_block_contents =
|
||||
PublishBlockRequest::new(Arc::new(block), Some((kzg_proofs, blobs)));
|
||||
|
||||
let decoded: PublishBlockRequest<E> =
|
||||
PublishBlockRequest::from_ssz_bytes(&signed_block_contents.as_ssz_bytes(), &spec)
|
||||
.expect("should decode BlockAndBlobSidecars");
|
||||
let decoded: PublishBlockRequest<E> = PublishBlockRequest::from_ssz_bytes(
|
||||
&signed_block_contents.as_ssz_bytes(),
|
||||
ForkName::Deneb,
|
||||
)
|
||||
.expect("should decode BlockAndBlobSidecars");
|
||||
assert!(matches!(decoded, PublishBlockRequest::BlockContents(_)));
|
||||
}
|
||||
}
|
||||
@@ -1643,7 +1647,7 @@ impl<T: EthSpec> FullBlockContents<T> {
|
||||
) -> PublishBlockRequest<T> {
|
||||
let (block, maybe_blobs) = self.deconstruct();
|
||||
let signed_block = block.sign(secret_key, fork, genesis_validators_root, spec);
|
||||
PublishBlockRequest::new(signed_block, maybe_blobs)
|
||||
PublishBlockRequest::new(Arc::new(signed_block), maybe_blobs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1674,7 +1678,10 @@ impl<T: EthSpec> Into<BeaconBlock<T>> for FullBlockContents<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type SignedBlockContentsTuple<T> = (SignedBeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
|
||||
pub type SignedBlockContentsTuple<T> = (
|
||||
Arc<SignedBeaconBlock<T>>,
|
||||
Option<(KzgProofs<T>, BlobsList<T>)>,
|
||||
);
|
||||
|
||||
fn parse_required_header<T>(
|
||||
headers: &HeaderMap,
|
||||
@@ -1729,12 +1736,12 @@ impl TryFrom<&HeaderMap> for ProduceBlockV3Metadata {
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub enum PublishBlockRequest<T: EthSpec> {
|
||||
BlockContents(SignedBlockContents<T>),
|
||||
Block(SignedBeaconBlock<T>),
|
||||
Block(Arc<SignedBeaconBlock<T>>),
|
||||
}
|
||||
|
||||
impl<T: EthSpec> PublishBlockRequest<T> {
|
||||
pub fn new(
|
||||
block: SignedBeaconBlock<T>,
|
||||
block: Arc<SignedBeaconBlock<T>>,
|
||||
blob_items: Option<(KzgProofs<T>, BlobsList<T>)>,
|
||||
) -> Self {
|
||||
match blob_items {
|
||||
@@ -1747,23 +1754,12 @@ impl<T: EthSpec> PublishBlockRequest<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// SSZ decode with fork variant determined by slot.
|
||||
pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result<Self, ssz::DecodeError> {
|
||||
let slot_len = <Slot as Decode>::ssz_fixed_len();
|
||||
let slot_bytes = bytes
|
||||
.get(0..slot_len)
|
||||
.ok_or(DecodeError::InvalidByteLength {
|
||||
len: bytes.len(),
|
||||
expected: slot_len,
|
||||
})?;
|
||||
|
||||
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
||||
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
||||
|
||||
match fork_at_slot {
|
||||
/// SSZ decode with fork variant determined by `fork_name`.
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, ssz::DecodeError> {
|
||||
match fork_name {
|
||||
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||
SignedBeaconBlock::from_ssz_bytes(bytes, spec)
|
||||
.map(|block| PublishBlockRequest::Block(block))
|
||||
SignedBeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
|
||||
.map(|block| PublishBlockRequest::Block(Arc::new(block)))
|
||||
}
|
||||
ForkName::Deneb => {
|
||||
let mut builder = ssz::SszDecoderBuilder::new(bytes);
|
||||
@@ -1772,16 +1768,20 @@ impl<T: EthSpec> PublishBlockRequest<T> {
|
||||
builder.register_type::<BlobsList<T>>()?;
|
||||
|
||||
let mut decoder = builder.build()?;
|
||||
let block = decoder
|
||||
.decode_next_with(|bytes| SignedBeaconBlock::from_ssz_bytes(bytes, spec))?;
|
||||
let block = decoder.decode_next_with(|bytes| {
|
||||
SignedBeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
|
||||
})?;
|
||||
let kzg_proofs = decoder.decode_next()?;
|
||||
let blobs = decoder.decode_next()?;
|
||||
Ok(PublishBlockRequest::new(block, Some((kzg_proofs, blobs))))
|
||||
Ok(PublishBlockRequest::new(
|
||||
Arc::new(block),
|
||||
Some((kzg_proofs, blobs)),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signed_block(&self) -> &SignedBeaconBlock<T> {
|
||||
pub fn signed_block(&self) -> &Arc<SignedBeaconBlock<T>> {
|
||||
match self {
|
||||
PublishBlockRequest::BlockContents(block_and_sidecars) => {
|
||||
&block_and_sidecars.signed_block
|
||||
@@ -1811,14 +1811,14 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
|
||||
let signed_block = blinded_block
|
||||
.try_into_full_block(None)
|
||||
.ok_or("Failed to build full block with payload".to_string())?;
|
||||
Ok(PublishBlockRequest::new(signed_block, None))
|
||||
Ok(PublishBlockRequest::new(Arc::new(signed_block), None))
|
||||
}
|
||||
// This variant implies a pre-deneb block
|
||||
Some(FullPayloadContents::Payload(execution_payload)) => {
|
||||
let signed_block = blinded_block
|
||||
.try_into_full_block(Some(execution_payload))
|
||||
.ok_or("Failed to build full block with payload".to_string())?;
|
||||
Ok(PublishBlockRequest::new(signed_block, None))
|
||||
Ok(PublishBlockRequest::new(Arc::new(signed_block), None))
|
||||
}
|
||||
// This variant implies a post-deneb block
|
||||
Some(FullPayloadContents::PayloadAndBlobs(payload_and_blobs)) => {
|
||||
@@ -1827,7 +1827,7 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
|
||||
.ok_or("Failed to build full block with payload".to_string())?;
|
||||
|
||||
Ok(PublishBlockRequest::new(
|
||||
signed_block,
|
||||
Arc::new(signed_block),
|
||||
Some((
|
||||
payload_and_blobs.blobs_bundle.proofs,
|
||||
payload_and_blobs.blobs_bundle.blobs,
|
||||
@@ -1837,10 +1837,10 @@ pub fn into_full_block_and_blobs<T: EthSpec>(
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> TryFrom<SignedBeaconBlock<T>> for PublishBlockRequest<T> {
|
||||
impl<T: EthSpec> TryFrom<Arc<SignedBeaconBlock<T>>> for PublishBlockRequest<T> {
|
||||
type Error = &'static str;
|
||||
fn try_from(block: SignedBeaconBlock<T>) -> Result<Self, Self::Error> {
|
||||
match block {
|
||||
fn try_from(block: Arc<SignedBeaconBlock<T>>) -> Result<Self, Self::Error> {
|
||||
match *block {
|
||||
SignedBeaconBlock::Base(_)
|
||||
| SignedBeaconBlock::Altair(_)
|
||||
| SignedBeaconBlock::Merge(_)
|
||||
@@ -1861,7 +1861,7 @@ impl<T: EthSpec> From<SignedBlockContentsTuple<T>> for PublishBlockRequest<T> {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode)]
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
pub struct SignedBlockContents<T: EthSpec> {
|
||||
pub signed_block: SignedBeaconBlock<T>,
|
||||
pub signed_block: Arc<SignedBeaconBlock<T>>,
|
||||
pub kzg_proofs: KzgProofs<T>,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")]
|
||||
pub blobs: BlobsList<T>,
|
||||
|
||||
Reference in New Issue
Block a user