Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
800304d
Add get IL rpc requests support to the engine api module
conache Jul 15, 2026
c708ac1
Add serde tests for the IL engine api response
conache Jul 15, 2026
345d51e
Expose get IL capability and execution layer wrapper method
conache Jul 15, 2026
9ec1d4c
Testing support
conache Jul 15, 2026
090c84f
Use accurate error for the request
conache Jul 15, 2026
de829b5
Merge branch 'unstable' of https://github.com/sigp/lighthouse into su…
conache Aug 4, 2026
259b854
Use ProgressiveTransactions type
conache Aug 4, 2026
67323c4
Fix import placing
conache Aug 4, 2026
db95323
Merge branch 'unstable' into support-get-il-v1
conache Aug 6, 2026
6679570
Merge branch 'unstable' into support-get-il-v1
conache Aug 10, 2026
245a8f0
Merge branch 'unstable' into support-get-il-v1
conache Aug 10, 2026
f12999c
Merge branch 'unstable' into support-get-il-v1
conache Aug 12, 2026
7c5e3c9
Merge branch 'unstable' into support-get-il-v1
conache Aug 13, 2026
5c8649f
Merge branch 'unstable' into support-get-il-v1
conache Aug 16, 2026
1cf9b44
Merge branch 'unstable' into support-get-il-v1
conache Aug 18, 2026
778678c
Merge branch 'unstable' into support-get-il-v1
conache Aug 18, 2026
93d627b
Merge branch 'unstable' into support-get-il-v1
conache Aug 24, 2026
ec6f4f3
Merge branch 'unstable' into support-get-il-v1
conache Aug 27, 2026
2793e87
Merge branch 'unstable' into support-get-il-v1
conache Aug 30, 2026
685c60c
Merge branch 'unstable' into support-get-il-v1
conache Sep 2, 2026
21ea7fc
Remove blockHash parameter from the engine api call to align with the…
conache Sep 2, 2026
f7da152
Fix stale comment
conache Sep 2, 2026
5824ae4
Merge branch 'unstable' into support-get-il-v1
conache Sep 3, 2026
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
13 changes: 9 additions & 4 deletions beacon_node/execution_layer/src/engine_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use crate::engines::ForkchoiceState;
use crate::http::{
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_GET_BLOBS_V2, ENGINE_GET_CLIENT_VERSION_V1,
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4,
ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2,
ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V5,
ENGINE_GET_INCLUSION_LIST_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2,
ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6,
ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4,
ENGINE_NEW_PAYLOAD_V5,
};
use eth2::types::{
BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2,
Expand Down Expand Up @@ -614,6 +615,7 @@ pub struct EngineCapabilities {
pub get_client_version_v1: bool,
pub get_blobs_v2: bool,
pub get_blobs_v3: bool,
pub get_inclusion_list_v1: bool,
}

impl EngineCapabilities {
Expand Down Expand Up @@ -676,6 +678,9 @@ impl EngineCapabilities {
if self.get_blobs_v2 {
response.push(ENGINE_GET_BLOBS_V2);
}
if self.get_inclusion_list_v1 {
response.push(ENGINE_GET_INCLUSION_LIST_V1);
}

response
}
Expand Down
84 changes: 83 additions & 1 deletion beacon_node/execution_layer/src/engine_api/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::sync::LazyLock;
use tokio::sync::Mutex;
use tracing::Span;
use tracing_opentelemetry::OpenTelemetrySpanExt;
use types::ProgressiveTransactions;

use std::time::{Duration, Instant};

Expand Down Expand Up @@ -67,6 +68,9 @@ pub const ENGINE_GET_BLOBS_V2: &str = "engine_getBlobsV2";
pub const ENGINE_GET_BLOBS_V3: &str = "engine_getBlobsV3";
pub const ENGINE_GET_BLOBS_TIMEOUT: Duration = Duration::from_secs(1);

pub const ENGINE_GET_INCLUSION_LIST_V1: &str = "engine_getInclusionListV1";
pub const ENGINE_GET_INCLUSION_LIST_TIMEOUT: Duration = Duration::from_secs(1);

/// This error is returned during a `chainId` call by Geth.
pub const EIP155_ERROR_STR: &str = "chain not synced beyond EIP-155 replay-protection fork block";
/// This code is returned by all clients when a method is not supported
Expand Down Expand Up @@ -94,6 +98,7 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
ENGINE_GET_CLIENT_VERSION_V1,
ENGINE_GET_BLOBS_V2,
ENGINE_GET_BLOBS_V3,
ENGINE_GET_INCLUSION_LIST_V1,
];

/// We opt to initialize the JsonClientVersionV1 rather than the ClientVersionV1
Expand Down Expand Up @@ -752,6 +757,16 @@ impl HttpJsonRpc {
.await
}

pub async fn get_inclusion_list_v1(&self) -> Result<ProgressiveTransactions, Error> {
self.rpc_request::<JsonInclusionListV1>(
ENGINE_GET_INCLUSION_LIST_V1,
json!([]),
ENGINE_GET_INCLUSION_LIST_TIMEOUT * self.execution_timeout_multiplier,
)
.await
.map(|response| response.0)
}

pub async fn get_block_by_number(
&self,
query: BlockByNumberQuery<'_>,
Expand Down Expand Up @@ -1251,6 +1266,7 @@ impl HttpJsonRpc {
get_client_version_v1: capabilities.contains(ENGINE_GET_CLIENT_VERSION_V1),
get_blobs_v2: capabilities.contains(ENGINE_GET_BLOBS_V2),
get_blobs_v3: capabilities.contains(ENGINE_GET_BLOBS_V3),
get_inclusion_list_v1: capabilities.contains(ENGINE_GET_INCLUSION_LIST_V1),
})
}

Expand Down Expand Up @@ -1529,7 +1545,7 @@ mod test {
use super::*;
use crate::test_utils::{DEFAULT_JWT_SECRET, MockServer};
use fixed_bytes::FixedBytesExtended;
use ssz_types::VariableList;
use ssz_types::{ProgressiveVariableList, VariableList};
use std::future::Future;
use std::str::FromStr;
use std::sync::Arc;
Expand Down Expand Up @@ -1709,6 +1725,15 @@ mod test {
txs
}

fn generate_progressive_transactions(spec: &[usize]) -> ProgressiveTransactions {
let mut txs = ProgressiveTransactions::empty();
for &num_bytes in spec {
txs.push(ProgressiveVariableList::new(vec![0; num_bytes]));
}

txs
}

#[test]
fn transaction_serde() {
assert_transactions_serde::<MainnetEthSpec>(
Expand Down Expand Up @@ -1757,6 +1782,42 @@ mod test {
);
}

fn assert_inclusion_list_serde(
name: &str,
as_obj: ProgressiveTransactions,
as_json: serde_json::Value,
) {
assert_eq!(
serde_json::to_value(JsonInclusionListV1(as_obj.clone())).unwrap(),
as_json,
"encoding for {}",
name
);
assert_eq!(
serde_json::from_value::<JsonInclusionListV1>(as_json)
.unwrap()
.0,
as_obj,
"decoding for {}",
name
);
}

#[test]
fn inclusion_list_serde() {
assert_inclusion_list_serde("empty", generate_progressive_transactions(&[]), json!([]));
assert_inclusion_list_serde(
"one empty tx",
generate_progressive_transactions(&[0]),
json!(["0x"]),
);
assert_inclusion_list_serde(
"mixed bag",
generate_progressive_transactions(&[0, 1, 3, 0]),
json!(["0x", "0x00", "0x000000", "0x"]),
);
}

#[tokio::test]
async fn get_block_by_number_request() {
Tester::new(true)
Expand Down Expand Up @@ -1784,6 +1845,27 @@ mod test {
.await;
}

#[tokio::test]
async fn get_inclusion_list_v1_request() {
Tester::new(true)
.assert_request_equals(
|client| async move {
let _ = client.get_inclusion_list_v1().await;
},
json!({
"id": STATIC_ID,
"jsonrpc": JSONRPC_VERSION,
"method": ENGINE_GET_INCLUSION_LIST_V1,
"params": []
}),
)
.await;

Tester::new(false)
.assert_auth_failure(|client| async move { client.get_inclusion_list_v1().await })
.await;
}

#[tokio::test]
async fn forkchoice_updated_v1_with_payload_attributes_request() {
Tester::new(true)
Expand Down
7 changes: 7 additions & 0 deletions beacon_node/execution_layer/src/engine_api/json_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,13 @@ impl TryFrom<JsonClientVersionV1> for ClientVersionV1 {
}
}

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct JsonInclusionListV1(
#[serde(with = "ssz_types::serde_utils::prog_list_of_hex_prog_var_list")]
pub ProgressiveTransactions,
);

#[cfg(test)]
mod tests {
use bls::{PublicKeyBytes, SignatureBytes};
Expand Down
18 changes: 17 additions & 1 deletion beacon_node/execution_layer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ use types::execution::BlockProductionVersion;
use types::kzg_ext::{KzgCommitments, ProgressiveKzgCommitments};
use types::{
AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, ExecutionRequests,
ExecutionRequestsElectra, ExecutionRequestsGloas, KzgProofs, SignedBlindedBeaconBlock,
ExecutionRequestsElectra, ExecutionRequestsGloas, KzgProofs, ProgressiveTransactions,
SignedBlindedBeaconBlock,
};
use types::{
BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix,
Expand Down Expand Up @@ -155,6 +156,7 @@ pub enum Error {
ZeroLengthTransaction,
PayloadBodiesByRangeNotSupported,
GetBlobsNotSupported,
GetInclusionListNotSupported,
InvalidJWTSecret(String),
InvalidForkForPayload,
InvalidPayloadBody(String),
Expand Down Expand Up @@ -1776,6 +1778,20 @@ impl<E: EthSpec> ExecutionLayer<E> {
}
}

pub async fn get_inclusion_list_v1(&self) -> Result<ProgressiveTransactions, Error> {
let capabilities = self.get_engine_capabilities(None).await?;

if capabilities.get_inclusion_list_v1 {
self.engine()
.request(|engine| async move { engine.api.get_inclusion_list_v1().await })
.await
.map_err(Box::new)
.map_err(Error::EngineError)
} else {
Err(Error::GetInclusionListNotSupported)
}
}

pub async fn get_block_by_number(
&self,
query: BlockByNumberQuery<'_>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use types::{
Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix,
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu,
ExecutionPayloadGloas, ExecutionPayloadHeader, ExecutionPayloadHeze, ExecutionRequests,
ForkName, Hash256, KzgProofs, Transaction, Transactions, Uint256,
ForkName, Hash256, KzgProofs, ProgressiveTransactions, Transaction, Transactions, Uint256,
};

const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
Expand Down Expand Up @@ -178,6 +178,11 @@ pub struct ExecutionBlockGenerator<E: EthSpec> {
/// execution requests with the generated payload ID.
next_execution_requests: Option<ExecutionRequests<E>>,
generate_blobs: bool,
/*
* Inclusion lists (heze+)
*/
/// The transactions returned by `getInclusionList`.
inclusion_list: ProgressiveTransactions,
}

fn make_rng() -> Arc<Mutex<StdRng>> {
Expand Down Expand Up @@ -221,6 +226,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
execution_requests: <_>::default(),
next_execution_requests: None,
generate_blobs: true,
inclusion_list: <_>::default(),
};

generator.insert_pow_block(0).unwrap();
Expand Down Expand Up @@ -489,6 +495,16 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
self.next_execution_requests = Some(requests);
}

/// Return the configured inclusion list transactions
pub fn get_inclusion_list(&self) -> ProgressiveTransactions {
self.inclusion_list.clone()
}

/// Set the transactions returned by `getInclusionList`.
pub fn set_inclusion_list(&mut self, transactions: ProgressiveTransactions) {
self.inclusion_list = transactions;
}

/// Look up a blob and proof by versioned hash across all stored bundles.
pub fn get_blob_and_proof(&self, versioned_hash: &Hash256) -> Option<BlobAndProof<E>> {
self.blobs_bundles
Expand Down
5 changes: 5 additions & 0 deletions beacon_node/execution_layer/src/test_utils/handle_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,11 @@ pub async fn handle_rpc<E: EthSpec>(
let response: Option<Vec<BlobAndProofV2<E>>> = results.into_iter().collect();
Ok(serde_json::to_value(response).unwrap())
}
ENGINE_GET_INCLUSION_LIST_V1 => {
let transactions = ctx.execution_block_generator.read().get_inclusion_list();

Ok(serde_json::to_value(JsonInclusionListV1(transactions)).unwrap())
}
ENGINE_FORKCHOICE_UPDATED_V1
| ENGINE_FORKCHOICE_UPDATED_V2
| ENGINE_FORKCHOICE_UPDATED_V3
Expand Down
1 change: 1 addition & 0 deletions beacon_node/execution_layer/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
get_client_version_v1: true,
get_blobs_v2: true,
get_blobs_v3: true,
get_inclusion_list_v1: true,
};

pub static DEFAULT_CLIENT_VERSION: LazyLock<JsonClientVersionV1> =
Expand Down
Loading