From 193898046d970cb745684bba5182aed0b677e2c7 Mon Sep 17 00:00:00 2001 From: Shashank Date: Wed, 7 Jan 2026 15:42:07 +0530 Subject: [PATCH 1/4] Impl eth get transaction v2 --- src/rpc/methods/eth.rs | 83 ++++++++++++++----- src/rpc/mod.rs | 1 + .../subcommands/api_cmd/api_compare_tests.rs | 43 ++++++++++ 3 files changed, 108 insertions(+), 19 deletions(-) diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index e3779f12d8a2..df938b07b71e 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -2393,33 +2393,78 @@ impl RpcMethod<2> for EthGetTransactionCount { (sender, block_param): Self::Params, ) -> Result { let addr = sender.to_filecoin_address()?; - if let BlockNumberOrHash::PredefinedBlock(ref predefined) = block_param - && *predefined == Predefined::Pending - { - return Ok(EthUint64(ctx.mpool.get_sequence(&addr)?)); + match block_param { + BlockNumberOrHash::PredefinedBlock(Predefined::Pending) => { + Ok(EthUint64(ctx.mpool.get_sequence(&addr)?)) + } + _ => { + let ts = tipset_by_block_number_or_hash( + ctx.chain_store(), + block_param, + ResolveNullTipset::TakeOlder, + )?; + eth_get_transaction_count(&ctx, &ts, addr).await + } } - let ts = tipset_by_block_number_or_hash( - ctx.chain_store(), - block_param.clone(), - ResolveNullTipset::TakeOlder, - )?; + } +} - let (state_cid, _) = ctx.state_manager.tipset_state(&ts).await?; +pub enum EthGetTransactionCountV2 {} +impl RpcMethod<2> for EthGetTransactionCountV2 { + const NAME: &'static str = "Filecoin.EthGetTransactionCount"; + const NAME_ALIAS: Option<&'static str> = Some("eth_getTransactionCount"); + const PARAM_NAMES: [&'static str; 2] = ["sender", "blockParam"]; + const API_PATHS: BitFlags = make_bitflags!(ApiPaths::V2); + const PERMISSION: Permission = Permission::Read; + + type Params = (EthAddress, ExtBlockNumberOrHash); + type Ok = EthUint64; - let state = StateTree::new_from_root(ctx.store_owned(), &state_cid)?; - let actor = state.get_required_actor(&addr)?; - if is_evm_actor(&actor.code) { - let evm_state = evm::State::load(ctx.store(), actor.code, actor.state)?; - if !evm_state.is_alive() { - return Ok(EthUint64(0)); + async fn handle( + ctx: Ctx, + (sender, block_param): Self::Params, + ) -> Result { + let addr = sender.to_filecoin_address()?; + match block_param { + ExtBlockNumberOrHash::PredefinedBlock(ExtPredefined::Pending) => { + Ok(EthUint64(ctx.mpool.get_sequence(&addr)?)) + } + _ => { + let ts = tipset_by_block_number_or_hash_v2( + &ctx, + block_param, + ResolveNullTipset::TakeOlder, + ) + .await?; + eth_get_transaction_count(&ctx, &ts, addr).await } - Ok(EthUint64(evm_state.nonce())) - } else { - Ok(EthUint64(actor.sequence)) } } } +async fn eth_get_transaction_count( + ctx: &Ctx, + ts: &Tipset, + addr: FilecoinAddress, +) -> Result +where + B: Blockstore + Send + Sync + 'static, +{ + let (state_cid, _) = ctx.state_manager.tipset_state(&ts).await?; + + let state = StateTree::new_from_root(ctx.store_owned(), &state_cid)?; + let actor = state.get_required_actor(&addr)?; + if is_evm_actor(&actor.code) { + let evm_state = evm::State::load(ctx.store(), actor.code, actor.state)?; + if !evm_state.is_alive() { + return Ok(EthUint64(0)); + } + Ok(EthUint64(evm_state.nonce())) + } else { + Ok(EthUint64(actor.sequence)) + } +} + pub enum EthMaxPriorityFeePerGas {} impl RpcMethod<0> for EthMaxPriorityFeePerGas { const NAME: &'static str = "Filecoin.EthMaxPriorityFeePerGas"; diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index ba494aaf102a..dcc5bfdb8fa9 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -125,6 +125,7 @@ macro_rules! for_each_rpc_method { $callback!($crate::rpc::eth::EthGetTransactionByHash); $callback!($crate::rpc::eth::EthGetTransactionByHashLimited); $callback!($crate::rpc::eth::EthGetTransactionCount); + $callback!($crate::rpc::eth::EthGetTransactionCountV2); $callback!($crate::rpc::eth::EthGetTransactionHashByCid); $callback!($crate::rpc::eth::EthGetTransactionByBlockNumberAndIndex); $callback!($crate::rpc::eth::EthGetTransactionByBlockHashAndIndex); diff --git a/src/tool/subcommands/api_cmd/api_compare_tests.rs b/src/tool/subcommands/api_cmd/api_compare_tests.rs index adf169fe0b54..6a2e42b12c5f 100644 --- a/src/tool/subcommands/api_cmd/api_compare_tests.rs +++ b/src/tool/subcommands/api_cmd/api_compare_tests.rs @@ -1757,6 +1757,49 @@ fn eth_tests_with_tipset(store: &Arc, shared_tipset: &Tipset )) .unwrap(), ), + RpcTest::identity( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_block_hash_object(block_hash.clone(), true), + )) + .unwrap(), + ), + RpcTest::identity( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_predefined(ExtPredefined::Earliest), + )) + .unwrap(), + ) + .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError), + RpcTest::basic( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_predefined(ExtPredefined::Pending), + )) + .unwrap(), + ), + RpcTest::basic( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest), + )) + .unwrap(), + ), + RpcTest::basic( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe), + )) + .unwrap(), + ), + RpcTest::basic( + EthGetTransactionCountV2::request(( + EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(), + ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized), + )) + .unwrap(), + ), RpcTest::identity( EthGetStorageAt::request(( // https://filfox.info/en/address/f410fpoidg73f7krlfohnla52dotowde5p2sejxnd4mq From 8a2c647c3d20f2b99b5c86a085513f5e435ea9dd Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 8 Jan 2026 09:35:22 +0530 Subject: [PATCH 2/4] lint fix --- src/rpc/methods/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index df938b07b71e..680308f4baaf 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -2450,7 +2450,7 @@ async fn eth_get_transaction_count( where B: Blockstore + Send + Sync + 'static, { - let (state_cid, _) = ctx.state_manager.tipset_state(&ts).await?; + let (state_cid, _) = ctx.state_manager.tipset_state(ts).await?; let state = StateTree::new_from_root(ctx.store_owned(), &state_cid)?; let actor = state.get_required_actor(&addr)?; From ba645eb8bff61554d34067048f931bc686d0604c Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 8 Jan 2026 10:25:21 +0530 Subject: [PATCH 3/4] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd1d8adcdfd1..841bb1f890fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ - [#6380](https://github.com/ChainSafe/forest/pull/6380) Implemented `Filecoin.EthFeeHistory` for API v2. +- [#6387](https://github.com/ChainSafe/forest/pull/6387) Implemented `Filecoin.EthGetTransactionCount` for API v2. + ### Changed ### Removed From 9d4d1cc027ad5c6ffdc7f992a6fe0b3222478b50 Mon Sep 17 00:00:00 2001 From: Shashank Date: Thu, 8 Jan 2026 10:25:36 +0530 Subject: [PATCH 4/4] Add test snapshot --- src/tool/subcommands/api_cmd/test_snapshots.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tool/subcommands/api_cmd/test_snapshots.txt b/src/tool/subcommands/api_cmd/test_snapshots.txt index dd34ab5e46b8..2e645609c48f 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots.txt @@ -78,6 +78,7 @@ filecoin_ethgettransactionbyblocknumberandindex_1740132538304408.rpcsnap.json.zs filecoin_ethgettransactionbyhash_1741272955520821.rpcsnap.json.zst filecoin_ethgettransactionbyhashlimited_1741272955509708.rpcsnap.json.zst filecoin_ethgettransactioncount_1740132538183426.rpcsnap.json.zst +filecoin_ethgettransactioncount_v2_1767847407595348.rpcsnap.json.zst filecoin_ethgettransactionhashbycid_1737446676698540.rpcsnap.json.zst filecoin_ethgettransactionreceipt_1741272955712904.rpcsnap.json.zst filecoin_ethgettransactionreceipt_1765811578590165.rpcsnap.json.zst # transaction not found