diff --git a/src/cid_collections/hash_set.rs b/src/cid_collections/hash_set.rs index c92f7da90084..b55af3de0fcb 100644 --- a/src/cid_collections/hash_set.rs +++ b/src/cid_collections/hash_set.rs @@ -31,6 +31,11 @@ impl CidHashSet { pub fn insert(&mut self, cid: Cid) -> bool { self.inner.insert(cid, ()).is_none() } + + /// Returns the number of elements. + pub fn len(&self) -> usize { + self.inner.len() + } } //////////////////// diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index a941e96f8645..58dcb2f1f66f 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -6,6 +6,7 @@ use super::gas; use crate::blocks::{Tipset, TipsetKey}; use crate::chain::{index::ResolveNullTipset, ChainStore}; use crate::chain_sync::SyncStage; +use crate::cid_collections::CidHashSet; use crate::lotus_json::LotusJson; use crate::lotus_json::{lotus_json_with_self, HasLotusJson}; use crate::message::{ChainMessage, Message as _, SignedMessage}; @@ -50,6 +51,7 @@ macro_rules! for_each_method { $callback!(crate::rpc::eth::EthGasPrice); $callback!(crate::rpc::eth::EthGetBalance); $callback!(crate::rpc::eth::EthGetBlockByNumber); + $callback!(crate::rpc::eth::EthGetBlockTransactionCountByNumber); }; } pub(crate) use for_each_method; @@ -146,6 +148,15 @@ pub struct Uint64( lotus_json_with_self!(Uint64); +#[derive(PartialEq, Debug, Deserialize, Serialize, Default, Clone, JsonSchema)] +pub struct Int64( + #[schemars(with = "String")] + #[serde(with = "crate::lotus_json::hexify")] + pub i64, +); + +lotus_json_with_self!(Int64); + #[derive(PartialEq, Debug, Deserialize, Serialize, Default, Clone, JsonSchema)] pub struct Bytes( #[schemars(with = "String")] @@ -1282,6 +1293,49 @@ impl RpcMethod<2> for EthGetBlockByNumber { } } +pub enum EthGetBlockTransactionCountByNumber {} +impl RpcMethod<1> for EthGetBlockTransactionCountByNumber { + const NAME: &'static str = "Filecoin.EthGetBlockTransactionCountByNumber"; + const PARAM_NAMES: [&'static str; 1] = ["block_number"]; + const API_VERSION: ApiVersion = ApiVersion::V1; + const PERMISSION: Permission = Permission::Read; + + type Params = (Int64,); + type Ok = Uint64; + + async fn handle( + ctx: Ctx, + (block_number,): Self::Params, + ) -> Result { + let height = block_number.0; + let head = ctx.chain_store.heaviest_tipset(); + if height > head.epoch() { + return Err(anyhow::anyhow!("requested a future epoch (beyond \"latest\")").into()); + } + let ts = ctx.chain_store.chain_index.tipset_by_height( + height, + head, + ResolveNullTipset::TakeOlder, + )?; + let count = count_messages_in_tipset(ctx.store(), &ts)?; + Ok(Uint64(count as _)) + } +} + +fn count_messages_in_tipset(store: &impl Blockstore, ts: &Tipset) -> anyhow::Result { + let mut message_cids = CidHashSet::default(); + for block in ts.block_headers() { + let (bls_messages, secp_messages) = crate::chain::store::block_messages(store, block)?; + for m in bls_messages { + message_cids.insert(m.cid()?); + } + for m in secp_messages { + message_cids.insert(m.cid()?); + } + } + Ok(message_cids.len()) +} + pub enum EthSyncing {} impl RpcMethod<0> for EthSyncing { const NAME: &'static str = "Filecoin.EthSyncing"; diff --git a/src/tool/subcommands/api_cmd.rs b/src/tool/subcommands/api_cmd.rs index ef9c45acd8e0..6f5462f1702f 100644 --- a/src/tool/subcommands/api_cmd.rs +++ b/src/tool/subcommands/api_cmd.rs @@ -1021,6 +1021,9 @@ fn eth_tests_with_tipset(shared_tipset: &Tipset) -> Vec { )) .unwrap(), ), + RpcTest::identity( + EthGetBlockTransactionCountByNumber::request((Int64(shared_tipset.epoch()),)).unwrap(), + ), ] }