diff --git a/CHANGELOG.md b/CHANGELOG.md index 67790329ead6..e0b54e6116cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ - [#6312](https://github.com/ChainSafe/forest/pull/6312) Implemented `Filecoin.StateGetID` for API v2. +- [#6323](https://github.com/ChainSafe/forest/pull/6323) Implemented `Filecoin.FilecoinAddressToEthAddress` for API v1 and v2. + ### Changed ### Removed diff --git a/build.rs b/build.rs index 8fcccb6ddda4..8d6dd5d27d97 100644 --- a/build.rs +++ b/build.rs @@ -60,7 +60,10 @@ fn rpc_regression_tests_gen() { let tests: Vec<&str> = include_str!("src/tool/subcommands/api_cmd/test_snapshots.txt") .lines() - .map(str::trim) + .map(|i| { + // Remove comment + i.split("#").next().unwrap().trim() + }) .filter(|l| !l.is_empty() && !l.starts_with('#')) .collect(); let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index 650426c05ac4..cfe2bd389d79 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -2747,11 +2747,11 @@ impl RpcMethod<0> for EthSubscribe { pub enum EthAddressToFilecoinAddress {} impl RpcMethod<1> for EthAddressToFilecoinAddress { const NAME: &'static str = "Filecoin.EthAddressToFilecoinAddress"; - const NAME_ALIAS: Option<&'static str> = None; - const N_REQUIRED_PARAMS: usize = 1; const PARAM_NAMES: [&'static str; 1] = ["ethAddress"]; const API_PATHS: BitFlags = ApiPaths::all_with_v2(); const PERMISSION: Permission = Permission::Read; + const DESCRIPTION: Option<&'static str> = + Some("Converts an EthAddress into an f410 Filecoin Address"); type Params = (EthAddress,); type Ok = FilecoinAddress; async fn handle( @@ -2762,6 +2762,39 @@ impl RpcMethod<1> for EthAddressToFilecoinAddress { } } +pub enum FilecoinAddressToEthAddress {} +impl RpcMethod<2> for FilecoinAddressToEthAddress { + const NAME: &'static str = "Filecoin.FilecoinAddressToEthAddress"; + const N_REQUIRED_PARAMS: usize = 1; + const PARAM_NAMES: [&'static str; 2] = ["filecoinAddress", "blockParam"]; + const API_PATHS: BitFlags = ApiPaths::all_with_v2(); + const PERMISSION: Permission = Permission::Read; + const DESCRIPTION: Option<&'static str> = + Some("Converts any Filecoin address to an EthAddress"); + type Params = (FilecoinAddress, Option); + type Ok = EthAddress; + async fn handle( + ctx: Ctx, + (address, block_param): Self::Params, + ) -> Result { + if let Ok(eth_address) = EthAddress::from_filecoin_address(&address) { + Ok(eth_address) + } else { + let block_param = block_param.unwrap_or(BlockNumberOrPredefined::PredefinedBlock( + ExtPredefined::Finalized, + )); + let ts = tipset_by_ext_block_number_or_hash( + ctx.chain_store(), + block_param.into(), + ResolveNullTipset::TakeOlder, + )?; + + let id_address = ctx.state_manager.lookup_required_id(&address, &ts)?; + Ok(EthAddress::from_filecoin_address(&id_address)?) + } + } +} + async fn get_eth_transaction_receipt( ctx: Ctx, tx_hash: EthHash, diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index c02678ae30bf..be1c06dc45ae 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -98,6 +98,7 @@ macro_rules! for_each_rpc_method { // eth vertical $callback!($crate::rpc::eth::EthAccounts); $callback!($crate::rpc::eth::EthAddressToFilecoinAddress); + $callback!($crate::rpc::eth::FilecoinAddressToEthAddress); $callback!($crate::rpc::eth::EthBlockNumber); $callback!($crate::rpc::eth::EthCall); $callback!($crate::rpc::eth::EthChainId); diff --git a/src/tool/subcommands/api_cmd/api_compare_tests.rs b/src/tool/subcommands/api_cmd/api_compare_tests.rs index 19a073232ccf..d2919a373ecd 100644 --- a/src/tool/subcommands/api_cmd/api_compare_tests.rs +++ b/src/tool/subcommands/api_cmd/api_compare_tests.rs @@ -87,6 +87,42 @@ static KNOWN_EMPTY_CALIBNET_ADDRESS: LazyLock
= LazyLock::new(|| { .into() }); +// this is the ID address of the `t1w2zb5a723izlm4q3khclsjcnapfzxcfhvqyfoly` address +static KNOWN_CALIBNET_F0_ADDRESS: LazyLock
= LazyLock::new(|| { + crate::shim::address::Network::Testnet + .parse_address("t0168923") + .unwrap() + .into() +}); + +static KNOWN_CALIBNET_F1_ADDRESS: LazyLock
= LazyLock::new(|| { + crate::shim::address::Network::Testnet + .parse_address("t1w2zb5a723izlm4q3khclsjcnapfzxcfhvqyfoly") + .unwrap() + .into() +}); + +static KNOWN_CALIBNET_F2_ADDRESS: LazyLock
= LazyLock::new(|| { + crate::shim::address::Network::Testnet + .parse_address("t2nfplhzpyeck5dcc4fokj5ar6nbs3mhbdmq6xu3q") + .unwrap() + .into() +}); + +static KNOWN_CALIBNET_F3_ADDRESS: LazyLock
= LazyLock::new(|| { + crate::shim::address::Network::Testnet + .parse_address("t3wmbvnabsj6x2uki33phgtqqemmunnttowpx3chklrchy76pv52g5ajnaqdypxoomq5ubfk65twl5ofvkhshq") + .unwrap() + .into() +}); + +static KNOWN_CALIBNET_F4_ADDRESS: LazyLock
= LazyLock::new(|| { + crate::shim::address::Network::Testnet + .parse_address("t410fx2cumi6pgaz64varl77xbuub54bgs3k5xsvn3ki") + .unwrap() + .into() +}); + const TICKET_QUALITY_GREEDY: f64 = 0.9; const TICKET_QUALITY_OPTIMAL: f64 = 0.8; const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; @@ -1255,11 +1291,11 @@ fn state_tests_with_tipset( fn wallet_tests(worker_address: Option
) -> Vec { let prefunded_wallets = [ // the following addresses should have 666 attoFIL each - Address::from_str("t0168923").unwrap(), // this is the ID address of the `t1w2zb5a723izlm4q3khclsjcnapfzxcfhvqyfoly` address - Address::from_str("t1w2zb5a723izlm4q3khclsjcnapfzxcfhvqyfoly").unwrap(), - Address::from_str("t2nfplhzpyeck5dcc4fokj5ar6nbs3mhbdmq6xu3q").unwrap(), - Address::from_str("t3wmbvnabsj6x2uki33phgtqqemmunnttowpx3chklrchy76pv52g5ajnaqdypxoomq5ubfk65twl5ofvkhshq").unwrap(), - Address::from_str("t410fx2cumi6pgaz64varl77xbuub54bgs3k5xsvn3ki").unwrap(), + *KNOWN_CALIBNET_F0_ADDRESS, + *KNOWN_CALIBNET_F1_ADDRESS, + *KNOWN_CALIBNET_F2_ADDRESS, + *KNOWN_CALIBNET_F3_ADDRESS, + *KNOWN_CALIBNET_F4_ADDRESS, // This address should have 0 FIL *KNOWN_EMPTY_CALIBNET_ADDRESS, ]; @@ -1456,12 +1492,26 @@ fn eth_tests() -> Vec { EthUninstallFilter::request_with_alias((FilterID::new().unwrap(),), use_alias).unwrap(), )); tests.push(RpcTest::identity( - EthAddressToFilecoinAddress::request((EthAddress::from_str( - "0xff38c072f286e3b20b3954ca9f99c05fbecc64aa", - ) - .unwrap(),)) + EthAddressToFilecoinAddress::request(("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa" + .parse() + .unwrap(),)) .unwrap(), )); + tests.push(RpcTest::identity( + FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F0_ADDRESS, None)).unwrap(), + )); + tests.push(RpcTest::identity( + FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F1_ADDRESS, None)).unwrap(), + )); + tests.push(RpcTest::identity( + FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F2_ADDRESS, None)).unwrap(), + )); + tests.push(RpcTest::identity( + FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F3_ADDRESS, None)).unwrap(), + )); + tests.push(RpcTest::identity( + FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F4_ADDRESS, None)).unwrap(), + )); } tests } @@ -1936,9 +1986,27 @@ fn eth_tests_with_tipset(store: &Arc, shared_tipset: &Tipset ]; for block in shared_tipset.block_headers() { + tests.extend([RpcTest::identity( + FilecoinAddressToEthAddress::request(( + block.miner_address, + Some(BlockNumberOrPredefined::PredefinedBlock( + ExtPredefined::Latest, + )), + )) + .unwrap(), + )]); let (bls_messages, secp_messages) = crate::chain::store::block_messages(store, block).unwrap(); for msg in sample_messages(bls_messages.iter(), secp_messages.iter()) { + tests.extend([RpcTest::identity( + FilecoinAddressToEthAddress::request(( + msg.from(), + Some(BlockNumberOrPredefined::PredefinedBlock( + ExtPredefined::Latest, + )), + )) + .unwrap(), + )]); if let Ok(eth_to_addr) = msg.to.try_into() { tests.extend([RpcTest::identity( EthEstimateGas::request(( diff --git a/src/tool/subcommands/api_cmd/test_snapshot.rs b/src/tool/subcommands/api_cmd/test_snapshot.rs index e118341762bc..b47bb6448613 100644 --- a/src/tool/subcommands/api_cmd/test_snapshot.rs +++ b/src/tool/subcommands/api_cmd/test_snapshot.rs @@ -260,6 +260,8 @@ mod tests { .trim() .split("\n") .map(|i| { + // Remove comment + let i = i.split("#").next().unwrap().trim(); let captures = pattern.captures(i).expect("pattern capture failure"); captures .name("name") diff --git a/src/tool/subcommands/api_cmd/test_snapshots.txt b/src/tool/subcommands/api_cmd/test_snapshots.txt index 1d654beee276..29952cd584a2 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots.txt @@ -92,6 +92,11 @@ filecoin_evm_getstorageat_statedecodeparams_1755619756266970.rpcsnap.json.zst filecoin_evm_invokecontract_statedecodeparams_1755004924714521.rpcsnap.json.zst filecoin_evm_invokecontractdelegate_statedecodeparams_1755004924714578.rpcsnap.json.zst filecoin_evm_resurrect_statedecodeparams_1755004924714636.rpcsnap.json.zst +filecoin_filecoinaddresstoethaddress_1765291874419799.rpcsnap.json.zst # F4 address +filecoin_filecoinaddresstoethaddress_1765357908887069.rpcsnap.json.zst # F0 address +filecoin_filecoinaddresstoethaddress_1765363872743134.rpcsnap.json.zst # F1 address +filecoin_filecoinaddresstoethaddress_1765363872743268.rpcsnap.json.zst # F3 address +filecoin_filecoinaddresstoethaddress_1765363872743313.rpcsnap.json.zst # F2 address filecoin_gasestimategaslimit_1741782110512299.rpcsnap.json.zst filecoin_getactoreventsraw_1741782590255476.rpcsnap.json.zst filecoin_market_addbalance_statedecodeparams_1757426002278914.rpcsnap.json.zst