diff --git a/src/rpc/error.rs b/src/rpc/error.rs index 80aed93b9e19..c3c62cbcedfe 100644 --- a/src/rpc/error.rs +++ b/src/rpc/error.rs @@ -80,6 +80,10 @@ impl ServerError { Some("This method is not supported by the current version of the Forest node".into()), ) } + + pub fn inner(&self) -> &ErrorObjectOwned { + &self.inner + } } impl From for ServerError { diff --git a/src/tool/subcommands/api_cmd.rs b/src/tool/subcommands/api_cmd.rs index e3ab1868ab9b..d6dce47e9821 100644 --- a/src/tool/subcommands/api_cmd.rs +++ b/src/tool/subcommands/api_cmd.rs @@ -172,6 +172,9 @@ pub enum ApiCommands { /// only when the response from Forest is fixed and matches the response from Lotus. #[arg(long)] use_response_from: Option, + /// Allow generating snapshot even if the test fails. + #[arg(long, default_value_t = false)] + allow_failure: bool, }, /// Dumps RPC test cases for a specified API path. /// @@ -272,6 +275,7 @@ impl ApiCommands { chain, out_dir, use_response_from, + allow_failure, } => { unsafe { std::env::set_var("FOREST_TIPSET_CACHE_DISABLED", "1") }; if !out_dir.is_dir() { @@ -296,6 +300,7 @@ impl ApiCommands { tracking_db.clone(), &chain, allow_response_mismatch, + allow_failure, ) .await { diff --git a/src/tool/subcommands/api_cmd/api_compare_tests.rs b/src/tool/subcommands/api_cmd/api_compare_tests.rs index 25f81b3e687e..f5bc1f5fd2f7 100644 --- a/src/tool/subcommands/api_cmd/api_compare_tests.rs +++ b/src/tool/subcommands/api_cmd/api_compare_tests.rs @@ -201,6 +201,7 @@ pub(super) enum PolicyOnRejected { Fail, Pass, PassWithIdenticalError, + PassWithIdenticalErrorCaseInsensitive, /// If Forest reason is a subset of Lotus reason, the test passes. /// We don't always bubble up errors and format the error chain like Lotus. PassWithQuasiIdenticalError, @@ -1138,6 +1139,27 @@ 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(), + // This address should have 0 FIL + Address::from_str("t1qb2x5qctp34rxd7ucl327h5ru6aazj2heno7x5y").unwrap(), + ]; + + let mut tests = vec![]; + for wallet in prefunded_wallets { + tests.push(RpcTest::identity( + WalletBalance::request((wallet,)).unwrap(), + )); + tests.push(RpcTest::identity( + WalletValidateAddress::request((wallet.to_string(),)).unwrap(), + )); + } + let known_wallet = *KNOWN_CALIBNET_ADDRESS; // "Hello world!" signed with the above address: let signature = "44364ca78d85e53dda5ac6f719a4f2de3261c17f58558ab7730f80c478e6d43775244e7d6855afad82e4a1fd6449490acfa88e3fcfe7c1fe96ed549c100900b400"; @@ -1149,11 +1171,26 @@ fn wallet_tests(worker_address: Option
) -> Vec { _ => panic!("Invalid signature (must be bls or secp256k1)"), }; - let mut tests = vec![ - RpcTest::identity(WalletBalance::request((known_wallet,)).unwrap()), - RpcTest::identity(WalletValidateAddress::request((known_wallet.to_string(),)).unwrap()), - RpcTest::identity(WalletVerify::request((known_wallet, text, signature)).unwrap()), - ]; + tests.push(RpcTest::identity( + WalletBalance::request((known_wallet,)).unwrap(), + )); + tests.push(RpcTest::identity( + WalletValidateAddress::request((known_wallet.to_string(),)).unwrap(), + )); + tests.push( + RpcTest::identity( + // Both Forest and Lotus should fail miserably at invocking Cthulhu's name + WalletValidateAddress::request(( + "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn".to_string(), + )) + .unwrap(), + ) + // Forest returns `Unknown address network`, Lotus `unknown address network`. + .policy_on_rejected(PolicyOnRejected::PassWithIdenticalErrorCaseInsensitive), + ); + tests.push(RpcTest::identity( + WalletVerify::request((known_wallet, text, signature)).unwrap(), + )); // If a worker address is provided, we can test wallet methods requiring // a shared key. @@ -3046,6 +3083,9 @@ fn evaluate_test_success( match test.policy_on_rejected { PolicyOnRejected::Pass => true, PolicyOnRejected::PassWithIdenticalError => reason_forest == reason_lotus, + PolicyOnRejected::PassWithIdenticalErrorCaseInsensitive => { + reason_forest.to_lowercase() == reason_lotus.to_lowercase() + } PolicyOnRejected::PassWithQuasiIdenticalError => { reason_lotus.contains(reason_forest) || reason_forest.contains(reason_lotus) } diff --git a/src/tool/subcommands/api_cmd/generate_test_snapshot.rs b/src/tool/subcommands/api_cmd/generate_test_snapshot.rs index 899149fbeee6..ef00e6195572 100644 --- a/src/tool/subcommands/api_cmd/generate_test_snapshot.rs +++ b/src/tool/subcommands/api_cmd/generate_test_snapshot.rs @@ -33,6 +33,7 @@ pub async fn run_test_with_dump( db: Arc>>, chain: &NetworkChain, allow_response_mismatch: bool, + allow_failure: bool, ) -> anyhow::Result<()> { if chain.is_testnet() { CurrentNetwork::set_global(Network::Testnet); @@ -45,12 +46,21 @@ pub async fn run_test_with_dump( ($ty:ty) => { if test_dump.request.method_name.as_ref() == <$ty>::NAME { let params = <$ty>::parse_params(params_raw.clone(), ParamStructure::Either)?; - let result = <$ty>::handle(ctx.clone(), params).await?; - anyhow::ensure!( - allow_response_mismatch - || test_dump.forest_response == Ok(result.into_lotus_json_value()?), - "Response mismatch between Forest and Lotus" - ); + match <$ty>::handle(ctx.clone(), params).await { + Ok(result) => { + anyhow::ensure!( + allow_response_mismatch + || test_dump.forest_response == Ok(result.into_lotus_json_value()?), + "Response mismatch between Forest and Lotus" + ); + } + Err(_) if allow_failure => { + // If we allow failure, we do not check the error + } + Err(e) => { + bail!("Error running test {}: {}", <$ty>::NAME, e); + } + } run = true; } }; diff --git a/src/tool/subcommands/api_cmd/test_snapshot.rs b/src/tool/subcommands/api_cmd/test_snapshot.rs index 822efb0c6010..2914c5c5fec1 100644 --- a/src/tool/subcommands/api_cmd/test_snapshot.rs +++ b/src/tool/subcommands/api_cmd/test_snapshot.rs @@ -106,7 +106,7 @@ pub async fn run_test_from_snapshot(path: &Path) -> anyhow::Result<()> { let result = <$ty>::handle(ctx.clone(), params) .await .map(|r| r.into_lotus_json()) - .map_err(|e| e.to_string()); + .map_err(|e| e.inner().to_string()); let expected = match expected_response.clone() { Ok(v) => serde_json::from_value(v).map_err(|e| e.to_string()), Err(e) => Err(e), diff --git a/src/tool/subcommands/api_cmd/test_snapshots.txt b/src/tool/subcommands/api_cmd/test_snapshots.txt index 8a388ebd11b2..8007de1d90ef 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots.txt @@ -206,3 +206,18 @@ filecoin_stateverifiedregistryrootkey_1737546933391747.rpcsnap.json.zst filecoin_stateverifierstatus_1737546933391932.rpcsnap.json.zst filecoin_statevmcirculatingsupplyinternal_1737546933391364.rpcsnap.json.zst filecoin_statewaitmsg_1741784839566802.rpcsnap.json.zst +filecoin_walletbalance_1755692429792122.rpcsnap.json.zst +filecoin_walletbalance_1755692429792131.rpcsnap.json.zst +filecoin_walletbalance_1755692429792140.rpcsnap.json.zst +filecoin_walletbalance_1755692429792149.rpcsnap.json.zst +filecoin_walletbalance_1755692429792157.rpcsnap.json.zst +filecoin_walletbalance_1755692429792168.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792177.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792185.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792193.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792202.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792220.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792228.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792237.rpcsnap.json.zst +filecoin_walletvalidateaddress_1755692429792245.rpcsnap.json.zst +filecoin_walletverify_1755692429792254.rpcsnap.json.zst diff --git a/src/tool/subcommands/api_cmd/test_snapshots_ignored.txt b/src/tool/subcommands/api_cmd/test_snapshots_ignored.txt index 12c24dbf6207..e00ed4fa1c72 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots_ignored.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots_ignored.txt @@ -67,7 +67,6 @@ Filecoin.SyncCheckBad Filecoin.SyncMarkBad Filecoin.SyncSubmitBlock Filecoin.Version -Filecoin.WalletBalance Filecoin.WalletDefaultAddress Filecoin.WalletDelete Filecoin.WalletExport @@ -78,8 +77,6 @@ Filecoin.WalletNew Filecoin.WalletSetDefault Filecoin.WalletSign Filecoin.WalletSignMessage -Filecoin.WalletValidateAddress -Filecoin.WalletVerify Filecoin.Web3ClientVersion Forest.ChainExport Forest.ChainGetMinBaseFee