diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index ba0a37736..86829e5f6 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -7,9 +7,10 @@ use serde::{Deserialize, Serialize}; use strum::IntoStaticStr; pub use types::{ Address, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadHeader, FixedVector, - Hash256, Uint256, VariableList, + Hash256, Uint256, VariableList, kzg_proof::KzgProof, kzg_commitment::KzgCommitment, blob::Blob, }; + pub mod auth; pub mod http; pub mod json_structures; diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 0f848a771..e37aef72d 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -3,13 +3,14 @@ use super::*; use crate::auth::Auth; use crate::json_structures::*; +use eth2::lighthouse::Eth1Block; use reqwest::header::CONTENT_TYPE; use sensitive_url::SensitiveUrl; use serde::de::DeserializeOwned; use serde_json::json; use std::time::Duration; -use types::EthSpec; +use types::{EthSpec, FullPayload, execution_payload::BlobsBundle}; pub use deposit_log::{DepositLog, Log}; pub use reqwest::Client; @@ -34,6 +35,9 @@ pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8); pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1"; pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2); +pub const ENGINE_GET_BLOBS_BUNDLE_V1: &str = "engine_getBlobsBundleV1"; +pub const ENGINE_GET_BLOBS_BUNDLE_TIMEOUT: Duration = Duration::from_secs(2); + pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1"; pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8); @@ -664,6 +668,32 @@ impl HttpJsonRpc { Ok(response.into()) } + pub async fn get_blobs_bundle_v1( + &self, + payload_id: PayloadId, + ) -> Result, Error> { + let params = json!([JsonPayloadIdRequest::from(payload_id)]); + + let response: JsonBlobBundlesV1 = self + .rpc_request(ENGINE_GET_BLOBS_BUNDLE_V1, params, ENGINE_GET_BLOBS_BUNDLE_TIMEOUT) + .await?; + + Ok(response.into()) + } + + pub async fn get_full_payload( + &self, + payload_id: PayloadId, + ) -> Result, Error> { + let payload = self.get_payload_v1(payload_id).await; + let blobs = self.get_blobs_bundle_v1(payload_id).await; + + Ok(FullPayload{ + execution_payload: payload?, + blobs_bundle: blobs?.into(), + }) + } + pub async fn forkchoice_updated_v1( &self, forkchoice_state: ForkChoiceState, diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index 31aa79f05..4907acee3 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -1,6 +1,6 @@ use super::*; use serde::{Deserialize, Serialize}; -use types::{EthSpec, ExecutionBlockHash, FixedVector, Transaction, Unsigned, VariableList}; +use types::{EthSpec, ExecutionBlockHash, FixedVector, Transaction, Unsigned, VariableList, execution_payload::BlobsBundle}; #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -269,6 +269,54 @@ impl From for PayloadAttributes { } } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(bound = "T: EthSpec", rename_all = "camelCase")] +pub struct JsonBlobBundlesV1 { + pub block_hash: Hash256, + pub kzgs: Vec, + pub blobs: Vec>, + pub aggregated_proof: KzgProof, +} + +impl From> for JsonBlobBundlesV1 { + fn from(p: BlobsBundle) -> Self { + // Use this verbose deconstruction pattern to ensure no field is left unused. + let BlobsBundle { + block_hash, + aggregated_proof, + blobs, + kzgs, + } = p; + + Self { + block_hash, + aggregated_proof, + blobs, + kzgs, + } + } +} + +impl From> for BlobsBundle { + fn from(j: JsonBlobBundlesV1) -> Self { + // Use this verbose deconstruction pattern to ensure no field is left unused. + let JsonBlobBundlesV1 { + block_hash, + aggregated_proof, + blobs, + kzgs, + } = j; + + Self { + block_hash, + aggregated_proof, + blobs, + kzgs, + } + } +} + + #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct JsonForkChoiceStateV1 { diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 3bdca82ad..5d1190f81 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -835,10 +835,10 @@ impl ExecutionLayer { engine .api - .get_payload_v1::(payload_id) + .get_full_payload::(payload_id) .await .map(|full_payload| { - if full_payload.fee_recipient != suggested_fee_recipient { + if full_payload.execution_payload.fee_recipient != suggested_fee_recipient { error!( self.log(), "Inconsistent fee recipient"; @@ -847,11 +847,11 @@ impl ExecutionLayer { indicate that fees are being diverted to another address. Please \ ensure that the value of suggested_fee_recipient is set correctly and \ that the Execution Engine is trusted.", - "fee_recipient" => ?full_payload.fee_recipient, + "fee_recipient" => ?full_payload.execution_payload.fee_recipient, "suggested_fee_recipient" => ?suggested_fee_recipient, ); } - if f(self, &full_payload).is_some() { + if f(self, &full_payload.execution_payload).is_some() { warn!( self.log(), "Duplicate payload cached, this might indicate redundant proposal \ diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index eaa99718c..d4f49d377 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -232,7 +232,7 @@ impl From>> deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload, blobs_bundle }, } = body; ( @@ -272,7 +272,7 @@ for ( deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload, blobs_bundle }, blob_kzg_commitments, } = body; @@ -324,7 +324,7 @@ impl BeaconBlockBodyMerge> { deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload, blobs_bundle }, } = self; BeaconBlockBodyMerge { @@ -356,7 +356,7 @@ impl BeaconBlockBodyEip4844> { deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload, blobs_bundle }, blob_kzg_commitments, } = self; diff --git a/consensus/types/src/blob.rs b/consensus/types/src/blob.rs index 8ea3468ff..efe243859 100644 --- a/consensus/types/src/blob.rs +++ b/consensus/types/src/blob.rs @@ -1,9 +1,23 @@ use ssz_types::VariableList; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use ssz::{Decode, DecodeError, Encode}; +use crate::test_utils::RngCore; use crate::bls_field_element::BlsFieldElement; -use crate::EthSpec; +use crate::{EthSpec, Uint256}; +use crate::test_utils::TestRandom; #[derive(Default, Debug, PartialEq, Hash, Clone, Serialize, Deserialize)] #[serde(transparent)] -pub struct Blob(pub VariableList); \ No newline at end of file +pub struct Blob(pub VariableList); + +impl TestRandom for Blob { + fn random_for_test(rng: &mut impl RngCore) -> Self { + let mut res = Blob(VariableList::empty()); + for i in 0..4096 { + let slice = ethereum_types::U256([rng.next_u64(), rng.next_u64(), rng.next_u64(), rng.next_u64()]); + let elem =BlsFieldElement(slice); + res.0.push(elem); + } + res + } +} \ No newline at end of file diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 412e5a8df..9d6c42c91 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -1,4 +1,4 @@ -use crate::{test_utils::TestRandom, *}; +use crate::{test_utils::TestRandom, test_utils::RngCore, *, kzg_commitment::KzgCommitment, kzg_proof::KzgProof, blob::Blob}; use derivative::Derivative; use serde_derive::{Deserialize, Serialize}; use ssz::Encode; @@ -43,6 +43,24 @@ pub struct ExecutionPayload { pub transactions: Transactions, } +#[derive( + Default, Debug, Clone, Serialize, Deserialize, Derivative, +)] +#[serde(bound = "T: EthSpec")] +pub struct BlobsBundle { + pub block_hash: Hash256, + pub kzgs: Vec, + pub blobs: Vec>, + pub aggregated_proof: KzgProof, +} + + +impl TestRandom for BlobsBundle { + fn random_for_test(rng: &mut impl RngCore) -> Self { + todo!() + } +} + impl ExecutionPayload { pub fn empty() -> Self { Self::default() diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index 114ca02ec..134fe3815 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -1,4 +1,4 @@ -use crate::{test_utils::TestRandom, *}; +use crate::{test_utils::TestRandom, test_utils::RngCore, *}; use derivative::Derivative; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -8,6 +8,8 @@ use std::fmt::Debug; use std::hash::Hash; use test_random_derive::TestRandom; use tree_hash::TreeHash; +use execution_payload::BlobsBundle; +use core::hash::Hasher; #[derive(Debug)] pub enum BlockType { @@ -218,16 +220,37 @@ impl Encode for BlindedPayload { } } -#[derive(Default, Debug, Clone, Serialize, Deserialize, TestRandom, Derivative)] -#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[serde(bound = "T: EthSpec")] pub struct FullPayload { pub execution_payload: ExecutionPayload, + pub blobs_bundle: Option>, +} + +impl TestRandom for FullPayload { + fn random_for_test(rng: &mut impl RngCore) -> Self { + todo!() + } +} + +impl PartialEq for FullPayload { + fn eq(&self, other: &FullPayload) -> bool { + todo!() + } +} + +impl Hash for FullPayload { + fn hash(&self, into: &mut H) { + todo!() + } } impl From> for FullPayload { fn from(execution_payload: ExecutionPayload) -> Self { - Self { execution_payload } + Self { + execution_payload, + blobs_bundle: None, + } } } @@ -265,6 +288,7 @@ impl Decode for FullPayload { fn from_ssz_bytes(bytes: &[u8]) -> Result { Ok(FullPayload { execution_payload: Decode::from_ssz_bytes(bytes)?, + blobs_bundle: None, }) } } diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 4ab74ac21..55e0e8afd 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -304,7 +304,7 @@ impl SignedBeaconBlockMerge> { deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload: execution_payload, blobs_bundle: None }, }, }, signature, @@ -357,7 +357,7 @@ impl SignedBeaconBlockEip4844> { deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayload { execution_payload }, + execution_payload: FullPayload { execution_payload: execution_payload, blobs_bundle: None }, blob_kzg_commitments, }, },