Skip to content
Draft
Show file tree
Hide file tree
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
31 changes: 24 additions & 7 deletions eth1_api/src/eth1_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@ use static_assertions::const_assert_eq;
use std_ext::CopyExt;
use thiserror::Error;
use types::{
combined::{ExecutionPayload, ExecutionPayloadParams},
config::Config,
deneb::primitives::VersionedHash,
nonstandard::{Phase, WithBlobsAndMev},
phase0::primitives::{ExecutionBlockHash, ExecutionBlockNumber},
preset::Preset,
redacting_url::RedactingUrl,
combined::{ExecutionPayload, ExecutionPayloadParams}, config::Config, deneb::primitives::VersionedHash,eip7805::{InclusionList, InclusionListTransactions}, nonstandard::{Phase, WithBlobsAndMev}, phase0::primitives::{ExecutionBlockHash, ExecutionBlockNumber}, preset::Preset, redacting_url::RedactingUrl
};
use web3::{
api::{Eth, Namespace as _},
Expand All @@ -49,6 +43,7 @@ const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
const ENGINE_GET_BLOBS_TIMEOUT: Duration = Duration::from_secs(1);
const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(1);
const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8);
pub const ENGINE_GET_INCLUSION_LIST_TIMEOUT: Duration = Duration::from_secs(4);

pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1";
pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2";
Expand All @@ -63,6 +58,8 @@ pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1";
pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2";
pub const ENGINE_NEW_PAYLOAD_V3: &str = "engine_newPayloadV3";
pub const ENGINE_NEW_PAYLOAD_V4: &str = "engine_newPayloadV4";
pub const ENGINE_GET_INCLUSION_LIST_V1: &str = "engine_getInclusionListV1";


pub const CAPABILITIES: &[&str] = &[
ENGINE_FORKCHOICE_UPDATED_V1,
Expand All @@ -78,6 +75,7 @@ pub const CAPABILITIES: &[&str] = &[
ENGINE_NEW_PAYLOAD_V2,
ENGINE_NEW_PAYLOAD_V3,
ENGINE_NEW_PAYLOAD_V4,
ENGINE_GET_INCLUSION_LIST_V1,
];

#[expect(clippy::struct_field_names)]
Expand Down Expand Up @@ -311,6 +309,7 @@ impl Eth1Api {
versioned_hashes,
parent_beacon_block_root,
execution_requests,
inclusion_list,
}),
) => {
let payload_v3 = ExecutionPayloadV3::from(payload);
Expand All @@ -321,6 +320,7 @@ impl Eth1Api {
serde_json::to_value(versioned_hashes)?,
serde_json::to_value(parent_beacon_block_root)?,
serde_json::to_value(raw_execution_requests)?,
serde_json::to_value(inclusion_list)?,
];

self.execute(
Expand Down Expand Up @@ -506,6 +506,23 @@ impl Eth1Api {
}
}

pub async fn get_inclusion_list<P: Preset>(&self,parent_hash: H256) -> Result<WithClientVersions<InclusionListTransactions<P>>> {

let params = vec![serde_json::to_value(parent_hash)?];
self.execute::<EngineGetInclusionListV1Response<P>>(
ENGINE_GET_INCLUSION_LIST_V1,
params,
Some(ENGINE_GET_INCLUSION_LIST_TIMEOUT),
Some(ENGINE_GET_INCLUSION_LIST_V1),
)
.await
.map(|with_client_info| {
with_client_info.map(|response_struct| response_struct.transactions)
})

}


async fn execute<T: DeserializeOwned + Send>(
&self,
method: &str,
Expand Down
12 changes: 12 additions & 0 deletions eth1_api/src/eth1_execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,18 @@ impl<P: Preset> ExecutionEngine<P> for Eth1ExecutionEngine<P> {
}
}

fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<types::eip7805::InclusionListTransactions<P>>>>,
) -> Result<()> {
ExecutionServiceMessage::GetInclusionList {
parent_hash,
sender,
}
.send(&self.execution_service_tx);
}

fn stop(&self) {
ExecutionServiceMessage::Stop.send(&self.execution_service_tx);
}
Expand Down
26 changes: 26 additions & 0 deletions eth1_api/src/execution_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use types::{
combined::{ExecutionPayload, ExecutionPayloadParams},
nonstandard::Phase,
phase0::primitives::{ExecutionBlockHash, H256},
eip7805::InclusionListTransactions,
preset::Preset,
};

Expand Down Expand Up @@ -139,6 +140,22 @@ impl<P: Preset, W: Wait> ExecutionService<P, W> {
}
}
}
ExecutionServiceMessage::GetInclusionList { parent_hash, sender } => {
let response = self.get_inclusion_list(parent_hash).await;

if let Err(error) = response {
warn!("engine_getInclusionList call failed: {error}");
}

if let Some(sender) = sender {
if let Err(message) = sender.send(response) {
warn!(
"sending engine_getInclusionList result \
failed because the receiver was dropped: {message:?}"
);
}
}
}
ExecutionServiceMessage::Stop => {
Eth1ApiToBlobFetcher::Stop.send(&self.blob_fetcher_tx);

Expand Down Expand Up @@ -236,4 +253,13 @@ impl<P: Preset, W: Wait> ExecutionService<P, W> {

Ok(response)
}

async fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
) -> Result<InclusionListTransactions<P>> {
let response = self.api.get_inclusion_list(parent_hash).await?;

Ok(response)
}
}
54 changes: 54 additions & 0 deletions execution_engine/src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use types::{
deneb::containers::BlobIdentifier,
nonstandard::{Phase, TimedPowBlock},
phase0::primitives::{ExecutionBlockHash, H256},
eip7805::InclusionListTransactions,
preset::Preset,
};

Expand Down Expand Up @@ -58,6 +59,13 @@ pub trait ExecutionEngine<P: Preset> {

/// [`get_pow_block`](https://github.com/ethereum/consensus-specs/blob/1bfefe301da592375e2e02f65849a96aadec1936/specs/bellatrix/fork-choice.md#get_pow_block)
fn pow_block(&self, block_hash: ExecutionBlockHash) -> Option<TimedPowBlock>;

/// [`engine_getInclusionListV1`]
fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()>;

fn stop(&self);
}
Expand Down Expand Up @@ -113,6 +121,14 @@ impl<P: Preset, E: ExecutionEngine<P>> ExecutionEngine<P> for &E {
(*self).pow_block(block_hash)
}

fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()> {
(*self).get_inclusion_list(parent_hash, sender)
}

fn stop(&self) {
(*self).stop()
}
Expand Down Expand Up @@ -170,6 +186,14 @@ impl<P: Preset, E: ExecutionEngine<P>> ExecutionEngine<P> for Arc<E> {
self.as_ref().pow_block(block_hash)
}

fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()> {
self.as_ref().get_inclusion_list(parent_hash, sender)
}

fn stop(&self) {
self.as_ref().stop()
}
Expand Down Expand Up @@ -238,6 +262,16 @@ impl<P: Preset, E: ExecutionEngine<P>> ExecutionEngine<P> for Mutex<E> {
.pow_block(block_hash)
}

fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()> {
self.lock()
.expect("execution engine mutex is poisoned")
.get_inclusion_list(parent_hash, sender)
}

fn stop(&self) {
self.lock()
.expect("execution engine mutex is poisoned")
Expand Down Expand Up @@ -289,6 +323,19 @@ impl<P: Preset> ExecutionEngine<P> for NullExecutionEngine {
None
}

fn get_inclusion_list(
&self,
_parent_hash: ExecutionBlockHash,
_sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()> {
// Return empty inclusion list for null engine
if let Some(sender) = _sender {
let empty_list = InclusionListTransactions::default();
let _ = sender.send(Ok(empty_list));
}
Ok(())
}

fn stop(&self) {}
}

Expand Down Expand Up @@ -349,6 +396,13 @@ impl<P: Preset> ExecutionEngine<P> for MockExecutionEngine<P> {
self.pow_blocks.get(&block_hash).copied()
}

fn get_inclusion_list(
&self,
parent_hash: ExecutionBlockHash,
sender: Option<Sender<Result<InclusionListTransactions<P>>>>,
) -> Result<()> {
}

fn stop(&self) {}
}

Expand Down
5 changes: 5 additions & 0 deletions execution_engine/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use types::{
deneb::containers::BlobIdentifier,
nonstandard::Phase,
phase0::primitives::{ExecutionBlockHash, H256},
eip7805::InclusionListTransactions,
preset::Preset,
};

Expand All @@ -35,6 +36,10 @@ pub enum ExecutionServiceMessage<P: Preset> {
params: Option<ExecutionPayloadParams<P>>,
sender: Option<Sender<Result<PayloadStatusV1>>>,
},
GetInclusionList {
parent_hash: ExecutionBlockHash,
sender: Sender<Result<InclusionListTransactions<P>>>,
},
Stop,
}

Expand Down
13 changes: 13 additions & 0 deletions execution_engine/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use types::{
containers::ExecutionPayload as DenebExecutionPayload,
primitives::{Blob, KzgCommitment, KzgProof},
},
eip7805::InclusionListTransactions,
electra::containers::{
ConsolidationRequest, DepositRequest, ExecutionRequests, WithdrawalRequest,
},
Expand All @@ -34,6 +35,7 @@ use types::{
ExecutionAddress, ExecutionBlockHash, ExecutionBlockNumber, Gwei, UnixSeconds,
ValidatorIndex, H256,
},
eip7805::InclusionListTransactions,
preset::Preset,
};

Expand Down Expand Up @@ -573,6 +575,15 @@ impl<P: Preset> From<EngineGetPayloadV4Response<P>> for WithBlobsAndMev<Executio
}
}

#[derive(Deserialize)]
#[serde(bound = "", rename_all = "camelCase")]
pub struct EngineGetInclusionListV1Response<P: Preset> {
pub transactions: InclusionListTransactions<P>,
}




#[derive(Clone, Serialize)]
#[serde(untagged, bound = "")]
pub enum PayloadAttributes<P: Preset> {
Expand Down Expand Up @@ -930,6 +941,8 @@ pub struct BlobAndProofV1<P: Preset> {
pub proof: KzgProof,
}



#[cfg(test)]
mod tests {
use anyhow::Result;
Expand Down
8 changes: 8 additions & 0 deletions p2p/src/block_sync_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ impl<P: Preset> BlockSyncService<P> {
self.received_blob_sidecars.retain(|_, slot| *slot >= start_of_epoch);
self.received_block_roots.retain(|_, slot| *slot >= start_of_epoch);
}
P2pToSync::GossipInclusionList(signed_inclusion_list, peer_id, gossip_id) => {
debug!(
"received gossip inclusion list (slot: {}, validator_index: {})",
signed_inclusion_list.message.slot,
signed_inclusion_list.message.validator_index
);
self.controller.on_gossip_inclusion_list(signed_inclusion_list, gossip_id);
}
P2pToSync::BlobSidecarRejected(blob_identifier) => {
// In case blob sidecar is not valid (e.g. someone spams fake blob sidecars)
// Grandine should not dismiss newer valid blob sidecars with the same blob identifier
Expand Down
3 changes: 3 additions & 0 deletions p2p/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use types::{
containers::{Checkpoint, ProposerSlashing, SignedVoluntaryExit},
primitives::{Epoch, ForkDigest, Slot, SubnetId, ValidatorIndex, H256},
},
eip7805::{InclusionList,SignedInclusionList},
preset::Preset,
};

Expand Down Expand Up @@ -53,6 +54,7 @@ pub enum P2pToSync<P: Preset> {
FinalizedCheckpoint(Checkpoint),
GossipBlobSidecar(Arc<BlobSidecar<P>>, SubnetId, GossipId),
GossipBlock(Arc<SignedBeaconBlock<P>>, PeerId, GossipId),
GossipInclusionList(Arc<SignedInclusionList<P>>, PeerId, GossipId),
BlobSidecarRejected(BlobIdentifier),
Stop,
}
Expand Down Expand Up @@ -161,6 +163,7 @@ pub enum ValidatorToP2p<P: Preset> {
PublishAggregateAndProof(Arc<SignedAggregateAndProof<P>>),
PublishSyncCommitteeMessage(Box<(SubnetId, SyncCommitteeMessage)>),
PublishContributionAndProof(Box<SignedContributionAndProof<P>>),
PublishInclusionList(Arc<SignedInclusionList<P>>),
}

impl<P: Preset> ValidatorToP2p<P> {
Expand Down
22 changes: 22 additions & 0 deletions p2p/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ use types::{
containers::{ProposerSlashing, SignedVoluntaryExit},
primitives::{Epoch, ForkDigest, NodeId, Slot, SubnetId, H256},
},
eip7805::{InclusionList, SignedInclusionList},
preset::Preset,
traits::{BeaconState as _, SignedBeaconBlock as _},
};
Expand Down Expand Up @@ -415,6 +416,9 @@ impl<P: Preset> Network<P> {
ValidatorToP2p::PublishContributionAndProof(contribution_and_proof) => {
self.publish_contribution_and_proof(contribution_and_proof);
}
ValidatorToP2p::PublishInclusionList(inclusion_list) => {
self.publish_inclusion_list(inclusion_list);
}
}
},

Expand Down Expand Up @@ -699,6 +703,12 @@ impl<P: Preset> Network<P> {
));
}

fn publish_inclusion_list(&self, inclusion_list: Arc<SignedInclusionList<P>>) {
debug!("publishing inclusion list: {inclusion_list:?}");

self.publish(PubsubMessage::SignedInclusionList(inclusion_list));
}

fn publish_signed_bls_to_execution_change(
&self,
signed_bls_to_execution_change: Box<SignedBlsToExecutionChange>,
Expand Down Expand Up @@ -1568,6 +1578,18 @@ impl<P: Preset> Network<P> {
PubsubMessage::LightClientOptimisticUpdate(_) => {
debug!("received light client optimistic update as gossip");
}
PubsubMessage::SignedInclusionList(inclusion_list) => {
if let Some(metrics) = self.metrics.as_ref() {
metrics.register_gossip_object(&["inclusion_list"]);
}

trace!(
"received inclusion list as gossip: {inclusion_list:?} from {source}",
);

P2pToSync::GossipInclusionList(inclusion_list, source, GossipId { source, message_id })
.send(&self.channels.p2p_to_sync_tx);
}
}
}

Expand Down
Loading