Skip to content

Commit 8c1f218

Browse files
PelleKrabampagent
andcommitted
feat(anvil): add debug_getRawHeader
Expose canonical RLP-encoded block headers for proof witness construction. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019ff1b0-c07c-77f3-816c-5da33175c7a4
1 parent ae7557c commit 8c1f218

3 files changed

Lines changed: 59 additions & 3 deletions

File tree

crates/anvil/core/src/eth/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ pub enum EthRequest {
290290
#[serde(rename = "debug_getRawTransaction", with = "sequence")]
291291
DebugGetRawTransaction(TxHash),
292292

293+
/// geth's `debug_getRawHeader` endpoint
294+
#[serde(rename = "debug_getRawHeader", with = "sequence")]
295+
DebugGetRawHeader(BlockId),
296+
293297
/// geth's `debug_traceTransaction` endpoint
294298
#[serde(rename = "debug_traceTransaction")]
295299
DebugTraceTransaction(B256, #[serde(default)] GethDebugTracingOptions),

crates/anvil/src/eth/api.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ impl EthApi {
330330
EthRequest::DebugGetRawTransaction(hash) => {
331331
self.raw_transaction(hash).await.to_rpc_result()
332332
}
333+
EthRequest::DebugGetRawHeader(block) => self.raw_header(block).to_rpc_result(),
333334
// non eth-standard rpc calls
334335
EthRequest::DebugTraceTransaction(tx, opts) => {
335336
self.debug_trace_transaction(tx, opts).await.to_rpc_result()
@@ -1578,6 +1579,12 @@ impl EthApi {
15781579
self.backend.block_receipts(number).await
15791580
}
15801581

1582+
/// Returns the canonical RLP encoding of a block header.
1583+
pub fn raw_header(&self, block: BlockId) -> Result<Option<Bytes>> {
1584+
node_info!("debug_getRawHeader");
1585+
Ok(self.backend.get_block(block).map(|block| alloy_rlp::encode(&block.header).into()))
1586+
}
1587+
15811588
/// Returns an uncles at given block and index.
15821589
///
15831590
/// Handler for ETH RPC call: `eth_getUncleByBlockHashAndIndex`

crates/anvil/tests/it/beacon_api.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
use crate::utils::http_provider;
2-
use alloy_consensus::{Blob, BlobTransactionSidecar, SidecarBuilder, SimpleCoder, Transaction};
2+
use alloy_consensus::{
3+
Blob, BlobTransactionSidecar, Header, SidecarBuilder, SimpleCoder, Transaction,
4+
};
35
use alloy_network::{TransactionBuilder, TransactionBuilder4844};
4-
use alloy_primitives::{B256, FixedBytes, U256, b256};
6+
use alloy_primitives::{B256, Bytes, FixedBytes, U256, b256};
57
use alloy_provider::Provider;
6-
use alloy_rpc_types::TransactionRequest;
8+
use alloy_rlp::Decodable;
9+
use alloy_rpc_types::{BlockNumberOrTag, TransactionRequest};
710
use alloy_rpc_types_beacon::{genesis::GenesisResponse, sidecar::GetBlobsResponse};
811
use alloy_serde::WithOtherFields;
912
use anvil::{NodeConfig, spawn};
1013
use foundry_evm::hardfork::EthereumHardfork;
14+
use serde_json::json;
1115
use ssz::Decode;
1216

1317
#[tokio::test(flavor = "multi_thread")]
@@ -258,3 +262,44 @@ async fn test_beacon_api_get_genesis() {
258262
FixedBytes::from([0x00, 0x00, 0x00, 0x00])
259263
);
260264
}
265+
266+
#[tokio::test(flavor = "multi_thread")]
267+
async fn test_debug_get_raw_header() {
268+
let (_api, handle) = spawn(NodeConfig::test()).await;
269+
let provider = http_provider(&handle.http_endpoint());
270+
let block = provider.get_block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();
271+
let raw_header_response: serde_json::Value = reqwest::Client::new()
272+
.post(handle.http_endpoint())
273+
.json(&json!({
274+
"jsonrpc": "2.0",
275+
"id": 1,
276+
"method": "debug_getRawHeader",
277+
"params": ["latest"]
278+
}))
279+
.send()
280+
.await
281+
.unwrap()
282+
.json()
283+
.await
284+
.unwrap();
285+
let raw_header: Bytes = serde_json::from_value(raw_header_response["result"].clone()).unwrap();
286+
let header = Header::decode(&mut raw_header.as_ref()).unwrap();
287+
288+
assert_eq!(header.hash_slow(), block.header.hash);
289+
290+
let unavailable_response: serde_json::Value = reqwest::Client::new()
291+
.post(handle.http_endpoint())
292+
.json(&json!({
293+
"jsonrpc": "2.0",
294+
"id": 1,
295+
"method": "debug_getRawHeader",
296+
"params": ["0xffffff"]
297+
}))
298+
.send()
299+
.await
300+
.unwrap()
301+
.json()
302+
.await
303+
.unwrap();
304+
assert!(unavailable_response["result"].is_null());
305+
}

0 commit comments

Comments
 (0)