Skip to content
Closed
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
61 changes: 44 additions & 17 deletions crates/node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ use reth_rpc_api::Web3ApiServer;
use reth_rpc_builder::EthHandlers;
use reth_rpc_eth_api::{
EthApiTypes, EthFilterApiServer, RpcConvert,
helpers::{EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, FullEthApi},
helpers::{EthApiSpec, EthCall, EthFees, EthState, EthTransactions, FullEthApi},
};
use reth_rpc_eth_types::{EthApiError, logs_utils};
use reth_storage_api::{BlockNumReader, StateProviderFactory};
use reth_storage_api::{BlockIdReader, BlockNumReader, BlockReaderIdExt, StateProviderFactory};
use reth_trie_common::{ExecutionWitnessMode, HashedPostState};
use tempo_alloy::{
TempoNetwork,
Expand Down Expand Up @@ -748,19 +748,50 @@ impl<Api> ZoneRpc<Api>
where
Api: FullEthApi + EthApiTypes<NetworkTypes = TempoNetwork> + Send + Sync + 'static,
{
/// Serve the redacted block from the sealed header alone.
///
/// Redaction drops the entire body, so loading the recovered block (and evicting the block
/// cache with it) only to hash every transaction and RLP-encode the body for `size` is wasted
/// work. The requested block is usually cached, since clients poll `latest`, so the header
/// is taken from the cached block and only read from the provider on a miss.
fn block_by_id(&self, id: BlockId) -> BoxFut<'_> {
Box::pin(async move {
let block = EthBlocks::rpc_block(&self.eth.api, id, false)
let provider = self.eth.api.provider();
let Some(hash) = provider.block_hash_for_id(id).map_err(internal)? else {
return Ok(raw_null());
};
let cached = self
.eth
.api
.cache()
.get_maybe_block(hash)
.await
.map_err(internal)?;

let Some(mut block) = block else {
return Ok(raw_null());
let header = match cached {
Some(block) => block.clone_sealed_header(),
None => match provider.sealed_header_by_hash(hash).map_err(internal)? {
Some(header) => header,
None => return Ok(raw_null()),
},
};

redact_block(&mut block);
// A block carries withdrawals exactly when its header has a withdrawals root.
let withdrawals = header.withdrawals_root().map(|_| Default::default());
// `redact_header` zeroes `size`, so the block's RLP length is never observed.
let mut header = self
.eth
.api
.converter()
.convert_header(header, 0)
.map_err(internal)?;
redact_header(&mut header);

to_raw(&block)
to_raw(&RpcBlock {
header,
uncles: Vec::new(),
transactions: BlockTransactions::Hashes(Vec::new()),
withdrawals,
})
})
}
}
Expand Down Expand Up @@ -828,8 +859,11 @@ where

fn coinbase(&self) -> BoxFut<'_> {
Box::pin(async move {
let header = EthBlocks::rpc_block_header(&self.eth.api, BlockId::latest())
.await
let header = self
.eth
.api
.provider()
.latest_header()
.map_err(internal)?
.ok_or_else(|| JsonRpcError::internal("latest block not found"))?;
to_raw(&header.beneficiary())
Expand Down Expand Up @@ -1480,13 +1514,6 @@ fn apply_public_fee_policy(request: &mut TempoTransactionRequest) {
}
}

/// Strip privacy-sensitive fields from a block returned by the redacted RPC.
fn redact_block(block: &mut RpcBlock) {
redact_header(&mut block.header);
block.transactions = BlockTransactions::Hashes(Vec::new());
block.withdrawals = block.withdrawals.take().map(|_| Default::default());
}

pub(crate) fn rpc_connection_config(retry_connection_interval: Duration) -> ConnectionConfig {
ConnectionConfig::new()
.with_max_retries(u32::MAX)
Expand Down
Loading