From 213aee155873b8447eb4f968d2da4a841475eb66 Mon Sep 17 00:00:00 2001 From: Hubert Bugaj Date: Fri, 9 Jan 2026 18:14:58 +0100 Subject: [PATCH 1/5] fix: use ethereum block in `eth_subscribe` `newHeads` --- src/rpc/methods/chain.rs | 18 +++++++-- src/rpc/methods/eth.rs | 73 +++++++++++++++++++++++++++++++++++ src/rpc/methods/eth/pubsub.rs | 2 +- src/rpc/methods/eth/types.rs | 3 +- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index 02b1e9fbffe..5918b8b55df 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -17,6 +17,7 @@ use crate::lotus_json::{HasLotusJson, LotusJson, lotus_json_with_self}; #[cfg(test)] use crate::lotus_json::{assert_all_snapshots, assert_unchanged_via_json}; use crate::message::{ChainMessage, SignedMessage}; +use crate::rpc::eth::Block as EthBlock; use crate::rpc::eth::{EthLog, eth_logs_with_filter, types::ApiHeaders, types::EthFilterSpec}; use crate::rpc::f3::F3ExportLatestSnapshot; use crate::rpc::types::*; @@ -40,6 +41,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::fs::File; +use std::sync::Arc; use std::{collections::VecDeque, path::PathBuf, sync::LazyLock}; use tokio::sync::{ Mutex, @@ -74,8 +76,8 @@ static CHAIN_EXPORT_LOCK: LazyLock>> = /// /// Spawns an internal `tokio` task that can be aborted anytime via the returned `JoinHandle`, /// allowing manual cleanup if needed. -pub(crate) fn new_heads( - data: &crate::rpc::RPCState, +pub(crate) fn new_heads( + data: Ctx, ) -> (Subscriber, JoinHandle<()>) { let (sender, receiver) = broadcast::channel(HEAD_CHANNEL_CAPACITY); @@ -84,7 +86,17 @@ pub(crate) fn new_heads( let handle = tokio::spawn(async move { while let Ok(v) = subscriber.recv().await { let headers = match v { - HeadChange::Apply(ts) => ApiHeaders(ts.block_headers().clone().into()), + HeadChange::Apply(ts) => { + // Convert the tipset to an Ethereum block with full transaction info + // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block + match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), true).await { + Ok(block) => ApiHeaders(vec![block].into()), + Err(e) => { + tracing::error!("Failed to convert tipset to eth block: {}", e); + continue; + } + } + } }; if let Err(e) = sender.send(headers) { tracing::error!("Failed to send headers: {}", e); diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 25019f9f8fd..4ce4070f6da 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -545,6 +545,79 @@ impl Block { ..Default::default() } } + + /// Creates a new Ethereum block from a Filecoin tipset, executing transactions if requested. + /// + /// Reference: + pub async fn from_filecoin_tipset( + ctx: Ctx, + tipset: Arc, + full_tx_info: bool, + ) -> Result { + let parent_cid = tipset.parents().cid()?; + let parent_hash: EthHash = parent_cid.into(); + + let block_number = EthUint64(tipset.epoch() as u64); + + let tipset_cid = tipset.key().cid()?; + let block_hash: EthHash = tipset_cid.into(); + + let (state_root, msgs_and_receipts) = execute_tipset(&ctx, &tipset).await?; + + let state_tree = StateTree::new_from_root(ctx.store_owned(), &state_root)?; + + let mut block = Block::new(!msgs_and_receipts.is_empty(), tipset.len()); + + let mut gas_used: u64 = 0; + let mut transactions = Vec::new(); + + for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { + let ti = EthUint64(i as u64); + gas_used = gas_used.saturating_add(receipt.gas_used()); + + let smsg = match msg { + ChainMessage::Signed(msg) => msg.clone(), + ChainMessage::Unsigned(msg) => { + let sig = Signature::new_bls(vec![]); + SignedMessage::new_unchecked(msg.clone(), sig) + } + }; + + let mut tx = new_eth_tx_from_signed_message( + &smsg, + &state_tree, + ctx.chain_config().eth_chain_id, + )?; + + tx.block_hash = block_hash.clone(); + tx.block_number = block_number.clone(); + tx.transaction_index = ti; + + transactions.push(tx); + } + + block.transactions = if full_tx_info { + Transactions::Full(transactions) + } else { + Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) + }; + + block.hash = block_hash; + block.number = block_number; + block.parent_hash = parent_hash; + block.timestamp = EthUint64(tipset.block_headers().first().timestamp); + block.base_fee_per_gas = EthBigInt( + tipset + .block_headers() + .first() + .parent_base_fee + .atto() + .clone(), + ); + block.gas_used = EthUint64(gas_used); + + Ok(block) + } } lotus_json_with_self!(Block); diff --git a/src/rpc/methods/eth/pubsub.rs b/src/rpc/methods/eth/pubsub.rs index 29d290263fd..7c4d2bef3fd 100644 --- a/src/rpc/methods/eth/pubsub.rs +++ b/src/rpc/methods/eth/pubsub.rs @@ -123,7 +123,7 @@ where accepted_sink: jsonrpsee::SubscriptionSink, ctx: Arc>, ) { - let (subscriber, handle) = chain::new_heads(&ctx); + let (subscriber, handle) = chain::new_heads(ctx); tokio::spawn(async move { handle_subscription(subscriber, accepted_sink, handle).await; }); diff --git a/src/rpc/methods/eth/types.rs b/src/rpc/methods/eth/types.rs index 567860a4180..e714266447a 100644 --- a/src/rpc/methods/eth/types.rs +++ b/src/rpc/methods/eth/types.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0, MIT use super::*; -use crate::blocks::CachingBlockHeader; use crate::rpc::eth::pubsub_trait::LogFilter; use anyhow::ensure; use get_size2::GetSize; @@ -423,7 +422,7 @@ pub struct FilterID(EthHash); lotus_json_with_self!(FilterID); #[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] -pub struct ApiHeaders(#[serde(with = "crate::lotus_json")] pub Vec); +pub struct ApiHeaders(#[serde(with = "crate::lotus_json")] pub Vec); lotus_json_with_self!(ApiHeaders); From 587d6ab7c8f0faaff60f2e792dff65f92be609b8 Mon Sep 17 00:00:00 2001 From: Hubert Bugaj Date: Tue, 13 Jan 2026 17:20:11 +0100 Subject: [PATCH 2/5] fix: single block, not array --- src/rpc/methods/chain.rs | 2 +- src/rpc/methods/eth/types.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index 5918b8b55df..014ce9f1ed8 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -90,7 +90,7 @@ pub(crate) fn new_heads( // Convert the tipset to an Ethereum block with full transaction info // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), true).await { - Ok(block) => ApiHeaders(vec![block].into()), + Ok(block) => ApiHeaders(block), Err(e) => { tracing::error!("Failed to convert tipset to eth block: {}", e); continue; diff --git a/src/rpc/methods/eth/types.rs b/src/rpc/methods/eth/types.rs index e714266447a..8ed2dda171a 100644 --- a/src/rpc/methods/eth/types.rs +++ b/src/rpc/methods/eth/types.rs @@ -422,7 +422,7 @@ pub struct FilterID(EthHash); lotus_json_with_self!(FilterID); #[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] -pub struct ApiHeaders(#[serde(with = "crate::lotus_json")] pub Vec); +pub struct ApiHeaders(#[serde(with = "crate::lotus_json")] pub Block); lotus_json_with_self!(ApiHeaders); From cb317957f45edc590a836ed1113d34daf598a324 Mon Sep 17 00:00:00 2001 From: Hubert Bugaj Date: Tue, 13 Jan 2026 17:58:17 +0100 Subject: [PATCH 3/5] chore: changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 651cac711cb..16d49a23bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,8 @@ - [#6327](https://github.com/ChainSafe/forest/pull/6327) Fixed: Forest returns 404 for all invalid api paths. - [#6354](https://github.com/ChainSafe/forest/pull/6354) Fixed: Correctly calculate the epoch range instead of directly using the look back limit value while searching for messages. +- [#6400](https://github.com/ChainSafe/forest/issues/6400) Fixed `eth_subscribe` `newHeads` to return Ethereum block format instead of Filecoin block headers array. + ## Forest v0.30.5 "Dulce de Leche" Non-mandatory release supporting new API methods and addressing a critical panic issue. From 98009d4b1dc2dd560ab2a815c958bc1c24f27f68 Mon Sep 17 00:00:00 2001 From: Hubert Bugaj Date: Tue, 13 Jan 2026 18:04:00 +0100 Subject: [PATCH 4/5] chore: refactor the conversion method to use enum --- src/rpc/methods/chain.rs | 8 +++++-- src/rpc/methods/eth.rs | 47 +++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index 014ce9f1ed8..9378a203608 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -18,7 +18,9 @@ use crate::lotus_json::{HasLotusJson, LotusJson, lotus_json_with_self}; use crate::lotus_json::{assert_all_snapshots, assert_unchanged_via_json}; use crate::message::{ChainMessage, SignedMessage}; use crate::rpc::eth::Block as EthBlock; -use crate::rpc::eth::{EthLog, eth_logs_with_filter, types::ApiHeaders, types::EthFilterSpec}; +use crate::rpc::eth::{ + EthLog, TxInfo, eth_logs_with_filter, types::ApiHeaders, types::EthFilterSpec, +}; use crate::rpc::f3::F3ExportLatestSnapshot; use crate::rpc::types::*; use crate::rpc::{ApiPaths, Ctx, EthEventHandler, Permission, RpcMethod, ServerError}; @@ -89,7 +91,9 @@ pub(crate) fn new_heads( HeadChange::Apply(ts) => { // Convert the tipset to an Ethereum block with full transaction info // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block - match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), true).await { + match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), TxInfo::Full) + .await + { Ok(block) => ApiHeaders(block), Err(e) => { tracing::error!("Failed to convert tipset to eth block: {}", e); diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 4ce4070f6da..21a08826d87 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -531,6 +531,15 @@ pub struct Block { pub uncles: Vec, } +/// Specifies the level of detail for transactions in Ethereum blocks. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TxInfo { + /// Return only transaction hashes + Hash, + /// Return full transaction objects + Full, +} + impl Block { pub fn new(has_transactions: bool, tipset_len: usize) -> Self { Self { @@ -552,7 +561,7 @@ impl Block { pub async fn from_filecoin_tipset( ctx: Ctx, tipset: Arc, - full_tx_info: bool, + tx_info: TxInfo, ) -> Result { let parent_cid = tipset.parents().cid()?; let parent_hash: EthHash = parent_cid.into(); @@ -596,10 +605,11 @@ impl Block { transactions.push(tx); } - block.transactions = if full_tx_info { - Transactions::Full(transactions) - } else { - Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) + block.transactions = match tx_info { + TxInfo::Full => Transactions::Full(transactions), + TxInfo::Hash => { + Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) + } }; block.hash = block_hash; @@ -1568,7 +1578,7 @@ fn get_signed_message(ctx: &Ctx, message_cid: Cid) -> Result pub async fn block_from_filecoin_tipset( data: Ctx, tipset: Tipset, - full_tx_info: bool, + tx_info: TxInfo, ) -> Result { static ETH_BLOCK_CACHE: LazyLock> = LazyLock::new(|| { @@ -1635,7 +1645,9 @@ pub async fn block_from_filecoin_tipset( b }; - if !full_tx_info && let Transactions::Full(transactions) = &block.transactions { + if tx_info == TxInfo::Hash + && let Transactions::Full(transactions) = &block.transactions + { block.transactions = Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) } @@ -1663,7 +1675,12 @@ impl RpcMethod<2> for EthGetBlockByHash { BlockNumberOrHash::from_block_hash(block_hash), ResolveNullTipset::TakeOlder, )?; - let block = block_from_filecoin_tipset(ctx, ts, full_tx_info).await?; + let tx_info = if full_tx_info { + TxInfo::Full + } else { + TxInfo::Hash + }; + let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; Ok(block) } } @@ -1688,7 +1705,12 @@ impl RpcMethod<2> for EthGetBlockByNumber { block_param, ResolveNullTipset::TakeOlder, )?; - let block = block_from_filecoin_tipset(ctx, ts, full_tx_info).await?; + let tx_info = if full_tx_info { + TxInfo::Full + } else { + TxInfo::Hash + }; + let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; Ok(block) } } @@ -1710,7 +1732,12 @@ impl RpcMethod<2> for EthGetBlockByNumberV2 { ) -> Result { let ts = tipset_by_block_number_or_hash_v2(&ctx, block_param, ResolveNullTipset::TakeOlder) .await?; - let block = block_from_filecoin_tipset(ctx, ts, full_tx_info).await?; + let tx_info = if full_tx_info { + TxInfo::Full + } else { + TxInfo::Hash + }; + let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; Ok(block) } } From e58d24711b1c0a4a344f107abfecc681d4268987 Mon Sep 17 00:00:00 2001 From: Hubert Bugaj Date: Wed, 14 Jan 2026 10:49:14 +0100 Subject: [PATCH 5/5] chore: refactors --- src/rpc/methods/chain.rs | 5 +- src/rpc/methods/eth.rs | 239 +++++++++++++-------------------------- 2 files changed, 82 insertions(+), 162 deletions(-) diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index 9378a203608..dab1aa67415 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -43,7 +43,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sha2::Sha256; use std::fs::File; -use std::sync::Arc; use std::{collections::VecDeque, path::PathBuf, sync::LazyLock}; use tokio::sync::{ Mutex, @@ -91,9 +90,7 @@ pub(crate) fn new_heads( HeadChange::Apply(ts) => { // Convert the tipset to an Ethereum block with full transaction info // Note: In Filecoin's Eth RPC, a tipset maps to a single Ethereum block - match EthBlock::from_filecoin_tipset(data.clone(), Arc::new(ts), TxInfo::Full) - .await - { + match EthBlock::from_filecoin_tipset(data.clone(), ts, TxInfo::Full).await { Ok(block) => ApiHeaders(block), Err(e) => { tracing::error!("Failed to convert tipset to eth block: {}", e); diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 21a08826d87..6879cbb8999 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -540,6 +540,12 @@ pub enum TxInfo { Full, } +impl From for TxInfo { + fn from(full: bool) -> Self { + if full { TxInfo::Full } else { TxInfo::Hash } + } +} + impl Block { pub fn new(has_transactions: bool, tipset_len: usize) -> Self { Self { @@ -560,71 +566,80 @@ impl Block { /// Reference: pub async fn from_filecoin_tipset( ctx: Ctx, - tipset: Arc, + tipset: crate::blocks::Tipset, tx_info: TxInfo, ) -> Result { - let parent_cid = tipset.parents().cid()?; - let parent_hash: EthHash = parent_cid.into(); - - let block_number = EthUint64(tipset.epoch() as u64); - - let tipset_cid = tipset.key().cid()?; - let block_hash: EthHash = tipset_cid.into(); - - let (state_root, msgs_and_receipts) = execute_tipset(&ctx, &tipset).await?; - - let state_tree = StateTree::new_from_root(ctx.store_owned(), &state_root)?; - - let mut block = Block::new(!msgs_and_receipts.is_empty(), tipset.len()); + static ETH_BLOCK_CACHE: LazyLock> = + LazyLock::new(|| { + const DEFAULT_CACHE_SIZE: NonZeroUsize = nonzero!(500usize); + let cache_size = std::env::var("FOREST_ETH_BLOCK_CACHE_SIZE") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or(DEFAULT_CACHE_SIZE); + SizeTrackingLruCache::new_with_metrics("eth_block".into(), cache_size) + }); - let mut gas_used: u64 = 0; - let mut transactions = Vec::new(); + let block_cid = tipset.key().cid()?; + let mut block = if let Some(b) = ETH_BLOCK_CACHE.get_cloned(&block_cid.into()) { + b + } else { + let parent_cid = tipset.parents().cid()?; + let block_number = EthUint64(tipset.epoch() as u64); + let block_hash: EthHash = block_cid.into(); + + let (state_root, msgs_and_receipts) = execute_tipset(&ctx, &tipset).await?; + + let state_tree = StateTree::new_from_root(ctx.store_owned(), &state_root)?; + + let mut full_transactions = vec![]; + let mut gas_used = 0; + for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { + let ti = EthUint64(i as u64); + gas_used += receipt.gas_used(); + let smsg = match msg { + ChainMessage::Signed(msg) => msg.clone(), + ChainMessage::Unsigned(msg) => { + let sig = Signature::new_bls(vec![]); + SignedMessage::new_unchecked(msg.clone(), sig) + } + }; - for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { - let ti = EthUint64(i as u64); - gas_used = gas_used.saturating_add(receipt.gas_used()); + let mut tx = new_eth_tx_from_signed_message( + &smsg, + &state_tree, + ctx.chain_config().eth_chain_id, + )?; + tx.block_hash = block_hash.clone(); + tx.block_number = block_number.clone(); + tx.transaction_index = ti; + full_transactions.push(tx); + } - let smsg = match msg { - ChainMessage::Signed(msg) => msg.clone(), - ChainMessage::Unsigned(msg) => { - let sig = Signature::new_bls(vec![]); - SignedMessage::new_unchecked(msg.clone(), sig) - } + let b = Block { + hash: block_hash, + number: block_number, + parent_hash: parent_cid.into(), + timestamp: EthUint64(tipset.block_headers().first().timestamp), + base_fee_per_gas: tipset + .block_headers() + .first() + .parent_base_fee + .clone() + .into(), + gas_used: EthUint64(gas_used), + transactions: Transactions::Full(full_transactions), + ..Block::new(!msgs_and_receipts.is_empty(), tipset.len()) }; - - let mut tx = new_eth_tx_from_signed_message( - &smsg, - &state_tree, - ctx.chain_config().eth_chain_id, - )?; - - tx.block_hash = block_hash.clone(); - tx.block_number = block_number.clone(); - tx.transaction_index = ti; - - transactions.push(tx); - } - - block.transactions = match tx_info { - TxInfo::Full => Transactions::Full(transactions), - TxInfo::Hash => { - Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) - } + ETH_BLOCK_CACHE.push(block_cid.into(), b.clone()); + b }; - block.hash = block_hash; - block.number = block_number; - block.parent_hash = parent_hash; - block.timestamp = EthUint64(tipset.block_headers().first().timestamp); - block.base_fee_per_gas = EthBigInt( - tipset - .block_headers() - .first() - .parent_base_fee - .atto() - .clone(), - ); - block.gas_used = EthUint64(gas_used); + if tx_info == TxInfo::Hash + && let Transactions::Full(transactions) = &block.transactions + { + block.transactions = + Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) + } Ok(block) } @@ -1575,86 +1590,6 @@ fn get_signed_message(ctx: &Ctx, message_cid: Cid) -> Result }) } -pub async fn block_from_filecoin_tipset( - data: Ctx, - tipset: Tipset, - tx_info: TxInfo, -) -> Result { - static ETH_BLOCK_CACHE: LazyLock> = - LazyLock::new(|| { - const DEFAULT_CACHE_SIZE: NonZeroUsize = nonzero!(500usize); - let cache_size = std::env::var("FOREST_ETH_BLOCK_CACHE_SIZE") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(DEFAULT_CACHE_SIZE); - SizeTrackingLruCache::new_with_metrics("eth_block".into(), cache_size) - }); - - let block_cid = tipset.key().cid()?; - let mut block = if let Some(b) = ETH_BLOCK_CACHE.get_cloned(&block_cid.into()) { - b - } else { - let parent_cid = tipset.parents().cid()?; - let block_number = EthUint64(tipset.epoch() as u64); - let block_hash: EthHash = block_cid.into(); - - let (state_root, msgs_and_receipts) = execute_tipset(&data, &tipset).await?; - - let state_tree = StateTree::new_from_root(data.store_owned(), &state_root)?; - - let mut full_transactions = vec![]; - let mut gas_used = 0; - for (i, (msg, receipt)) in msgs_and_receipts.iter().enumerate() { - let ti = EthUint64(i as u64); - gas_used += receipt.gas_used(); - let smsg = match msg { - ChainMessage::Signed(msg) => msg.clone(), - ChainMessage::Unsigned(msg) => { - let sig = Signature::new_bls(vec![]); - SignedMessage::new_unchecked(msg.clone(), sig) - } - }; - - let mut tx = new_eth_tx_from_signed_message( - &smsg, - &state_tree, - data.chain_config().eth_chain_id, - )?; - tx.block_hash = block_hash.clone(); - tx.block_number = block_number.clone(); - tx.transaction_index = ti; - full_transactions.push(tx); - } - - let b = Block { - hash: block_hash, - number: block_number, - parent_hash: parent_cid.into(), - timestamp: EthUint64(tipset.block_headers().first().timestamp), - base_fee_per_gas: tipset - .block_headers() - .first() - .parent_base_fee - .clone() - .into(), - gas_used: EthUint64(gas_used), - transactions: Transactions::Full(full_transactions), - ..Block::new(!msgs_and_receipts.is_empty(), tipset.len()) - }; - ETH_BLOCK_CACHE.push(block_cid.into(), b.clone()); - b - }; - - if tx_info == TxInfo::Hash - && let Transactions::Full(transactions) = &block.transactions - { - block.transactions = - Transactions::Hash(transactions.iter().map(|tx| tx.hash.to_string()).collect()) - } - - Ok(block) -} - pub enum EthGetBlockByHash {} impl RpcMethod<2> for EthGetBlockByHash { const NAME: &'static str = "Filecoin.EthGetBlockByHash"; @@ -1675,13 +1610,9 @@ impl RpcMethod<2> for EthGetBlockByHash { BlockNumberOrHash::from_block_hash(block_hash), ResolveNullTipset::TakeOlder, )?; - let tx_info = if full_tx_info { - TxInfo::Full - } else { - TxInfo::Hash - }; - let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; - Ok(block) + Block::from_filecoin_tipset(ctx, ts, full_tx_info.into()) + .await + .map_err(ServerError::from) } } @@ -1705,13 +1636,9 @@ impl RpcMethod<2> for EthGetBlockByNumber { block_param, ResolveNullTipset::TakeOlder, )?; - let tx_info = if full_tx_info { - TxInfo::Full - } else { - TxInfo::Hash - }; - let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; - Ok(block) + Block::from_filecoin_tipset(ctx, ts, full_tx_info.into()) + .await + .map_err(ServerError::from) } } @@ -1732,13 +1659,9 @@ impl RpcMethod<2> for EthGetBlockByNumberV2 { ) -> Result { let ts = tipset_by_block_number_or_hash_v2(&ctx, block_param, ResolveNullTipset::TakeOlder) .await?; - let tx_info = if full_tx_info { - TxInfo::Full - } else { - TxInfo::Hash - }; - let block = block_from_filecoin_tipset(ctx, ts, tx_info).await?; - Ok(block) + Block::from_filecoin_tipset(ctx, ts, full_tx_info.into()) + .await + .map_err(ServerError::from) } }