1use super::{CreateTestsArgs, ReportMode, RunIgnored, TestCriteriaOverride};
5use crate::blocks::{ElectionProof, Ticket, Tipset};
6use crate::chain::ChainStore;
7use crate::db::car::ManyCar;
8use crate::eth::{EthChainId as EthChainIdType, SAFE_EPOCH_DELAY};
9use crate::lotus_json::HasLotusJson;
10use crate::message::{Message as _, SignedMessage};
11use crate::rpc::FilterList;
12use crate::rpc::auth::AuthNewParams;
13use crate::rpc::beacon::BeaconGetEntry;
14use crate::rpc::eth::{
15 BlockNumberOrHash, EthInt64, ExtBlockNumberOrHash, ExtPredefined, Predefined,
16 new_eth_tx_from_signed_message, types::*,
17};
18use crate::rpc::gas::{GasEstimateGasLimit, GasEstimateMessageGas};
19use crate::rpc::miner::BlockTemplate;
20use crate::rpc::misc::ActorEventFilter;
21use crate::rpc::state::StateGetAllClaims;
22use crate::rpc::types::*;
23use crate::rpc::{Permission, prelude::*};
24use crate::shim::actors::MarketActorStateLoad as _;
25use crate::shim::actors::market;
26use crate::shim::executor::Receipt;
27use crate::shim::sector::SectorSize;
28use crate::shim::{
29 address::{Address, Protocol},
30 crypto::Signature,
31 econ::TokenAmount,
32 message::{METHOD_SEND, Message},
33 state_tree::StateTree,
34};
35use crate::state_manager::StateManager;
36use crate::tool::offline_server::server::handle_chain_config;
37use crate::tool::subcommands::api_cmd::NetworkChain;
38use crate::tool::subcommands::api_cmd::report::ReportBuilder;
39use crate::tool::subcommands::api_cmd::state_decode_params_tests::create_all_state_decode_params_tests;
40use crate::utils::proofs_api::{self, ensure_proof_params_downloaded};
41use crate::{Config, rpc};
42use ahash::HashMap;
43use bls_signatures::Serialize as _;
44use chrono::Utc;
45use cid::Cid;
46use fil_actors_shared::fvm_ipld_bitfield::BitField;
47use fil_actors_shared::v10::runtime::DomainSeparationTag;
48use fvm_ipld_blockstore::Blockstore;
49use ipld_core::ipld::Ipld;
50use itertools::Itertools as _;
51use jsonrpsee::types::ErrorCode;
52use libp2p::PeerId;
53use libsecp256k1::{PublicKey, SecretKey};
54use num_traits::Signed;
55use serde::de::DeserializeOwned;
56use serde::{Deserialize, Serialize};
57use serde_json::Value;
58use similar::{ChangeTag, TextDiff};
59use std::borrow::Cow;
60use std::path::Path;
61use std::time::Instant;
62use std::{
63 path::PathBuf,
64 str::FromStr,
65 sync::{Arc, LazyLock},
66 time::Duration,
67};
68use tokio::sync::Semaphore;
69use tokio::task::JoinSet;
70use tracing::debug;
71
72const COLLECTION_SAMPLE_SIZE: usize = 5;
73
74static KNOWN_CALIBNET_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
77 crate::shim::address::Network::Testnet
78 .parse_address("t1c4dkec3qhrnrsa4mccy7qntkyq2hhsma4sq7lui")
79 .unwrap()
80 .into()
81});
82
83static KNOWN_EMPTY_CALIBNET_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
85 crate::shim::address::Network::Testnet
86 .parse_address("t1qb2x5qctp34rxd7ucl327h5ru6aazj2heno7x5y")
87 .unwrap()
88 .into()
89});
90
91static KNOWN_CALIBNET_F0_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
93 crate::shim::address::Network::Testnet
94 .parse_address("t0168923")
95 .unwrap()
96 .into()
97});
98
99static KNOWN_CALIBNET_F1_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
100 crate::shim::address::Network::Testnet
101 .parse_address("t1w2zb5a723izlm4q3khclsjcnapfzxcfhvqyfoly")
102 .unwrap()
103 .into()
104});
105
106static KNOWN_CALIBNET_F2_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
107 crate::shim::address::Network::Testnet
108 .parse_address("t2nfplhzpyeck5dcc4fokj5ar6nbs3mhbdmq6xu3q")
109 .unwrap()
110 .into()
111});
112
113static KNOWN_CALIBNET_F3_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
114 crate::shim::address::Network::Testnet
115 .parse_address("t3wmbvnabsj6x2uki33phgtqqemmunnttowpx3chklrchy76pv52g5ajnaqdypxoomq5ubfk65twl5ofvkhshq")
116 .unwrap()
117 .into()
118});
119
120static KNOWN_CALIBNET_F4_ADDRESS: LazyLock<Address> = LazyLock::new(|| {
121 crate::shim::address::Network::Testnet
122 .parse_address("t410fx2cumi6pgaz64varl77xbuub54bgs3k5xsvn3ki")
123 .unwrap()
124 .into()
125});
126
127fn generate_eth_random_address() -> anyhow::Result<EthAddress> {
128 let rng = &mut crate::utils::rand::forest_os_rng();
129 let secret_key = SecretKey::random(rng);
130 let public_key = PublicKey::from_secret_key(&secret_key);
131 EthAddress::eth_address_from_pub_key(&public_key.serialize())
132}
133
134const TICKET_QUALITY_GREEDY: f64 = 0.9;
135const TICKET_QUALITY_OPTIMAL: f64 = 0.8;
136const ZERO_ADDRESS: &str = "0x0000000000000000000000000000000000000000";
137const MINER_ADDRESS: Address = Address::new_id(78216); const ACCOUNT_ADDRESS: Address = Address::new_id(1234); const EVM_ADDRESS: &str = "t410fbqoynu2oi2lxam43knqt6ordiowm2ywlml27z4i";
141
142#[derive(
144 Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize, strum::Display,
145)]
146#[serde(rename_all = "snake_case")]
147pub enum TestSummary {
148 MissingMethod,
150 Rejected(String),
152 NotJsonRPC,
154 InfraError,
156 BadJson,
158 CustomCheckFailed,
160 Timeout,
162 Valid,
164}
165
166impl TestSummary {
167 fn from_err(err: &rpc::ClientError) -> Self {
168 match err {
169 rpc::ClientError::Call(it) => match it.code().into() {
170 ErrorCode::MethodNotFound => Self::MissingMethod,
171 _ => {
172 let message = normalized_error_message(it.message());
175 Self::Rejected(message.to_string())
176 }
177 },
178 rpc::ClientError::ParseError(_) => Self::NotJsonRPC,
179 rpc::ClientError::RequestTimeout => Self::Timeout,
180 rpc::ClientError::Transport(_)
181 | rpc::ClientError::RestartNeeded(_)
182 | rpc::ClientError::InvalidSubscriptionId
183 | rpc::ClientError::InvalidRequestId(_)
184 | rpc::ClientError::Custom(_)
185 | rpc::ClientError::HttpNotImplemented
186 | rpc::ClientError::EmptyBatchRequest(_)
187 | rpc::ClientError::RegisterMethod(_) => Self::InfraError,
188 _ => unimplemented!(),
189 }
190 }
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct TestDump {
196 pub request: rpc::Request,
197 pub path: rpc::ApiPaths,
198 pub forest_response: Result<Value, String>,
199 pub lotus_response: Result<Value, String>,
200}
201
202impl std::fmt::Display for TestDump {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 writeln!(f, "Request path: {}", self.path.path())?;
205 writeln!(f, "Request dump: {:?}", self.request)?;
206 writeln!(f, "Request params JSON: {}", self.request.params)?;
207 let (forest_response, lotus_response) = (
208 self.forest_response
209 .as_ref()
210 .ok()
211 .and_then(|v| serde_json::to_string_pretty(v).ok()),
212 self.lotus_response
213 .as_ref()
214 .ok()
215 .and_then(|v| serde_json::to_string_pretty(v).ok()),
216 );
217 if let Some(forest_response) = &forest_response
218 && let Some(lotus_response) = &lotus_response
219 {
220 let diff = TextDiff::from_lines(forest_response, lotus_response);
221 let mut print_diff = Vec::new();
222 for change in diff.iter_all_changes() {
223 let sign = match change.tag() {
224 ChangeTag::Delete => "-",
225 ChangeTag::Insert => "+",
226 ChangeTag::Equal => " ",
227 };
228 print_diff.push(format!("{sign}{change}"));
229 }
230 writeln!(f, "Forest response: {forest_response}")?;
231 writeln!(f, "Lotus response: {lotus_response}")?;
232 writeln!(f, "Diff: {}", print_diff.join("\n"))?;
233 } else {
234 if let Some(forest_response) = &forest_response {
235 writeln!(f, "Forest response: {forest_response}")?;
236 }
237 if let Some(lotus_response) = &lotus_response {
238 writeln!(f, "Lotus response: {lotus_response}")?;
239 }
240 };
241 Ok(())
242 }
243}
244
245pub struct TestResult {
247 pub forest_status: TestSummary,
249 pub lotus_status: TestSummary,
251 pub test_dump: Option<TestDump>,
253 pub duration: Duration,
255}
256
257pub(super) enum PolicyOnRejected {
258 Fail,
259 Pass,
260 PassWithIdenticalError,
261 PassWithIdenticalErrorCaseInsensitive,
262 PassWithQuasiIdenticalError,
265}
266
267pub(super) enum SortPolicy {
268 All,
270}
271
272pub(super) struct RpcTest {
273 pub request: rpc::Request,
274 pub check_syntax: Arc<dyn Fn(serde_json::Value) -> bool + Send + Sync>,
275 pub check_semantics: Arc<dyn Fn(serde_json::Value, serde_json::Value) -> bool + Send + Sync>,
276 pub ignore: Option<&'static str>,
277 pub policy_on_rejected: PolicyOnRejected,
278 pub sort_policy: Option<SortPolicy>,
279}
280
281fn sort_json(value: &mut Value) {
282 match value {
283 Value::Array(arr) => {
284 for v in arr.iter_mut() {
285 sort_json(v);
286 }
287 arr.sort_by_key(|a| a.to_string());
288 }
289 Value::Object(obj) => {
290 let mut sorted_map: serde_json::Map<String, Value> = serde_json::Map::new();
291 let mut keys: Vec<String> = obj.keys().cloned().collect();
292 keys.sort();
293 for k in keys {
294 let mut v = obj.remove(&k).unwrap();
295 sort_json(&mut v);
296 sorted_map.insert(k, v);
297 }
298 *obj = sorted_map;
299 }
300 _ => (),
301 }
302}
303
304impl RpcTest {
308 fn basic<T>(request: rpc::Request<T>) -> Self
311 where
312 T: HasLotusJson,
313 {
314 Self::basic_raw(request.map_ty::<T::LotusJson>())
315 }
316 fn basic_raw<T: DeserializeOwned>(request: rpc::Request<T>) -> Self {
318 Self {
319 request: request.map_ty(),
320 check_syntax: Arc::new(|it| match serde_json::from_value::<T>(it) {
321 Ok(_) => true,
322 Err(e) => {
323 debug!(?e);
324 false
325 }
326 }),
327 check_semantics: Arc::new(|_, _| true),
328 ignore: None,
329 policy_on_rejected: PolicyOnRejected::Fail,
330 sort_policy: None,
331 }
332 }
333 fn validate<T: HasLotusJson>(
336 request: rpc::Request<T>,
337 validate: impl Fn(T, T) -> bool + Send + Sync + 'static,
338 ) -> Self {
339 Self::validate_raw(request.map_ty::<T::LotusJson>(), move |l, r| {
340 validate(T::from_lotus_json(l), T::from_lotus_json(r))
341 })
342 }
343 fn validate_raw<T: DeserializeOwned>(
345 request: rpc::Request<T>,
346 validate: impl Fn(T, T) -> bool + Send + Sync + 'static,
347 ) -> Self {
348 Self {
349 request: request.map_ty(),
350 check_syntax: Arc::new(|value| match serde_json::from_value::<T>(value) {
351 Ok(_) => true,
352 Err(e) => {
353 debug!("{e}");
354 false
355 }
356 }),
357 check_semantics: Arc::new(move |forest_json, lotus_json| {
358 match (
359 serde_json::from_value::<T>(forest_json),
360 serde_json::from_value::<T>(lotus_json),
361 ) {
362 (Ok(forest), Ok(lotus)) => validate(forest, lotus),
363 (forest, lotus) => {
364 if let Err(e) = forest {
365 debug!("[forest] invalid json: {e}");
366 }
367 if let Err(e) = lotus {
368 debug!("[lotus] invalid json: {e}");
369 }
370 false
371 }
372 }
373 }),
374 ignore: None,
375 policy_on_rejected: PolicyOnRejected::Fail,
376 sort_policy: None,
377 }
378 }
379 pub(crate) fn identity<T: PartialEq + HasLotusJson>(request: rpc::Request<T>) -> RpcTest {
382 Self::validate(request, |forest, lotus| forest == lotus)
383 }
384
385 fn ignore(mut self, msg: &'static str) -> Self {
386 self.ignore = Some(msg);
387 self
388 }
389
390 fn policy_on_rejected(mut self, policy: PolicyOnRejected) -> Self {
391 self.policy_on_rejected = policy;
392 self
393 }
394
395 fn sort_policy(mut self, policy: SortPolicy) -> Self {
396 self.sort_policy = Some(policy);
397 self
398 }
399
400 async fn run(&self, forest: &rpc::Client, lotus: &rpc::Client) -> TestResult {
401 let start = Instant::now();
402 let forest_resp = forest.call(self.request.clone()).await;
403 let forest_response = forest_resp.as_ref().map_err(|e| e.to_string()).cloned();
404 let lotus_resp = lotus.call(self.request.clone()).await;
405 let lotus_response = lotus_resp.as_ref().map_err(|e| e.to_string()).cloned();
406
407 let (forest_status, lotus_status) = match (forest_resp, lotus_resp) {
408 (Ok(forest), Ok(lotus))
409 if (self.check_syntax)(forest.clone()) && (self.check_syntax)(lotus.clone()) =>
410 {
411 let (forest, lotus) = if self.sort_policy.is_some() {
412 let mut sorted_forest = forest.clone();
413 sort_json(&mut sorted_forest);
414 let mut sorted_lotus = lotus.clone();
415 sort_json(&mut sorted_lotus);
416 (sorted_forest, sorted_lotus)
417 } else {
418 (forest, lotus)
419 };
420 let forest_status = if (self.check_semantics)(forest, lotus) {
421 TestSummary::Valid
422 } else {
423 TestSummary::CustomCheckFailed
424 };
425 (forest_status, TestSummary::Valid)
426 }
427 (forest_resp, lotus_resp) => {
428 let forest_status = forest_resp.map_or_else(
429 |e| TestSummary::from_err(&e),
430 |value| {
431 if (self.check_syntax)(value) {
432 TestSummary::Valid
433 } else {
434 TestSummary::BadJson
435 }
436 },
437 );
438 let lotus_status = lotus_resp.map_or_else(
439 |e| TestSummary::from_err(&e),
440 |value| {
441 if (self.check_syntax)(value) {
442 TestSummary::Valid
443 } else {
444 TestSummary::BadJson
445 }
446 },
447 );
448
449 (forest_status, lotus_status)
450 }
451 };
452
453 TestResult {
454 forest_status,
455 lotus_status,
456 test_dump: Some(TestDump {
457 request: self.request.clone(),
458 path: self.request.api_path().expect("invalid api paths"),
459 forest_response,
460 lotus_response,
461 }),
462 duration: start.elapsed(),
463 }
464 }
465}
466
467fn common_tests() -> Vec<RpcTest> {
468 vec![
469 RpcTest::validate(Version::request(()).unwrap(), |forest, lotus| {
471 forest.api_version == lotus.api_version && forest.block_delay == lotus.block_delay
472 }),
473 RpcTest::basic(StartTime::request(()).unwrap()),
474 RpcTest::basic(Session::request(()).unwrap()),
475 ]
476}
477
478fn chain_tests() -> Vec<RpcTest> {
479 vec![
480 RpcTest::basic(ChainHead::request(()).unwrap()),
481 RpcTest::identity(ChainGetGenesis::request(()).unwrap()),
482 ]
483}
484
485fn chain_tests_with_tipset<DB: Blockstore>(
486 store: &Arc<DB>,
487 offline: bool,
488 tipset: &Tipset,
489) -> anyhow::Result<Vec<RpcTest>> {
490 let mut tests = vec![
491 RpcTest::identity(ChainGetTipSetByHeight::request((
492 tipset.epoch(),
493 Default::default(),
494 ))?),
495 RpcTest::identity(ChainGetTipSetAfterHeight::request((
496 tipset.epoch(),
497 Default::default(),
498 ))?),
499 RpcTest::identity(ChainGetTipSet::request((tipset.key().into(),))?),
500 RpcTest::identity(ChainGetTipSet::request((None.into(),))?)
501 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
502 RpcTest::identity(ChainGetTipSetV2::request((TipsetSelector {
503 key: None.into(),
504 height: None,
505 tag: None,
506 },))?)
507 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
508 RpcTest::identity(ChainGetTipSetV2::request((TipsetSelector {
509 key: tipset.key().into(),
510 height: None,
511 tag: Some(TipsetTag::Latest),
512 },))?)
513 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
514 RpcTest::identity(ChainGetTipSetV2::request((TipsetSelector {
515 key: tipset.key().into(),
516 height: None,
517 tag: None,
518 },))?),
519 RpcTest::identity(ChainGetTipSetV2::request((TipsetSelector {
520 key: None.into(),
521 height: Some(TipsetHeight {
522 at: tipset.epoch(),
523 previous: true,
524 anchor: Some(TipsetAnchor {
525 key: None.into(),
526 tag: None,
527 }),
528 }),
529 tag: None,
530 },))?),
531 RpcTest::identity(ChainGetTipSetV2::request((TipsetSelector {
532 key: None.into(),
533 height: Some(TipsetHeight {
534 at: tipset.epoch(),
535 previous: true,
536 anchor: None,
537 }),
538 tag: None,
539 },))?)
540 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
541 .ignore("this case should pass when F3 is back on calibnet"),
542 validate_tagged_tipset_v2(
543 ChainGetTipSetV2::request((TipsetSelector {
544 key: None.into(),
545 height: None,
546 tag: Some(TipsetTag::Latest),
547 },))?,
548 offline,
549 ),
550 RpcTest::identity(ChainGetPath::request((
551 tipset.key().clone(),
552 tipset.parents().clone(),
553 ))?),
554 RpcTest::identity(ChainGetMessagesInTipset::request((tipset
555 .key()
556 .clone()
557 .into(),))?),
558 RpcTest::identity(ChainTipSetWeight::request((tipset.key().into(),))?),
559 RpcTest::basic(ChainGetFinalizedTipset::request(())?),
560 ];
561
562 if !offline {
563 tests.extend([
564 validate_tagged_tipset_v2(
566 ChainGetTipSetV2::request((TipsetSelector {
567 key: None.into(),
568 height: None,
569 tag: Some(TipsetTag::Safe),
570 },))?,
571 offline,
572 ),
573 validate_tagged_tipset_v2(
575 ChainGetTipSetV2::request((TipsetSelector {
576 key: None.into(),
577 height: None,
578 tag: Some(TipsetTag::Finalized),
579 },))?,
580 offline,
581 ),
582 ]);
583 }
584
585 for block in tipset.block_headers() {
586 let block_cid = *block.cid();
587 tests.extend([
588 RpcTest::identity(ChainReadObj::request((block_cid,))?),
589 RpcTest::identity(ChainHasObj::request((block_cid,))?),
590 RpcTest::identity(ChainGetBlock::request((block_cid,))?),
591 RpcTest::identity(ChainGetBlockMessages::request((block_cid,))?),
592 RpcTest::identity(ChainGetParentMessages::request((block_cid,))?),
593 RpcTest::identity(ChainGetParentReceipts::request((block_cid,))?),
594 RpcTest::identity(ChainStatObj::request((block.messages, None))?),
595 RpcTest::identity(ChainStatObj::request((
596 block.messages,
597 Some(block.messages),
598 ))?),
599 ]);
600
601 let (bls_messages, secp_messages) = crate::chain::store::block_messages(&store, block)?;
602 for msg_cid in sample_message_cids(bls_messages.iter(), secp_messages.iter()) {
603 tests.extend([RpcTest::identity(ChainGetMessage::request((msg_cid,))?)]);
604 }
605
606 for receipt in Receipt::get_receipts(store, block.message_receipts)? {
607 if let Some(events_root) = receipt.events_root() {
608 tests.extend([RpcTest::identity(ChainGetEvents::request((events_root,))?)
609 .sort_policy(SortPolicy::All)]);
610 }
611 }
612 }
613
614 Ok(tests)
615}
616
617fn auth_tests() -> anyhow::Result<Vec<RpcTest>> {
618 Ok(vec![
620 RpcTest::basic(AuthNew::request((
621 AuthNewParams::process_perms(Permission::Admin.to_string())?,
622 None,
623 ))?),
624 RpcTest::basic(AuthNew::request((
625 AuthNewParams::process_perms(Permission::Sign.to_string())?,
626 None,
627 ))?),
628 RpcTest::basic(AuthNew::request((
629 AuthNewParams::process_perms(Permission::Write.to_string())?,
630 None,
631 ))?),
632 RpcTest::basic(AuthNew::request((
633 AuthNewParams::process_perms(Permission::Read.to_string())?,
634 None,
635 ))?),
636 ])
637}
638
639fn mpool_tests() -> Vec<RpcTest> {
640 vec![
641 RpcTest::identity(MpoolGetNonce::request((*KNOWN_CALIBNET_ADDRESS,)).unwrap()),
642 RpcTest::identity(MpoolGetNonce::request((*KNOWN_EMPTY_CALIBNET_ADDRESS,)).unwrap())
651 .policy_on_rejected(PolicyOnRejected::Pass),
652 RpcTest::basic(MpoolPending::request((ApiTipsetKey(None),)).unwrap()),
653 RpcTest::basic(MpoolSelect::request((ApiTipsetKey(None), TICKET_QUALITY_GREEDY)).unwrap()),
654 RpcTest::basic(MpoolSelect::request((ApiTipsetKey(None), TICKET_QUALITY_OPTIMAL)).unwrap())
655 .ignore("https://github.com/ChainSafe/forest/issues/4490"),
656 ]
657}
658
659fn mpool_tests_with_tipset(tipset: &Tipset) -> Vec<RpcTest> {
660 vec![
661 RpcTest::basic(MpoolPending::request((tipset.key().into(),)).unwrap()),
662 RpcTest::basic(MpoolSelect::request((tipset.key().into(), TICKET_QUALITY_GREEDY)).unwrap()),
663 RpcTest::basic(
664 MpoolSelect::request((tipset.key().into(), TICKET_QUALITY_OPTIMAL)).unwrap(),
665 )
666 .ignore("https://github.com/ChainSafe/forest/issues/4490"),
667 ]
668}
669
670fn net_tests() -> Vec<RpcTest> {
671 vec![
674 RpcTest::basic(NetAddrsListen::request(()).unwrap()),
675 RpcTest::basic(NetPeers::request(()).unwrap()),
676 RpcTest::identity(NetListening::request(()).unwrap()),
677 RpcTest::basic(NetAgentVersion::request((PeerId::random().to_string(),)).unwrap())
679 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
680 RpcTest::basic(NetFindPeer::request((PeerId::random().to_string(),)).unwrap())
681 .policy_on_rejected(PolicyOnRejected::Pass)
682 .ignore("It times out in lotus when peer not found"),
683 RpcTest::basic(NetInfo::request(()).unwrap())
684 .ignore("Not implemented in Lotus. Why do we even have this method?"),
685 RpcTest::basic(NetAutoNatStatus::request(()).unwrap()),
686 RpcTest::identity(NetVersion::request(()).unwrap()),
687 RpcTest::identity(NetProtectAdd::request((vec![PeerId::random().to_string()],)).unwrap()),
688 RpcTest::identity(
689 NetProtectRemove::request((vec![PeerId::random().to_string()],)).unwrap(),
690 ),
691 RpcTest::basic(NetProtectList::request(()).unwrap()),
692 ]
693}
694
695fn node_tests() -> Vec<RpcTest> {
696 vec![
697 ]
701}
702
703fn event_tests_with_tipset<DB: Blockstore>(_store: &Arc<DB>, tipset: &Tipset) -> Vec<RpcTest> {
704 let epoch = tipset.epoch();
705 vec![
706 RpcTest::identity(GetActorEventsRaw::request((None,)).unwrap())
707 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
708 RpcTest::identity(
709 GetActorEventsRaw::request((Some(ActorEventFilter {
710 addresses: vec![],
711 fields: Default::default(),
712 from_height: Some(epoch),
713 to_height: Some(epoch),
714 tipset_key: None,
715 }),))
716 .unwrap(),
717 )
718 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
719 .sort_policy(SortPolicy::All),
720 RpcTest::identity(
721 GetActorEventsRaw::request((Some(ActorEventFilter {
722 addresses: vec![],
723 fields: Default::default(),
724 from_height: Some(epoch - 100),
725 to_height: Some(epoch),
726 tipset_key: None,
727 }),))
728 .unwrap(),
729 )
730 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
731 .sort_policy(SortPolicy::All),
732 RpcTest::identity(
733 GetActorEventsRaw::request((Some(ActorEventFilter {
734 addresses: vec![],
735 fields: Default::default(),
736 from_height: None,
737 to_height: None,
738 tipset_key: Some(tipset.key().clone().into()),
739 }),))
740 .unwrap(),
741 )
742 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
743 .sort_policy(SortPolicy::All),
744 RpcTest::identity(
745 GetActorEventsRaw::request((Some(ActorEventFilter {
746 addresses: vec![
747 Address::from_str("t410fvtakbtytk4otbnfymn4zn5ow252nj7lcpbtersq")
748 .unwrap()
749 .into(),
750 ],
751 fields: Default::default(),
752 from_height: Some(epoch - 100),
753 to_height: Some(epoch),
754 tipset_key: None,
755 }),))
756 .unwrap(),
757 )
758 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
759 .sort_policy(SortPolicy::All),
760 {
761 use std::collections::BTreeMap;
762
763 use base64::{Engine, prelude::BASE64_STANDARD};
764
765 use crate::lotus_json::LotusJson;
766 use crate::rpc::misc::ActorEventBlock;
767
768 let topic = BASE64_STANDARD
769 .decode("0Gprf0kYSUs3GSF9GAJ4bB9REqbB2I/iz+wAtFhPauw=")
770 .unwrap();
771 let mut fields: BTreeMap<String, Vec<ActorEventBlock>> = Default::default();
772 fields.insert(
773 "t1".into(),
774 vec![ActorEventBlock {
775 codec: 85,
776 value: LotusJson(topic),
777 }],
778 );
779 RpcTest::identity(
780 GetActorEventsRaw::request((Some(ActorEventFilter {
781 addresses: vec![],
782 fields,
783 from_height: Some(epoch - 100),
784 to_height: Some(epoch),
785 tipset_key: None,
786 }),))
787 .unwrap(),
788 )
789 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError)
790 .sort_policy(SortPolicy::All)
791 },
792 ]
793}
794
795fn miner_tests_with_tipset<DB: Blockstore>(
796 store: &Arc<DB>,
797 tipset: &Tipset,
798 miner_address: Option<Address>,
799) -> anyhow::Result<Vec<RpcTest>> {
800 let Some(miner_address) = miner_address else {
802 return Ok(vec![]);
803 };
804
805 let mut tests = Vec::new();
806 for block in tipset.block_headers() {
807 let (bls_messages, secp_messages) = crate::chain::store::block_messages(store, block)?;
808 tests.push(miner_create_block_test(
809 miner_address,
810 tipset,
811 bls_messages,
812 secp_messages,
813 ));
814 }
815 tests.push(miner_create_block_no_messages_test(miner_address, tipset));
816 Ok(tests)
817}
818
819fn miner_create_block_test(
820 miner: Address,
821 tipset: &Tipset,
822 bls_messages: Vec<Message>,
823 secp_messages: Vec<SignedMessage>,
824) -> RpcTest {
825 let priv_key = bls_signatures::PrivateKey::generate(&mut crate::utils::rand::forest_rng());
827 let signed_bls_msgs = bls_messages
828 .into_iter()
829 .map(|message| {
830 let sig = priv_key.sign(message.cid().to_bytes());
831 SignedMessage {
832 message,
833 signature: Signature::new_bls(sig.as_bytes().to_vec()),
834 }
835 })
836 .collect_vec();
837
838 let block_template = BlockTemplate {
839 miner,
840 parents: tipset.parents().to_owned(),
841 ticket: Ticket::default(),
842 eproof: ElectionProof::default(),
843 beacon_values: tipset.block_headers().first().beacon_entries.to_owned(),
844 messages: [signed_bls_msgs, secp_messages].concat(),
845 epoch: tipset.epoch(),
846 timestamp: tipset.min_timestamp(),
847 winning_post_proof: Vec::default(),
848 };
849 RpcTest::identity(MinerCreateBlock::request((block_template,)).unwrap())
850}
851
852fn miner_create_block_no_messages_test(miner: Address, tipset: &Tipset) -> RpcTest {
853 let block_template = BlockTemplate {
854 miner,
855 parents: tipset.parents().to_owned(),
856 ticket: Ticket::default(),
857 eproof: ElectionProof::default(),
858 beacon_values: tipset.block_headers().first().beacon_entries.to_owned(),
859 messages: Vec::default(),
860 epoch: tipset.epoch(),
861 timestamp: tipset.min_timestamp(),
862 winning_post_proof: Vec::default(),
863 };
864 RpcTest::identity(MinerCreateBlock::request((block_template,)).unwrap())
865}
866
867fn state_tests_with_tipset<DB: Blockstore>(
868 store: &Arc<DB>,
869 tipset: &Tipset,
870) -> anyhow::Result<Vec<RpcTest>> {
871 let mut tests = vec![
872 RpcTest::identity(StateNetworkName::request(())?),
873 RpcTest::identity(StateGetNetworkParams::request(())?),
874 RpcTest::identity(StateMinerInitialPledgeForSector::request((
875 1,
876 SectorSize::_32GiB,
877 1024,
878 tipset.key().into(),
879 ))?),
880 RpcTest::identity(StateGetActor::request((
881 Address::SYSTEM_ACTOR,
882 tipset.key().into(),
883 ))?),
884 RpcTest::identity(StateGetActorV2::request((
885 Address::SYSTEM_ACTOR,
886 TipsetSelector {
887 key: tipset.key().into(),
888 ..Default::default()
889 },
890 ))?),
891 RpcTest::identity(StateGetID::request((
892 Address::SYSTEM_ACTOR,
893 TipsetSelector {
894 key: tipset.key().into(),
895 ..Default::default()
896 },
897 ))?),
898 RpcTest::identity(StateGetRandomnessFromTickets::request((
899 DomainSeparationTag::ElectionProofProduction as i64,
900 tipset.epoch(),
901 "dead beef".as_bytes().to_vec(),
902 tipset.key().into(),
903 ))?),
904 RpcTest::identity(StateGetRandomnessDigestFromTickets::request((
905 tipset.epoch(),
906 tipset.key().into(),
907 ))?),
908 RpcTest::identity(StateGetRandomnessFromBeacon::request((
909 DomainSeparationTag::ElectionProofProduction as i64,
910 tipset.epoch(),
911 "dead beef".as_bytes().to_vec(),
912 tipset.key().into(),
913 ))?),
914 RpcTest::identity(StateGetRandomnessDigestFromBeacon::request((
915 tipset.epoch(),
916 tipset.key().into(),
917 ))?),
918 RpcTest::identity(StateLookupID::request((
920 Address::new_id(0xdeadbeef),
921 tipset.key().into(),
922 ))?),
923 RpcTest::identity(StateVerifiedRegistryRootKey::request((tipset
924 .key()
925 .into(),))?),
926 RpcTest::identity(StateVerifierStatus::request((
927 Address::VERIFIED_REGISTRY_ACTOR,
928 tipset.key().into(),
929 ))?),
930 RpcTest::identity(StateNetworkVersion::request((tipset.key().into(),))?),
931 RpcTest::identity(StateListMiners::request((tipset.key().into(),))?),
932 RpcTest::identity(StateListActors::request((tipset.key().into(),))?),
933 RpcTest::identity(MsigGetAvailableBalance::request((
934 Address::new_id(18101), tipset.key().into(),
936 ))?),
937 RpcTest::identity(MsigGetPending::request((
938 Address::new_id(18101), tipset.key().into(),
940 ))?),
941 RpcTest::identity(MsigGetVested::request((
942 Address::new_id(18101), tipset.parents().into(),
944 tipset.key().into(),
945 ))?),
946 RpcTest::identity(MsigGetVestingSchedule::request((
947 Address::new_id(18101), tipset.key().into(),
949 ))?),
950 RpcTest::identity(BeaconGetEntry::request((tipset.epoch(),))?),
951 RpcTest::identity(StateGetBeaconEntry::request((tipset.epoch(),))?),
952 RpcTest::identity(StateVerifiedClientStatus::request((
956 Address::VERIFIED_REGISTRY_ACTOR,
957 tipset.key().into(),
958 ))?),
959 RpcTest::identity(StateVerifiedClientStatus::request((
960 Address::DATACAP_TOKEN_ACTOR,
961 tipset.key().into(),
962 ))?),
963 RpcTest::identity(StateDealProviderCollateralBounds::request((
964 1,
965 true,
966 tipset.key().into(),
967 ))?),
968 RpcTest::identity(StateCirculatingSupply::request((tipset.key().into(),))?),
969 RpcTest::identity(StateVMCirculatingSupplyInternal::request((tipset
970 .key()
971 .into(),))?),
972 RpcTest::identity(StateMarketParticipants::request((tipset.key().into(),))?),
973 RpcTest::identity(StateMarketDeals::request((tipset.key().into(),))?),
974 RpcTest::identity(StateSectorPreCommitInfo::request((
975 Default::default(), u16::MAX as _,
977 tipset.key().into(),
978 ))?)
979 .policy_on_rejected(PolicyOnRejected::Pass),
980 RpcTest::identity(StateSectorGetInfo::request((
981 Default::default(), u16::MAX as _, tipset.key().into(),
984 ))?)
985 .policy_on_rejected(PolicyOnRejected::Pass),
986 RpcTest::identity(StateGetAllocationIdForPendingDeal::request((
987 u16::MAX as _, tipset.key().into(),
989 ))?),
990 RpcTest::identity(StateGetAllocationForPendingDeal::request((
991 u16::MAX as _, tipset.key().into(),
993 ))?),
994 RpcTest::identity(StateCompute::request((
995 tipset.epoch(),
996 vec![],
997 tipset.key().into(),
998 ))?),
999 ];
1000
1001 tests.extend(read_state_api_tests(tipset)?);
1002 tests.extend(create_all_state_decode_params_tests(tipset)?);
1003
1004 for &pending_deal_id in
1005 StateGetAllocationIdForPendingDeal::get_allocations_for_pending_deals(store, tipset)?
1006 .keys()
1007 .take(COLLECTION_SAMPLE_SIZE)
1008 {
1009 tests.extend([
1010 RpcTest::identity(StateGetAllocationIdForPendingDeal::request((
1011 pending_deal_id,
1012 tipset.key().into(),
1013 ))?),
1014 RpcTest::identity(StateGetAllocationForPendingDeal::request((
1015 pending_deal_id,
1016 tipset.key().into(),
1017 ))?),
1018 ]);
1019 }
1020
1021 let (deals, deals_map) = {
1023 let state = StateTree::new_from_root(store.clone(), tipset.parent_state())?;
1024 let actor = state.get_required_actor(&Address::MARKET_ACTOR)?;
1025 let market_state = market::State::load(&store, actor.code, actor.state)?;
1026 let proposals = market_state.proposals(&store)?;
1027 let mut deals = vec![];
1028 let mut deals_map = HashMap::default();
1029 proposals.for_each(|deal_id, deal_proposal| {
1030 deals.push(deal_id);
1031 deals_map.insert(deal_id, deal_proposal);
1032 Ok(())
1033 })?;
1034 (deals, deals_map)
1035 };
1036
1037 for deal in deals.into_iter().take(COLLECTION_SAMPLE_SIZE) {
1039 tests.push(RpcTest::identity(StateMarketStorageDeal::request((
1040 deal,
1041 tipset.key().into(),
1042 ))?));
1043 }
1044
1045 for block in tipset.block_headers() {
1046 tests.extend([
1047 RpcTest::identity(StateMinerAllocated::request((
1048 block.miner_address,
1049 tipset.key().into(),
1050 ))?),
1051 RpcTest::identity(StateMinerActiveSectors::request((
1052 block.miner_address,
1053 tipset.key().into(),
1054 ))?),
1055 RpcTest::identity(StateLookupID::request((
1056 block.miner_address,
1057 tipset.key().into(),
1058 ))?),
1059 RpcTest::identity(StateLookupRobustAddress::request((
1060 block.miner_address,
1061 tipset.key().into(),
1062 ))?),
1063 RpcTest::identity(StateMinerSectors::request((
1064 block.miner_address,
1065 None,
1066 tipset.key().into(),
1067 ))?),
1068 RpcTest::identity(StateMinerPartitions::request((
1069 block.miner_address,
1070 0,
1071 tipset.key().into(),
1072 ))?),
1073 RpcTest::identity(StateMarketBalance::request((
1074 block.miner_address,
1075 tipset.key().into(),
1076 ))?),
1077 RpcTest::identity(StateMinerInfo::request((
1078 block.miner_address,
1079 tipset.key().into(),
1080 ))?),
1081 RpcTest::identity(StateMinerPower::request((
1082 block.miner_address,
1083 tipset.key().into(),
1084 ))?),
1085 RpcTest::identity(StateMinerDeadlines::request((
1086 block.miner_address,
1087 tipset.key().into(),
1088 ))?),
1089 RpcTest::identity(StateMinerProvingDeadline::request((
1090 block.miner_address,
1091 tipset.key().into(),
1092 ))?),
1093 RpcTest::identity(StateMinerAvailableBalance::request((
1094 block.miner_address,
1095 tipset.key().into(),
1096 ))?),
1097 RpcTest::identity(StateMinerFaults::request((
1098 block.miner_address,
1099 tipset.key().into(),
1100 ))?),
1101 RpcTest::identity(MinerGetBaseInfo::request((
1102 block.miner_address,
1103 block.epoch,
1104 tipset.key().into(),
1105 ))?),
1106 RpcTest::identity(StateMinerRecoveries::request((
1107 block.miner_address,
1108 tipset.key().into(),
1109 ))?),
1110 RpcTest::identity(StateMinerSectorCount::request((
1111 block.miner_address,
1112 tipset.key().into(),
1113 ))?),
1114 RpcTest::identity(StateGetClaims::request((
1115 block.miner_address,
1116 tipset.key().into(),
1117 ))?),
1118 RpcTest::identity(StateGetAllClaims::request((tipset.key().into(),))?),
1119 RpcTest::identity(StateGetAllAllocations::request((tipset.key().into(),))?),
1120 RpcTest::identity(StateSectorPreCommitInfo::request((
1121 block.miner_address,
1122 u16::MAX as _, tipset.key().into(),
1124 ))?)
1125 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1126 RpcTest::identity(StateSectorGetInfo::request((
1127 block.miner_address,
1128 u16::MAX as _, tipset.key().into(),
1130 ))?)
1131 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1132 ]);
1133 for claim_id in StateGetClaims::get_claims(store, &block.miner_address, tipset)?
1134 .keys()
1135 .take(COLLECTION_SAMPLE_SIZE)
1136 {
1137 tests.extend([RpcTest::identity(StateGetClaim::request((
1138 block.miner_address,
1139 *claim_id,
1140 tipset.key().into(),
1141 ))?)]);
1142 }
1143 for address in StateGetAllocations::get_valid_actor_addresses(store, tipset)?
1144 .take(COLLECTION_SAMPLE_SIZE)
1145 {
1146 tests.extend([RpcTest::identity(StateGetAllocations::request((
1147 address,
1148 tipset.key().into(),
1149 ))?)]);
1150 for allocation_id in StateGetAllocations::get_allocations(store, &address, tipset)?
1151 .keys()
1152 .take(COLLECTION_SAMPLE_SIZE)
1153 {
1154 tests.extend([RpcTest::identity(StateGetAllocation::request((
1155 address,
1156 *allocation_id,
1157 tipset.key().into(),
1158 ))?)]);
1159 }
1160 }
1161 for sector in StateSectorGetInfo::get_sectors(store, &block.miner_address, tipset)?
1162 .into_iter()
1163 .take(COLLECTION_SAMPLE_SIZE)
1164 {
1165 tests.extend([
1166 RpcTest::identity(StateSectorGetInfo::request((
1167 block.miner_address,
1168 sector,
1169 tipset.key().into(),
1170 ))?),
1171 RpcTest::identity(StateMinerSectors::request((
1172 block.miner_address,
1173 {
1174 let mut bf = BitField::new();
1175 bf.set(sector);
1176 Some(bf)
1177 },
1178 tipset.key().into(),
1179 ))?),
1180 RpcTest::identity(StateSectorExpiration::request((
1181 block.miner_address,
1182 sector,
1183 tipset.key().into(),
1184 ))?)
1185 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1186 RpcTest::identity(StateSectorPartition::request((
1187 block.miner_address,
1188 sector,
1189 tipset.key().into(),
1190 ))?),
1191 RpcTest::identity(StateMinerSectorAllocated::request((
1192 block.miner_address,
1193 sector,
1194 tipset.key().into(),
1195 ))?),
1196 ]);
1197 }
1198 for sector in StateSectorPreCommitInfo::get_sectors(store, &block.miner_address, tipset)?
1199 .into_iter()
1200 .take(COLLECTION_SAMPLE_SIZE)
1201 {
1202 tests.extend([RpcTest::identity(StateSectorPreCommitInfo::request((
1203 block.miner_address,
1204 sector,
1205 tipset.key().into(),
1206 ))?)]);
1207 }
1208 for info in StateSectorPreCommitInfo::get_sector_pre_commit_infos(
1209 store,
1210 &block.miner_address,
1211 tipset,
1212 )?
1213 .into_iter()
1214 .take(COLLECTION_SAMPLE_SIZE)
1215 .filter(|info| {
1216 !info.deal_ids.iter().any(|id| {
1217 if let Some(Ok(deal)) = deals_map.get(id) {
1218 tipset.epoch() > deal.start_epoch || info.expiration > deal.end_epoch
1219 } else {
1220 true
1221 }
1222 })
1223 }) {
1224 tests.extend([RpcTest::identity(
1225 StateMinerInitialPledgeCollateral::request((
1226 block.miner_address,
1227 info.clone(),
1228 tipset.key().into(),
1229 ))?,
1230 )]);
1231 tests.extend([RpcTest::identity(
1232 StateMinerPreCommitDepositForPower::request((
1233 block.miner_address,
1234 info,
1235 tipset.key().into(),
1236 ))?,
1237 )]);
1238 }
1239
1240 let (bls_messages, secp_messages) = crate::chain::store::block_messages(store, block)?;
1241 for msg_cid in sample_message_cids(bls_messages.iter(), secp_messages.iter()) {
1242 tests.extend([
1243 RpcTest::identity(StateReplay::request((tipset.key().into(), msg_cid))?),
1244 validate_message_lookup(
1245 StateWaitMsg::request((msg_cid, 0, 10101, true))?
1246 .with_timeout(Duration::from_secs(15)),
1247 ),
1248 validate_message_lookup(
1249 StateWaitMsg::request((msg_cid, 0, 10101, false))?
1250 .with_timeout(Duration::from_secs(15)),
1251 ),
1252 validate_message_lookup(StateSearchMsg::request((
1253 None.into(),
1254 msg_cid,
1255 800,
1256 true,
1257 ))?),
1258 validate_message_lookup(StateSearchMsg::request((
1259 None.into(),
1260 msg_cid,
1261 800,
1262 false,
1263 ))?),
1264 validate_message_lookup(StateSearchMsgLimited::request((msg_cid, 800))?),
1265 ]);
1266 }
1267 for msg in sample_messages(bls_messages.iter(), secp_messages.iter()) {
1268 tests.extend([
1269 RpcTest::identity(StateAccountKey::request((msg.from(), tipset.key().into()))?),
1270 RpcTest::identity(StateAccountKey::request((msg.from(), Default::default()))?),
1271 RpcTest::identity(StateLookupID::request((msg.from(), tipset.key().into()))?),
1272 RpcTest::identity(StateListMessages::request((
1273 MessageFilter {
1274 from: Some(msg.from()),
1275 to: Some(msg.to()),
1276 },
1277 tipset.key().into(),
1278 tipset.epoch(),
1279 ))?),
1280 RpcTest::identity(StateListMessages::request((
1281 MessageFilter {
1282 from: Some(msg.from()),
1283 to: None,
1284 },
1285 tipset.key().into(),
1286 tipset.epoch(),
1287 ))?),
1288 RpcTest::identity(StateListMessages::request((
1289 MessageFilter {
1290 from: None,
1291 to: Some(msg.to()),
1292 },
1293 tipset.key().into(),
1294 tipset.epoch(),
1295 ))?),
1296 RpcTest::identity(StateCall::request((msg.clone(), tipset.key().into()))?),
1297 ]);
1298 }
1299 }
1300
1301 Ok(tests)
1302}
1303
1304fn wallet_tests(worker_address: Option<Address>) -> Vec<RpcTest> {
1305 let prefunded_wallets = [
1306 *KNOWN_CALIBNET_F0_ADDRESS,
1308 *KNOWN_CALIBNET_F1_ADDRESS,
1309 *KNOWN_CALIBNET_F2_ADDRESS,
1310 *KNOWN_CALIBNET_F3_ADDRESS,
1311 *KNOWN_CALIBNET_F4_ADDRESS,
1312 *KNOWN_EMPTY_CALIBNET_ADDRESS,
1314 ];
1315
1316 let mut tests = vec![];
1317 for wallet in prefunded_wallets {
1318 tests.push(RpcTest::identity(
1319 WalletBalance::request((wallet,)).unwrap(),
1320 ));
1321 tests.push(RpcTest::identity(
1322 WalletValidateAddress::request((wallet.to_string(),)).unwrap(),
1323 ));
1324 }
1325
1326 let known_wallet = *KNOWN_CALIBNET_ADDRESS;
1327 let signature = "44364ca78d85e53dda5ac6f719a4f2de3261c17f58558ab7730f80c478e6d43775244e7d6855afad82e4a1fd6449490acfa88e3fcfe7c1fe96ed549c100900b400";
1329 let text = "Hello world!".as_bytes().to_vec();
1330 let sig_bytes = hex::decode(signature).unwrap();
1331 let signature = match known_wallet.protocol() {
1332 Protocol::Secp256k1 => Signature::new_secp256k1(sig_bytes),
1333 Protocol::BLS => Signature::new_bls(sig_bytes),
1334 _ => panic!("Invalid signature (must be bls or secp256k1)"),
1335 };
1336
1337 tests.push(RpcTest::identity(
1338 WalletBalance::request((known_wallet,)).unwrap(),
1339 ));
1340 tests.push(RpcTest::identity(
1341 WalletValidateAddress::request((known_wallet.to_string(),)).unwrap(),
1342 ));
1343 tests.push(
1344 RpcTest::identity(
1345 WalletValidateAddress::request((
1347 "Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn".to_string(),
1348 ))
1349 .unwrap(),
1350 )
1351 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalErrorCaseInsensitive),
1353 );
1354 tests.push(RpcTest::identity(
1355 WalletVerify::request((known_wallet, text, signature)).unwrap(),
1356 ));
1357
1358 if let Some(worker_address) = worker_address {
1361 use base64::{Engine, prelude::BASE64_STANDARD};
1362 let msg =
1363 BASE64_STANDARD.encode("Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn".as_bytes());
1364 tests.push(RpcTest::identity(
1365 WalletSign::request((worker_address, msg.into())).unwrap(),
1366 ));
1367 tests.push(RpcTest::identity(
1368 WalletSign::request((worker_address, Vec::new())).unwrap(),
1369 ));
1370 let msg: Message = Message {
1371 from: worker_address,
1372 to: worker_address,
1373 value: TokenAmount::from_whole(1),
1374 method_num: METHOD_SEND,
1375 ..Default::default()
1376 };
1377 tests.push(RpcTest::identity(
1378 WalletSignMessage::request((worker_address, msg)).unwrap(),
1379 ));
1380 }
1381 tests
1382}
1383
1384fn eth_tests() -> Vec<RpcTest> {
1385 let mut tests = vec![];
1386 for use_alias in [false, true] {
1387 tests.push(RpcTest::identity(
1388 EthAccounts::request_with_alias((), use_alias).unwrap(),
1389 ));
1390 tests.push(RpcTest::basic(
1391 EthBlockNumber::request_with_alias((), use_alias).unwrap(),
1392 ));
1393 tests.push(RpcTest::identity(
1394 EthChainId::request_with_alias((), use_alias).unwrap(),
1395 ));
1396 tests.push(RpcTest::validate(
1398 EthGasPrice::request_with_alias((), use_alias).unwrap(),
1399 |forest, lotus| forest.0.is_positive() && lotus.0.is_positive(),
1400 ));
1401 tests.push(RpcTest::basic(
1402 EthSyncing::request_with_alias((), use_alias).unwrap(),
1403 ));
1404 tests.push(RpcTest::identity(
1405 EthGetBalance::request_with_alias(
1406 (
1407 EthAddress::from_str("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa").unwrap(),
1408 BlockNumberOrHash::from_predefined(Predefined::Latest),
1409 ),
1410 use_alias,
1411 )
1412 .unwrap(),
1413 ));
1414 tests.push(RpcTest::identity(
1415 EthGetBalance::request_with_alias(
1416 (
1417 EthAddress::from_str("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa").unwrap(),
1418 BlockNumberOrHash::from_predefined(Predefined::Pending),
1419 ),
1420 use_alias,
1421 )
1422 .unwrap(),
1423 ));
1424 tests.push(RpcTest::basic(
1425 Web3ClientVersion::request_with_alias((), use_alias).unwrap(),
1426 ));
1427 tests.push(RpcTest::basic(
1428 EthMaxPriorityFeePerGas::request_with_alias((), use_alias).unwrap(),
1429 ));
1430 tests.push(RpcTest::identity(
1431 EthProtocolVersion::request_with_alias((), use_alias).unwrap(),
1432 ));
1433
1434 let cases = [
1435 (
1436 Some(EthAddress::from_str("0x0c1d86d34e469770339b53613f3a2343accd62cb").unwrap()),
1437 Some(
1438 "0xf8b2cb4f000000000000000000000000CbfF24DED1CE6B53712078759233Ac8f91ea71B6"
1439 .parse()
1440 .unwrap(),
1441 ),
1442 ),
1443 (Some(EthAddress::from_str(ZERO_ADDRESS).unwrap()), None),
1444 (
1447 None,
1448 Some(
1449 EthBytes::from_str(
1450 concat!("0x", include_str!("contracts/cthulhu/invoke.hex")).trim(),
1451 )
1452 .unwrap(),
1453 ),
1454 ),
1455 ];
1456
1457 for (to, data) in cases {
1458 let msg = EthCallMessage {
1459 to,
1460 data: data.clone(),
1461 ..EthCallMessage::default()
1462 };
1463
1464 tests.push(RpcTest::identity(
1465 EthCall::request_with_alias(
1466 (
1467 msg.clone(),
1468 BlockNumberOrHash::from_predefined(Predefined::Latest),
1469 ),
1470 use_alias,
1471 )
1472 .unwrap(),
1473 ));
1474
1475 for tag in [
1476 ExtPredefined::Latest,
1477 ExtPredefined::Safe,
1478 ExtPredefined::Finalized,
1479 ] {
1480 tests.push(RpcTest::identity(
1481 EthCallV2::request_with_alias(
1482 (msg.clone(), ExtBlockNumberOrHash::PredefinedBlock(tag)),
1483 use_alias,
1484 )
1485 .unwrap(),
1486 ));
1487 }
1488 }
1489
1490 let cases = [
1491 Some(EthAddressList::List(vec![])),
1492 Some(EthAddressList::List(vec![
1493 EthAddress::from_str("0x0c1d86d34e469770339b53613f3a2343accd62cb").unwrap(),
1494 EthAddress::from_str("0x89beb26addec4bc7e9f475aacfd084300d6de719").unwrap(),
1495 ])),
1496 Some(EthAddressList::Single(
1497 EthAddress::from_str("0x0c1d86d34e469770339b53613f3a2343accd62cb").unwrap(),
1498 )),
1499 None,
1500 ];
1501
1502 for address in cases {
1503 tests.push(RpcTest::basic(
1504 EthNewFilter::request_with_alias(
1505 (EthFilterSpec {
1506 address,
1507 ..Default::default()
1508 },),
1509 use_alias,
1510 )
1511 .unwrap(),
1512 ));
1513 }
1514 tests.push(RpcTest::basic(
1515 EthNewPendingTransactionFilter::request_with_alias((), use_alias).unwrap(),
1516 ));
1517 tests.push(RpcTest::basic(
1518 EthNewBlockFilter::request_with_alias((), use_alias).unwrap(),
1519 ));
1520 tests.push(RpcTest::identity(
1521 EthUninstallFilter::request_with_alias((FilterID::new().unwrap(),), use_alias).unwrap(),
1522 ));
1523 tests.push(RpcTest::identity(
1524 EthAddressToFilecoinAddress::request(("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa"
1525 .parse()
1526 .unwrap(),))
1527 .unwrap(),
1528 ));
1529 tests.push(RpcTest::identity(
1530 FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F0_ADDRESS, None)).unwrap(),
1531 ));
1532 tests.push(RpcTest::identity(
1533 FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F1_ADDRESS, None)).unwrap(),
1534 ));
1535 tests.push(RpcTest::identity(
1536 FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F2_ADDRESS, None)).unwrap(),
1537 ));
1538 tests.push(RpcTest::identity(
1539 FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F3_ADDRESS, None)).unwrap(),
1540 ));
1541 tests.push(RpcTest::identity(
1542 FilecoinAddressToEthAddress::request((*KNOWN_CALIBNET_F4_ADDRESS, None)).unwrap(),
1543 ));
1544 }
1545 tests
1546}
1547
1548fn eth_call_api_err_tests(epoch: i64) -> Vec<RpcTest> {
1549 let contract_codes = [
1550 include_str!("./contracts/arithmetic_err/arithmetic_overflow_err.hex"),
1551 include_str!("contracts/assert_err/assert_err.hex"),
1552 include_str!("./contracts/divide_by_zero_err/divide_by_zero_err.hex"),
1553 include_str!("./contracts/generic_panic_err/generic_panic_err.hex"),
1554 include_str!("./contracts/index_out_of_bounds_err/index_out_of_bounds_err.hex"),
1555 include_str!("./contracts/invalid_enum_err/invalid_enum_err.hex"),
1556 include_str!("./contracts/invalid_storage_array_err/invalid_storage_array_err.hex"),
1557 include_str!("./contracts/out_of_memory_err/out_of_memory_err.hex"),
1558 include_str!("./contracts/pop_empty_array_err/pop_empty_array_err.hex"),
1559 include_str!("./contracts/uninitialized_fn_err/uninitialized_fn_err.hex"),
1560 ];
1561
1562 let mut tests = Vec::new();
1563
1564 for &contract_hex in &contract_codes {
1565 let contract_code =
1566 EthBytes::from_str(contract_hex).expect("Contract bytecode should be valid hex");
1567
1568 let zero_address = EthAddress::from_str(ZERO_ADDRESS).unwrap();
1569 let msg = EthCallMessage {
1571 from: Some(zero_address),
1572 data: Some(contract_code),
1573 ..EthCallMessage::default()
1574 };
1575
1576 let eth_call_request =
1577 EthCall::request((msg.clone(), BlockNumberOrHash::from_block_number(epoch))).unwrap();
1578
1579 tests.push(
1580 RpcTest::identity(eth_call_request)
1581 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1582 );
1583
1584 let eth_call_v2_request =
1585 EthCallV2::request((msg, ExtBlockNumberOrHash::from_block_number(epoch))).unwrap();
1586
1587 tests.push(
1588 RpcTest::identity(eth_call_v2_request)
1589 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1590 );
1591 }
1592
1593 tests
1594}
1595
1596fn eth_tests_with_tipset<DB: Blockstore>(store: &Arc<DB>, shared_tipset: &Tipset) -> Vec<RpcTest> {
1597 let block_cid = shared_tipset.key().cid().unwrap();
1598 let block_hash: EthHash = block_cid.into();
1599
1600 let mut tests = vec![
1601 RpcTest::identity(
1602 EthGetBalance::request((
1603 EthAddress::from_str("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa").unwrap(),
1604 BlockNumberOrHash::from_block_number(shared_tipset.epoch()),
1605 ))
1606 .unwrap(),
1607 ),
1608 RpcTest::identity(
1609 EthGetBalance::request((
1610 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1611 BlockNumberOrHash::from_block_number(shared_tipset.epoch()),
1612 ))
1613 .unwrap(),
1614 ),
1615 RpcTest::identity(
1616 EthGetBalance::request((
1617 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1618 BlockNumberOrHash::from_block_number_object(shared_tipset.epoch()),
1619 ))
1620 .unwrap(),
1621 ),
1622 RpcTest::identity(
1623 EthGetBalance::request((
1624 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1625 BlockNumberOrHash::from_block_hash_object(block_hash, false),
1626 ))
1627 .unwrap(),
1628 ),
1629 RpcTest::identity(
1630 EthGetBalance::request((
1631 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1632 BlockNumberOrHash::from_block_hash_object(block_hash, true),
1633 ))
1634 .unwrap(),
1635 ),
1636 RpcTest::identity(
1637 EthGetBalance::request((
1638 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1639 BlockNumberOrHash::from_predefined(Predefined::Earliest),
1640 ))
1641 .unwrap(),
1642 )
1643 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1644 RpcTest::basic(
1645 EthGetBalance::request((
1646 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1647 BlockNumberOrHash::from_predefined(Predefined::Pending),
1648 ))
1649 .unwrap(),
1650 ),
1651 RpcTest::basic(
1652 EthGetBalance::request((
1653 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1654 BlockNumberOrHash::from_predefined(Predefined::Latest),
1655 ))
1656 .unwrap(),
1657 ),
1658 RpcTest::identity(
1659 EthGetBalance::request((
1660 generate_eth_random_address().unwrap(),
1661 BlockNumberOrHash::from_predefined(Predefined::Latest),
1662 ))
1663 .unwrap(),
1664 ),
1665 RpcTest::identity(
1666 EthGetBalanceV2::request((
1667 EthAddress::from_str("0xff38c072f286e3b20b3954ca9f99c05fbecc64aa").unwrap(),
1668 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
1669 ))
1670 .unwrap(),
1671 ),
1672 RpcTest::identity(
1673 EthGetBalanceV2::request((
1674 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1675 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
1676 ))
1677 .unwrap(),
1678 ),
1679 RpcTest::identity(
1680 EthGetBalanceV2::request((
1681 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1682 ExtBlockNumberOrHash::from_block_number_object(shared_tipset.epoch()),
1683 ))
1684 .unwrap(),
1685 ),
1686 RpcTest::identity(
1687 EthGetBalanceV2::request((
1688 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1689 ExtBlockNumberOrHash::from_block_hash_object(block_hash, false),
1690 ))
1691 .unwrap(),
1692 ),
1693 RpcTest::identity(
1694 EthGetBalanceV2::request((
1695 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1696 ExtBlockNumberOrHash::from_block_hash_object(block_hash, true),
1697 ))
1698 .unwrap(),
1699 ),
1700 RpcTest::identity(
1701 EthGetBalanceV2::request((
1702 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1703 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Earliest),
1704 ))
1705 .unwrap(),
1706 )
1707 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1708 RpcTest::basic(
1709 EthGetBalanceV2::request((
1710 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1711 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Pending),
1712 ))
1713 .unwrap(),
1714 ),
1715 RpcTest::basic(
1716 EthGetBalanceV2::request((
1717 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1718 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
1719 ))
1720 .unwrap(),
1721 ),
1722 RpcTest::basic(
1723 EthGetBalanceV2::request((
1724 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1725 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
1726 ))
1727 .unwrap(),
1728 ),
1729 RpcTest::basic(
1730 EthGetBalanceV2::request((
1731 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1732 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
1733 ))
1734 .unwrap(),
1735 ),
1736 RpcTest::identity(
1737 EthGetBalanceV2::request((
1738 generate_eth_random_address().unwrap(),
1739 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
1740 ))
1741 .unwrap(),
1742 ),
1743 RpcTest::identity(
1744 EthGetBlockByNumber::request((
1745 BlockNumberOrPredefined::BlockNumber(EthInt64(shared_tipset.epoch())),
1746 false,
1747 ))
1748 .unwrap(),
1749 ),
1750 RpcTest::identity(
1751 EthGetBlockByNumber::request((
1752 BlockNumberOrPredefined::BlockNumber(EthInt64(shared_tipset.epoch())),
1753 true,
1754 ))
1755 .unwrap(),
1756 ),
1757 RpcTest::identity(
1758 EthGetBlockByNumber::request((
1759 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Earliest),
1760 true,
1761 ))
1762 .unwrap(),
1763 )
1764 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1765 RpcTest::basic(
1766 EthGetBlockByNumber::request((
1767 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Pending),
1768 true,
1769 ))
1770 .unwrap(),
1771 ),
1772 RpcTest::basic(
1773 EthGetBlockByNumber::request((
1774 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Latest),
1775 true,
1776 ))
1777 .unwrap(),
1778 ),
1779 RpcTest::basic(
1780 EthGetBlockByNumber::request((
1781 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Safe),
1782 true,
1783 ))
1784 .unwrap(),
1785 ),
1786 RpcTest::basic(
1787 EthGetBlockByNumber::request((
1788 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Finalized),
1789 true,
1790 ))
1791 .unwrap(),
1792 ),
1793 RpcTest::identity(
1794 EthGetBlockByNumberV2::request((
1795 BlockNumberOrPredefined::BlockNumber(EthInt64(shared_tipset.epoch())),
1796 false,
1797 ))
1798 .unwrap(),
1799 ),
1800 RpcTest::identity(
1801 EthGetBlockByNumberV2::request((
1802 BlockNumberOrPredefined::BlockNumber(EthInt64(shared_tipset.epoch())),
1803 true,
1804 ))
1805 .unwrap(),
1806 ),
1807 RpcTest::identity(
1808 EthGetBlockByNumberV2::request((
1809 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Earliest),
1810 true,
1811 ))
1812 .unwrap(),
1813 )
1814 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1815 RpcTest::basic(
1816 EthGetBlockByNumberV2::request((
1817 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Pending),
1818 true,
1819 ))
1820 .unwrap(),
1821 ),
1822 RpcTest::basic(
1823 EthGetBlockByNumberV2::request((
1824 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Latest),
1825 true,
1826 ))
1827 .unwrap(),
1828 ),
1829 RpcTest::basic(
1830 EthGetBlockByNumberV2::request((
1831 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Safe),
1832 true,
1833 ))
1834 .unwrap(),
1835 ),
1836 RpcTest::basic(
1837 EthGetBlockByNumberV2::request((
1838 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Finalized),
1839 true,
1840 ))
1841 .unwrap(),
1842 ),
1843 RpcTest::identity(
1844 EthGetBlockReceipts::request((BlockNumberOrHash::from_block_hash_object(
1845 block_hash, true,
1846 ),))
1847 .unwrap(),
1848 ),
1849 RpcTest::basic(
1853 EthGetBlockReceipts::request((BlockNumberOrHash::from_predefined(Predefined::Latest),))
1854 .unwrap(),
1855 ),
1856 RpcTest::identity(
1857 EthGetBlockReceiptsV2::request((ExtBlockNumberOrHash::from_block_hash_object(
1858 block_hash, true,
1859 ),))
1860 .unwrap(),
1861 ),
1862 RpcTest::basic(
1863 EthGetBlockReceiptsV2::request((ExtBlockNumberOrHash::from_predefined(
1864 ExtPredefined::Safe,
1865 ),))
1866 .unwrap(),
1867 ),
1868 RpcTest::basic(
1869 EthGetBlockReceiptsV2::request((ExtBlockNumberOrHash::from_predefined(
1870 ExtPredefined::Finalized,
1871 ),))
1872 .unwrap(),
1873 ),
1874 RpcTest::identity(EthGetBlockTransactionCountByHash::request((block_hash,)).unwrap()),
1875 RpcTest::identity(
1876 EthGetBlockReceiptsLimited::request((
1877 BlockNumberOrHash::from_block_hash_object(block_hash, true),
1878 4,
1879 ))
1880 .unwrap(),
1881 )
1882 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1883 RpcTest::identity(
1884 EthGetBlockReceiptsLimited::request((
1885 BlockNumberOrHash::from_block_hash_object(block_hash, true),
1886 -1,
1887 ))
1888 .unwrap(),
1889 ),
1890 RpcTest::identity(
1891 EthGetBlockReceiptsLimitedV2::request((
1892 ExtBlockNumberOrHash::from_block_hash_object(block_hash, true),
1893 4,
1894 ))
1895 .unwrap(),
1896 )
1897 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
1898 RpcTest::identity(
1899 EthGetBlockReceiptsLimitedV2::request((
1900 ExtBlockNumberOrHash::from_block_hash_object(block_hash, true),
1901 -1,
1902 ))
1903 .unwrap(),
1904 ),
1905 RpcTest::identity(
1906 EthGetBlockTransactionCountByNumber::request((EthInt64(shared_tipset.epoch()),))
1907 .unwrap(),
1908 ),
1909 RpcTest::identity(
1910 EthGetBlockTransactionCountByNumberV2::request((BlockNumberOrPredefined::BlockNumber(
1911 EthInt64(shared_tipset.epoch()),
1912 ),))
1913 .unwrap(),
1914 ),
1915 RpcTest::identity(
1916 EthGetBlockTransactionCountByNumberV2::request((
1917 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Safe),
1918 ))
1919 .unwrap(),
1920 ),
1921 RpcTest::identity(
1922 EthGetBlockTransactionCountByNumberV2::request((
1923 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Finalized),
1924 ))
1925 .unwrap(),
1926 ),
1927 RpcTest::identity(
1928 EthGetTransactionCount::request((
1929 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1930 BlockNumberOrHash::from_block_hash_object(block_hash, true),
1931 ))
1932 .unwrap(),
1933 ),
1934 RpcTest::identity(
1935 EthGetTransactionCount::request((
1936 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1937 BlockNumberOrHash::from_predefined(Predefined::Earliest),
1938 ))
1939 .unwrap(),
1940 )
1941 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1942 RpcTest::basic(
1943 EthGetTransactionCount::request((
1944 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1945 BlockNumberOrHash::from_predefined(Predefined::Pending),
1946 ))
1947 .unwrap(),
1948 ),
1949 RpcTest::basic(
1950 EthGetTransactionCount::request((
1951 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1952 BlockNumberOrHash::from_predefined(Predefined::Latest),
1953 ))
1954 .unwrap(),
1955 ),
1956 RpcTest::identity(
1957 EthGetTransactionCount::request((
1958 generate_eth_random_address().unwrap(),
1959 BlockNumberOrHash::from_predefined(Predefined::Latest),
1960 ))
1961 .unwrap(),
1962 ),
1963 RpcTest::identity(
1964 EthGetTransactionCountV2::request((
1965 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1966 ExtBlockNumberOrHash::from_block_hash_object(block_hash, true),
1967 ))
1968 .unwrap(),
1969 ),
1970 RpcTest::identity(
1971 EthGetTransactionCountV2::request((
1972 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1973 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Earliest),
1974 ))
1975 .unwrap(),
1976 )
1977 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
1978 RpcTest::basic(
1979 EthGetTransactionCountV2::request((
1980 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1981 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Pending),
1982 ))
1983 .unwrap(),
1984 ),
1985 RpcTest::basic(
1986 EthGetTransactionCountV2::request((
1987 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1988 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
1989 ))
1990 .unwrap(),
1991 ),
1992 RpcTest::basic(
1993 EthGetTransactionCountV2::request((
1994 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
1995 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
1996 ))
1997 .unwrap(),
1998 ),
1999 RpcTest::basic(
2000 EthGetTransactionCountV2::request((
2001 EthAddress::from_str("0xff000000000000000000000000000000000003ec").unwrap(),
2002 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
2003 ))
2004 .unwrap(),
2005 ),
2006 RpcTest::identity(
2007 EthGetTransactionCountV2::request((
2008 generate_eth_random_address().unwrap(),
2009 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
2010 ))
2011 .unwrap(),
2012 ),
2013 RpcTest::identity(
2014 EthGetStorageAt::request((
2015 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2017 EthBytes(vec![0xa]),
2018 BlockNumberOrHash::BlockNumber(EthInt64(shared_tipset.epoch())),
2019 ))
2020 .unwrap(),
2021 ),
2022 RpcTest::identity(
2023 EthGetStorageAt::request((
2024 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2025 EthBytes(vec![0xa]),
2026 BlockNumberOrHash::from_predefined(Predefined::Earliest),
2027 ))
2028 .unwrap(),
2029 )
2030 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2031 RpcTest::basic(
2032 EthGetStorageAt::request((
2033 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2034 EthBytes(vec![0xa]),
2035 BlockNumberOrHash::from_predefined(Predefined::Pending),
2036 ))
2037 .unwrap(),
2038 ),
2039 RpcTest::basic(
2040 EthGetStorageAt::request((
2041 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2042 EthBytes(vec![0xa]),
2043 BlockNumberOrHash::from_predefined(Predefined::Latest),
2044 ))
2045 .unwrap(),
2046 ),
2047 RpcTest::identity(
2048 EthGetStorageAt::request((
2049 generate_eth_random_address().unwrap(),
2050 EthBytes(vec![0x0]),
2051 BlockNumberOrHash::from_predefined(Predefined::Latest),
2052 ))
2053 .unwrap(),
2054 ),
2055 RpcTest::identity(
2056 EthGetStorageAtV2::request((
2057 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2058 EthBytes(vec![0xa]),
2059 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2060 ))
2061 .unwrap(),
2062 ),
2063 RpcTest::basic(
2064 EthGetStorageAtV2::request((
2065 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2066 EthBytes(vec![0xa]),
2067 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
2068 ))
2069 .unwrap(),
2070 ),
2071 RpcTest::basic(
2072 EthGetStorageAtV2::request((
2073 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2074 EthBytes(vec![0xa]),
2075 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
2076 ))
2077 .unwrap(),
2078 ),
2079 RpcTest::identity(
2080 EthGetStorageAtV2::request((
2081 generate_eth_random_address().unwrap(),
2082 EthBytes(vec![0x0]),
2083 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
2084 ))
2085 .unwrap(),
2086 ),
2087 RpcTest::identity(
2088 EthFeeHistory::request((
2089 10.into(),
2090 BlockNumberOrPredefined::BlockNumber(shared_tipset.epoch().into()),
2091 None,
2092 ))
2093 .unwrap(),
2094 ),
2095 RpcTest::identity(
2096 EthFeeHistory::request((
2097 10.into(),
2098 BlockNumberOrPredefined::BlockNumber(shared_tipset.epoch().into()),
2099 Some(vec![10., 50., 90.]),
2100 ))
2101 .unwrap(),
2102 ),
2103 RpcTest::identity(
2104 EthFeeHistory::request((
2105 10.into(),
2106 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Earliest),
2107 None,
2108 ))
2109 .unwrap(),
2110 )
2111 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2112 RpcTest::basic(
2113 EthFeeHistory::request((
2114 10.into(),
2115 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Pending),
2116 Some(vec![10., 50., 90.]),
2117 ))
2118 .unwrap(),
2119 ),
2120 RpcTest::basic(
2121 EthFeeHistory::request((
2122 10.into(),
2123 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Latest),
2124 None,
2125 ))
2126 .unwrap(),
2127 ),
2128 RpcTest::basic(
2129 EthFeeHistory::request((
2130 10.into(),
2131 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Safe),
2132 None,
2133 ))
2134 .unwrap(),
2135 ),
2136 RpcTest::basic(
2137 EthFeeHistory::request((
2138 10.into(),
2139 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Finalized),
2140 Some(vec![10., 50., 90.]),
2141 ))
2142 .unwrap(),
2143 ),
2144 RpcTest::identity(
2145 EthFeeHistoryV2::request((
2146 10.into(),
2147 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2148 None,
2149 ))
2150 .unwrap(),
2151 ),
2152 RpcTest::identity(
2153 EthFeeHistoryV2::request((
2154 10.into(),
2155 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2156 Some(vec![10., 50., 90.]),
2157 ))
2158 .unwrap(),
2159 ),
2160 RpcTest::identity(
2161 EthFeeHistoryV2::request((
2162 10.into(),
2163 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Earliest),
2164 None,
2165 ))
2166 .unwrap(),
2167 )
2168 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2169 RpcTest::basic(
2170 EthFeeHistoryV2::request((
2171 10.into(),
2172 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Pending),
2173 Some(vec![10., 50., 90.]),
2174 ))
2175 .unwrap(),
2176 ),
2177 RpcTest::basic(
2178 EthFeeHistoryV2::request((
2179 10.into(),
2180 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
2181 None,
2182 ))
2183 .unwrap(),
2184 ),
2185 RpcTest::basic(
2186 EthFeeHistoryV2::request((
2187 10.into(),
2188 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
2189 None,
2190 ))
2191 .unwrap(),
2192 ),
2193 RpcTest::basic(
2194 EthFeeHistoryV2::request((
2195 10.into(),
2196 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
2197 Some(vec![10., 50., 90.]),
2198 ))
2199 .unwrap(),
2200 ),
2201 RpcTest::identity(
2202 EthGetCode::request((
2203 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2205 BlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2206 ))
2207 .unwrap(),
2208 ),
2209 RpcTest::identity(
2210 EthGetCode::request((
2211 Address::from_str("f410fpoidg73f7krlfohnla52dotowde5p2sejxnd4mq")
2213 .unwrap()
2214 .try_into()
2215 .unwrap(),
2216 BlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2217 ))
2218 .unwrap(),
2219 ),
2220 RpcTest::identity(
2221 EthGetCode::request((
2222 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2223 BlockNumberOrHash::from_predefined(Predefined::Earliest),
2224 ))
2225 .unwrap(),
2226 )
2227 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2228 RpcTest::basic(
2229 EthGetCode::request((
2230 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2231 BlockNumberOrHash::from_predefined(Predefined::Pending),
2232 ))
2233 .unwrap(),
2234 ),
2235 RpcTest::basic(
2236 EthGetCode::request((
2237 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2238 BlockNumberOrHash::from_predefined(Predefined::Latest),
2239 ))
2240 .unwrap(),
2241 ),
2242 RpcTest::identity(
2243 EthGetCode::request((
2244 generate_eth_random_address().unwrap(),
2245 BlockNumberOrHash::from_predefined(Predefined::Latest),
2246 ))
2247 .unwrap(),
2248 ),
2249 RpcTest::identity(
2250 EthGetCodeV2::request((
2251 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2253 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2254 ))
2255 .unwrap(),
2256 ),
2257 RpcTest::basic(
2258 EthGetCodeV2::request((
2259 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2260 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),
2261 ))
2262 .unwrap(),
2263 ),
2264 RpcTest::basic(
2265 EthGetCodeV2::request((
2266 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2267 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Finalized),
2268 ))
2269 .unwrap(),
2270 ),
2271 RpcTest::identity(
2272 EthGetCodeV2::request((
2273 generate_eth_random_address().unwrap(),
2274 ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),
2275 ))
2276 .unwrap(),
2277 ),
2278 RpcTest::identity(
2279 EthGetTransactionByBlockNumberAndIndex::request((
2280 BlockNumberOrPredefined::BlockNumber(shared_tipset.epoch().into()),
2281 0.into(),
2282 ))
2283 .unwrap(),
2284 )
2285 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2286 RpcTest::identity(
2287 EthGetTransactionByBlockNumberAndIndex::request((
2288 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Earliest),
2289 0.into(),
2290 ))
2291 .unwrap(),
2292 )
2293 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2294 RpcTest::identity(
2295 EthGetTransactionByBlockNumberAndIndex::request((
2296 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Pending),
2297 0.into(),
2298 ))
2299 .unwrap(),
2300 )
2301 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2302 RpcTest::identity(
2303 EthGetTransactionByBlockNumberAndIndex::request((
2304 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Latest),
2305 0.into(),
2306 ))
2307 .unwrap(),
2308 )
2309 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2310 RpcTest::identity(
2311 EthGetTransactionByBlockNumberAndIndexV2::request((
2312 BlockNumberOrPredefined::BlockNumber(shared_tipset.epoch().into()),
2313 0.into(),
2314 ))
2315 .unwrap(),
2316 )
2317 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2318 RpcTest::identity(
2319 EthGetTransactionByBlockNumberAndIndexV2::request((
2320 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Safe),
2321 0.into(),
2322 ))
2323 .unwrap(),
2324 )
2325 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2326 RpcTest::identity(
2327 EthGetTransactionByBlockNumberAndIndexV2::request((
2328 BlockNumberOrPredefined::PredefinedBlock(ExtPredefined::Finalized),
2329 0.into(),
2330 ))
2331 .unwrap(),
2332 )
2333 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2334 RpcTest::identity(
2335 EthGetTransactionByBlockHashAndIndex::request((block_hash, 0.into())).unwrap(),
2336 )
2337 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
2338 RpcTest::identity(EthGetBlockByHash::request((block_hash, false)).unwrap()),
2339 RpcTest::identity(EthGetBlockByHash::request((block_hash, true)).unwrap()),
2340 RpcTest::identity(
2341 EthGetLogs::request((EthFilterSpec {
2342 from_block: Some(format!("0x{:x}", shared_tipset.epoch())),
2343 to_block: Some(format!("0x{:x}", shared_tipset.epoch())),
2344 ..Default::default()
2345 },))
2346 .unwrap(),
2347 )
2348 .sort_policy(SortPolicy::All)
2349 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2350 RpcTest::identity(
2351 EthGetLogs::request((EthFilterSpec {
2352 from_block: Some(format!("0x{:x}", shared_tipset.epoch())),
2353 to_block: Some(format!("0x{:x}", shared_tipset.epoch())),
2354 address: Some(EthAddressList::List(Vec::new())),
2355 ..Default::default()
2356 },))
2357 .unwrap(),
2358 )
2359 .sort_policy(SortPolicy::All)
2360 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2361 RpcTest::identity(
2362 EthGetLogs::request((EthFilterSpec {
2363 from_block: Some(format!("0x{:x}", shared_tipset.epoch() - 100)),
2364 to_block: Some(format!("0x{:x}", shared_tipset.epoch())),
2365 ..Default::default()
2366 },))
2367 .unwrap(),
2368 )
2369 .sort_policy(SortPolicy::All)
2370 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2371 RpcTest::identity(
2372 EthGetLogs::request((EthFilterSpec {
2373 address: Some(EthAddressList::Single(
2374 EthAddress::from_str("0x7B90337f65fAA2B2B8ed583ba1Ba6EB0C9D7eA44").unwrap(),
2375 )),
2376 ..Default::default()
2377 },))
2378 .unwrap(),
2379 )
2380 .sort_policy(SortPolicy::All)
2381 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2382 RpcTest::identity(EthGetFilterLogs::request((FilterID::new().unwrap(),)).unwrap())
2383 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
2384 RpcTest::identity(EthGetFilterChanges::request((FilterID::new().unwrap(),)).unwrap())
2385 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
2386 RpcTest::identity(EthGetTransactionHashByCid::request((block_cid,)).unwrap()),
2387 RpcTest::identity(
2388 EthTraceBlock::request((ExtBlockNumberOrHash::from_block_number(
2389 shared_tipset.epoch(),
2390 ),))
2391 .unwrap(),
2392 ),
2393 RpcTest::identity(
2394 EthTraceBlock::request((ExtBlockNumberOrHash::from_predefined(
2395 ExtPredefined::Earliest,
2396 ),))
2397 .unwrap(),
2398 )
2399 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2400 RpcTest::basic(
2401 EthTraceBlock::request((ExtBlockNumberOrHash::from_predefined(
2402 ExtPredefined::Pending,
2403 ),))
2404 .unwrap(),
2405 ),
2406 RpcTest::basic(
2407 EthTraceBlock::request((ExtBlockNumberOrHash::from_predefined(ExtPredefined::Latest),))
2408 .unwrap(),
2409 ),
2410 RpcTest::basic(
2411 EthTraceBlock::request((ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),))
2412 .unwrap(),
2413 ),
2414 RpcTest::basic(
2415 EthTraceBlock::request((ExtBlockNumberOrHash::from_predefined(
2416 ExtPredefined::Finalized,
2417 ),))
2418 .unwrap(),
2419 ),
2420 RpcTest::identity(
2421 EthTraceBlockV2::request((ExtBlockNumberOrHash::from_block_number(
2422 shared_tipset.epoch(),
2423 ),))
2424 .unwrap(),
2425 ),
2426 RpcTest::basic(
2427 EthTraceBlockV2::request((ExtBlockNumberOrHash::from_predefined(
2428 ExtPredefined::Pending,
2429 ),))
2430 .unwrap(),
2431 ),
2432 RpcTest::basic(
2433 EthTraceBlockV2::request((ExtBlockNumberOrHash::from_predefined(
2434 ExtPredefined::Latest,
2435 ),))
2436 .unwrap(),
2437 ),
2438 RpcTest::basic(
2439 EthTraceBlockV2::request((ExtBlockNumberOrHash::from_predefined(ExtPredefined::Safe),))
2440 .unwrap(),
2441 ),
2442 RpcTest::basic(
2443 EthTraceBlockV2::request((ExtBlockNumberOrHash::from_predefined(
2444 ExtPredefined::Finalized,
2445 ),))
2446 .unwrap(),
2447 ),
2448 RpcTest::identity(
2449 EthTraceReplayBlockTransactions::request((
2450 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2451 vec!["trace".to_string()],
2452 ))
2453 .unwrap(),
2454 ),
2455 RpcTest::identity(
2456 EthTraceReplayBlockTransactionsV2::request((
2457 ExtBlockNumberOrHash::from_block_number(shared_tipset.epoch()),
2458 vec!["trace".to_string()],
2459 ))
2460 .unwrap(),
2461 ),
2462 RpcTest::identity(
2463 EthTraceFilter::request((EthTraceFilterCriteria {
2464 from_block: Some(format!("0x{:x}", shared_tipset.epoch() - 100)),
2465 to_block: Some(format!("0x{:x}", shared_tipset.epoch() - SAFE_EPOCH_DELAY)),
2466 ..Default::default()
2467 },))
2468 .unwrap(),
2469 )
2470 .policy_on_rejected(PolicyOnRejected::PassWithIdenticalError),
2473 RpcTest::identity(
2474 EthGetTransactionReceipt::request((
2475 EthHash::from_str(
2478 "0xf234567890123456789d6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f70809",
2479 )
2480 .unwrap(),
2481 ))
2482 .unwrap(),
2483 ),
2484 ];
2485
2486 for block in shared_tipset.block_headers() {
2487 tests.extend([RpcTest::identity(
2488 FilecoinAddressToEthAddress::request((
2489 block.miner_address,
2490 Some(BlockNumberOrPredefined::PredefinedBlock(
2491 ExtPredefined::Latest,
2492 )),
2493 ))
2494 .unwrap(),
2495 )]);
2496 let (bls_messages, secp_messages) =
2497 crate::chain::store::block_messages(store, block).unwrap();
2498 for msg in sample_messages(bls_messages.iter(), secp_messages.iter()) {
2499 tests.extend([RpcTest::identity(
2500 FilecoinAddressToEthAddress::request((
2501 msg.from(),
2502 Some(BlockNumberOrPredefined::PredefinedBlock(
2503 ExtPredefined::Latest,
2504 )),
2505 ))
2506 .unwrap(),
2507 )]);
2508 if let Ok(eth_to_addr) = EthAddress::try_from(msg.to) {
2509 tests.extend([RpcTest::identity(
2510 EthEstimateGas::request((
2511 EthCallMessage {
2512 to: Some(eth_to_addr),
2513 value: Some(msg.value.clone().into()),
2514 data: Some(msg.params.clone().into()),
2515 ..Default::default()
2516 },
2517 Some(BlockNumberOrHash::BlockNumber(shared_tipset.epoch().into())),
2518 ))
2519 .unwrap(),
2520 )
2521 .policy_on_rejected(PolicyOnRejected::Pass)]);
2522 tests.extend([RpcTest::identity(
2523 EthEstimateGasV2::request((
2524 EthCallMessage {
2525 to: Some(eth_to_addr),
2526 value: Some(msg.value.clone().into()),
2527 data: Some(msg.params.clone().into()),
2528 ..Default::default()
2529 },
2530 Some(ExtBlockNumberOrHash::BlockNumber(
2531 shared_tipset.epoch().into(),
2532 )),
2533 ))
2534 .unwrap(),
2535 )
2536 .policy_on_rejected(PolicyOnRejected::Pass)]);
2537 }
2538 }
2539 }
2540
2541 tests
2542}
2543
2544fn read_state_api_tests(tipset: &Tipset) -> anyhow::Result<Vec<RpcTest>> {
2545 let tests = vec![
2546 RpcTest::identity(StateReadState::request((
2547 Address::SYSTEM_ACTOR,
2548 tipset.key().into(),
2549 ))?),
2550 RpcTest::identity(StateReadState::request((
2551 Address::SYSTEM_ACTOR,
2552 Default::default(),
2553 ))?),
2554 RpcTest::identity(StateReadState::request((
2555 Address::CRON_ACTOR,
2556 tipset.key().into(),
2557 ))?),
2558 RpcTest::identity(StateReadState::request((
2559 Address::MARKET_ACTOR,
2560 tipset.key().into(),
2561 ))?),
2562 RpcTest::identity(StateReadState::request((
2563 Address::INIT_ACTOR,
2564 tipset.key().into(),
2565 ))?),
2566 RpcTest::identity(StateReadState::request((
2567 Address::POWER_ACTOR,
2568 tipset.key().into(),
2569 ))?),
2570 RpcTest::identity(StateReadState::request((
2571 Address::REWARD_ACTOR,
2572 tipset.key().into(),
2573 ))?),
2574 RpcTest::identity(StateReadState::request((
2575 Address::VERIFIED_REGISTRY_ACTOR,
2576 tipset.key().into(),
2577 ))?),
2578 RpcTest::identity(StateReadState::request((
2579 Address::DATACAP_TOKEN_ACTOR,
2580 tipset.key().into(),
2581 ))?),
2582 RpcTest::identity(StateReadState::request((
2583 Address::new_id(66116), tipset.key().into(),
2586 ))?),
2587 RpcTest::identity(StateReadState::request((
2588 Address::new_id(18101), tipset.key().into(),
2591 ))?),
2592 RpcTest::identity(StateReadState::request((
2593 ACCOUNT_ADDRESS,
2594 tipset.key().into(),
2595 ))?),
2596 RpcTest::identity(StateReadState::request((
2597 MINER_ADDRESS,
2598 tipset.key().into(),
2599 ))?),
2600 RpcTest::identity(StateReadState::request((
2601 Address::from_str(EVM_ADDRESS).unwrap(), tipset.key().into(),
2603 ))?),
2604 ];
2605
2606 Ok(tests)
2607}
2608
2609fn eth_state_tests_with_tipset<DB: Blockstore>(
2610 store: &Arc<DB>,
2611 shared_tipset: &Tipset,
2612 eth_chain_id: EthChainIdType,
2613) -> anyhow::Result<Vec<RpcTest>> {
2614 let mut tests = vec![];
2615
2616 for block in shared_tipset.block_headers() {
2617 let state = StateTree::new_from_root(store.clone(), shared_tipset.parent_state())?;
2618
2619 let (bls_messages, secp_messages) = crate::chain::store::block_messages(store, block)?;
2620 for smsg in sample_signed_messages(bls_messages.iter(), secp_messages.iter()) {
2621 let tx = new_eth_tx_from_signed_message(&smsg, &state, eth_chain_id)?;
2622 tests.push(RpcTest::identity(
2623 EthGetMessageCidByTransactionHash::request((tx.hash,))?,
2624 ));
2625 tests.push(RpcTest::identity(EthGetTransactionByHash::request((
2626 tx.hash,
2627 ))?));
2628 tests.push(RpcTest::identity(EthGetTransactionByHashLimited::request(
2629 (tx.hash, shared_tipset.epoch()),
2630 )?));
2631 tests.push(RpcTest::identity(EthTraceTransaction::request((tx
2632 .hash
2633 .to_string(),))?));
2634 if smsg.message.from.protocol() == Protocol::Delegated
2635 && smsg.message.to.protocol() == Protocol::Delegated
2636 {
2637 tests.push(
2638 RpcTest::identity(EthGetTransactionReceipt::request((tx.hash,))?)
2639 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2640 );
2641 tests.push(
2642 RpcTest::identity(EthGetTransactionReceiptLimited::request((tx.hash, 800))?)
2643 .policy_on_rejected(PolicyOnRejected::PassWithQuasiIdenticalError),
2644 );
2645 }
2646 }
2647 }
2648 tests.push(RpcTest::identity(
2649 EthGetMessageCidByTransactionHash::request((EthHash::from_str(
2650 "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355f",
2651 )?,))?,
2652 ));
2653
2654 tests.extend(eth_call_api_err_tests(shared_tipset.epoch()));
2656
2657 Ok(tests)
2658}
2659
2660fn gas_tests_with_tipset(shared_tipset: &Tipset) -> Vec<RpcTest> {
2661 let addr = Address::from_str("t15ydyu3d65gznpp2qxwpkjsgz4waubeunn6upvla").unwrap();
2664 let message = Message {
2665 from: addr,
2666 to: addr,
2667 value: TokenAmount::from_whole(1),
2668 method_num: METHOD_SEND,
2669 ..Default::default()
2670 };
2671
2672 vec![
2673 RpcTest::identity(
2679 GasEstimateGasLimit::request((message.clone(), shared_tipset.key().into())).unwrap(),
2680 ),
2681 RpcTest::validate(
2685 GasEstimateMessageGas::request((
2686 message,
2687 None, shared_tipset.key().into(),
2689 ))
2690 .unwrap(),
2691 |forest_api_msg, lotus_api_msg| {
2692 let forest_msg = forest_api_msg.message;
2693 let lotus_msg = lotus_api_msg.message;
2694 if forest_msg.gas_limit != lotus_msg.gas_limit {
2696 return false;
2697 }
2698
2699 let forest_fee_cap = &forest_msg.gas_fee_cap;
2701 let lotus_fee_cap = &lotus_msg.gas_fee_cap;
2702 let forest_premium = &forest_msg.gas_premium;
2703 let lotus_premium = &lotus_msg.gas_premium;
2704
2705 if [forest_fee_cap, lotus_fee_cap, forest_premium, lotus_premium]
2707 .iter()
2708 .any(|amt| amt.is_negative())
2709 {
2710 return false;
2711 }
2712
2713 forest_fee_cap.is_within_percent(lotus_fee_cap, 5)
2714 && forest_premium.is_within_percent(lotus_premium, 5)
2715 },
2716 ),
2717 ]
2718}
2719
2720fn f3_tests() -> anyhow::Result<Vec<RpcTest>> {
2721 Ok(vec![
2722 RpcTest::basic(F3GetECPowerTable::request((None.into(),))?),
2724 RpcTest::basic(F3GetLatestCertificate::request(())?),
2725 RpcTest::basic(F3ListParticipants::request(())?),
2726 RpcTest::basic(F3GetProgress::request(())?),
2727 RpcTest::basic(F3GetOrRenewParticipationTicket::request((
2728 Address::new_id(1000),
2729 vec![],
2730 3,
2731 ))?),
2732 RpcTest::identity(F3IsRunning::request(())?),
2733 RpcTest::identity(F3GetCertificate::request((0,))?),
2734 RpcTest::identity(F3GetCertificate::request((50,))?),
2735 RpcTest::identity(F3GetManifest::request(())?),
2736 ])
2737}
2738
2739fn f3_tests_with_tipset(tipset: &Tipset) -> anyhow::Result<Vec<RpcTest>> {
2740 Ok(vec![
2741 RpcTest::identity(F3GetECPowerTable::request((tipset.key().into(),))?),
2742 RpcTest::identity(F3GetF3PowerTable::request((tipset.key().into(),))?),
2743 ])
2744}
2745
2746fn snapshot_tests(
2749 store: Arc<ManyCar>,
2750 offline: bool,
2751 num_tipsets: usize,
2752 miner_address: Option<Address>,
2753 eth_chain_id: u64,
2754) -> anyhow::Result<Vec<RpcTest>> {
2755 let mut tests = vec![];
2756 let shared_tipset = store
2759 .heaviest_tipset()?
2760 .chain(&store)
2761 .take(SAFE_EPOCH_DELAY as usize)
2762 .last()
2763 .expect("Infallible");
2764
2765 for tipset in shared_tipset.chain(&store).take(num_tipsets) {
2766 tests.extend(chain_tests_with_tipset(&store, offline, &tipset)?);
2767 tests.extend(miner_tests_with_tipset(&store, &tipset, miner_address)?);
2768 tests.extend(state_tests_with_tipset(&store, &tipset)?);
2769 tests.extend(eth_tests_with_tipset(&store, &tipset));
2770 tests.extend(event_tests_with_tipset(&store, &tipset));
2771 tests.extend(gas_tests_with_tipset(&tipset));
2772 tests.extend(mpool_tests_with_tipset(&tipset));
2773 tests.extend(eth_state_tests_with_tipset(&store, &tipset, eth_chain_id)?);
2774 tests.extend(f3_tests_with_tipset(&tipset)?);
2775 }
2776
2777 Ok(tests)
2778}
2779
2780fn sample_message_cids<'a>(
2781 bls_messages: impl Iterator<Item = &'a Message> + 'a,
2782 secp_messages: impl Iterator<Item = &'a SignedMessage> + 'a,
2783) -> impl Iterator<Item = Cid> + 'a {
2784 bls_messages
2785 .map(|m| m.cid())
2786 .unique()
2787 .take(COLLECTION_SAMPLE_SIZE)
2788 .chain(
2789 secp_messages
2790 .map(|m| m.cid())
2791 .unique()
2792 .take(COLLECTION_SAMPLE_SIZE),
2793 )
2794 .unique()
2795}
2796
2797fn sample_messages<'a>(
2798 bls_messages: impl Iterator<Item = &'a Message> + 'a,
2799 secp_messages: impl Iterator<Item = &'a SignedMessage> + 'a,
2800) -> impl Iterator<Item = &'a Message> + 'a {
2801 bls_messages
2802 .unique()
2803 .take(COLLECTION_SAMPLE_SIZE)
2804 .chain(
2805 secp_messages
2806 .map(SignedMessage::message)
2807 .unique()
2808 .take(COLLECTION_SAMPLE_SIZE),
2809 )
2810 .unique()
2811}
2812
2813fn sample_signed_messages<'a>(
2814 bls_messages: impl Iterator<Item = &'a Message> + 'a,
2815 secp_messages: impl Iterator<Item = &'a SignedMessage> + 'a,
2816) -> impl Iterator<Item = SignedMessage> + 'a {
2817 bls_messages
2818 .unique()
2819 .take(COLLECTION_SAMPLE_SIZE)
2820 .map(|msg| {
2821 let sig = Signature::new_bls(vec![]);
2822 SignedMessage::new_unchecked(msg.clone(), sig)
2823 })
2824 .chain(secp_messages.cloned().unique().take(COLLECTION_SAMPLE_SIZE))
2825 .unique()
2826}
2827
2828pub(super) async fn create_tests(
2829 CreateTestsArgs {
2830 offline,
2831 n_tipsets,
2832 miner_address,
2833 worker_address,
2834 eth_chain_id,
2835 snapshot_files,
2836 }: CreateTestsArgs,
2837) -> anyhow::Result<Vec<RpcTest>> {
2838 let mut tests = vec![];
2839 tests.extend(auth_tests()?);
2840 tests.extend(common_tests());
2841 tests.extend(chain_tests());
2842 tests.extend(mpool_tests());
2843 tests.extend(net_tests());
2844 tests.extend(node_tests());
2845 tests.extend(wallet_tests(worker_address));
2846 tests.extend(eth_tests());
2847 tests.extend(f3_tests()?);
2848 if !snapshot_files.is_empty() {
2849 let store = Arc::new(ManyCar::try_from(snapshot_files.clone())?);
2850 revalidate_chain(store.clone(), n_tipsets).await?;
2851 tests.extend(snapshot_tests(
2852 store,
2853 offline,
2854 n_tipsets,
2855 miner_address,
2856 eth_chain_id,
2857 )?);
2858 }
2859 tests.sort_by_key(|test| test.request.method_name.clone());
2860
2861 tests.extend(create_deferred_tests(snapshot_files)?);
2862 Ok(tests)
2863}
2864
2865fn create_deferred_tests(snapshot_files: Vec<PathBuf>) -> anyhow::Result<Vec<RpcTest>> {
2867 let mut tests = vec![];
2868
2869 if !snapshot_files.is_empty() {
2870 let store = Arc::new(ManyCar::try_from(snapshot_files)?);
2871 tests.push(RpcTest::identity(ChainSetHead::request((store
2872 .heaviest_tipset()?
2873 .key()
2874 .clone(),))?));
2875 }
2876
2877 Ok(tests)
2878}
2879
2880async fn revalidate_chain(db: Arc<ManyCar>, n_ts_to_validate: usize) -> anyhow::Result<()> {
2881 if n_ts_to_validate == 0 {
2882 return Ok(());
2883 }
2884 let chain_config = Arc::new(handle_chain_config(&NetworkChain::Calibnet)?);
2885
2886 let genesis_header = crate::genesis::read_genesis_header(
2887 None,
2888 chain_config.genesis_bytes(&db).await?.as_deref(),
2889 &db,
2890 )
2891 .await?;
2892 let chain_store = Arc::new(ChainStore::new(
2893 db.clone(),
2894 db.clone(),
2895 db.clone(),
2896 chain_config,
2897 genesis_header.clone(),
2898 )?);
2899 let state_manager = Arc::new(StateManager::new(chain_store.clone())?);
2900 let head_ts = db.heaviest_tipset()?;
2901
2902 proofs_api::maybe_set_proofs_parameter_cache_dir_env(&Config::default().client.data_dir);
2905 ensure_proof_params_downloaded().await?;
2906 state_manager.validate_tipsets(
2907 head_ts
2908 .chain(&db)
2909 .take(SAFE_EPOCH_DELAY as usize + n_ts_to_validate),
2910 )?;
2911
2912 Ok(())
2913}
2914
2915#[allow(clippy::too_many_arguments)]
2916pub(super) async fn run_tests(
2917 tests: impl IntoIterator<Item = RpcTest>,
2918 forest: impl Into<Arc<rpc::Client>>,
2919 lotus: impl Into<Arc<rpc::Client>>,
2920 max_concurrent_requests: usize,
2921 filter_file: Option<PathBuf>,
2922 filter: String,
2923 filter_version: Option<rpc::ApiPaths>,
2924 run_ignored: RunIgnored,
2925 fail_fast: bool,
2926 dump_dir: Option<PathBuf>,
2927 test_criteria_overrides: &[TestCriteriaOverride],
2928 report_dir: Option<PathBuf>,
2929 report_mode: ReportMode,
2930 n_retries: usize,
2931) -> anyhow::Result<()> {
2932 let forest = Into::<Arc<rpc::Client>>::into(forest);
2933 let lotus = Into::<Arc<rpc::Client>>::into(lotus);
2934 let semaphore = Arc::new(Semaphore::new(max_concurrent_requests));
2935 let mut tasks = JoinSet::new();
2936
2937 let filter_list = if let Some(filter_file) = &filter_file {
2938 FilterList::new_from_file(filter_file)?
2939 } else {
2940 FilterList::default().allow(filter.clone())
2941 };
2942
2943 let mut report_builder = ReportBuilder::new(&filter_list, report_mode);
2945
2946 for test in tests.into_iter().unique_by(
2948 |RpcTest {
2949 request:
2950 rpc::Request {
2951 method_name,
2952 params,
2953 api_paths,
2954 ..
2955 },
2956 ignore,
2957 ..
2958 }| {
2959 (
2960 method_name.clone(),
2961 params.clone(),
2962 *api_paths,
2963 ignore.is_some(),
2964 )
2965 },
2966 ) {
2967 if matches!(run_ignored, RunIgnored::Default) && test.ignore.is_some() {
2969 continue;
2970 }
2971 if matches!(run_ignored, RunIgnored::IgnoredOnly) && test.ignore.is_none() {
2973 continue;
2974 }
2975
2976 if !filter_list.authorize(&test.request.method_name) {
2977 continue;
2978 }
2979
2980 if let Some(filter_version) = filter_version
2981 && !test.request.api_paths.contains(filter_version)
2982 {
2983 continue;
2984 }
2985
2986 let semaphore = semaphore.clone();
2988 let forest = forest.clone();
2989 let lotus = lotus.clone();
2990 let test_criteria_overrides = test_criteria_overrides.to_vec();
2991 tasks.spawn(async move {
2992 let mut n_retries_left = n_retries;
2993 let mut backoff_secs = 2;
2994 loop {
2995 {
2996 let _permit = semaphore.acquire().await;
2998 let test_result = test.run(&forest, &lotus).await;
2999 let success =
3000 evaluate_test_success(&test_result, &test, &test_criteria_overrides);
3001 if success || n_retries_left == 0 {
3002 return (success, test, test_result);
3003 }
3004 }
3006 tokio::time::sleep(Duration::from_secs(backoff_secs)).await;
3008 n_retries_left = n_retries_left.saturating_sub(1);
3009 backoff_secs = backoff_secs.saturating_mul(2);
3010 }
3011 });
3012 }
3013
3014 if tasks.is_empty() {
3016 return Ok(());
3017 }
3018
3019 while let Some(result) = tasks.join_next().await {
3020 match result {
3021 Ok((success, test, test_result)) => {
3022 let method_name = test.request.method_name.clone();
3023
3024 report_builder.track_test_result(
3025 method_name.as_ref(),
3026 success,
3027 &test_result,
3028 &test.request.params,
3029 );
3030
3031 if let (Some(dump_dir), Some(test_dump)) = (&dump_dir, &test_result.test_dump) {
3033 dump_test_data(dump_dir, success, test_dump)?;
3034 }
3035
3036 if !success && fail_fast {
3037 break;
3038 }
3039 }
3040 Err(e) => tracing::warn!("{e}"),
3041 }
3042 }
3043
3044 let has_failures = report_builder.has_failures();
3045 report_builder.print_summary();
3046
3047 if let Some(path) = report_dir {
3048 report_builder.finalize_and_save(&path)?;
3049 }
3050
3051 anyhow::ensure!(!has_failures, "Some tests failed");
3052
3053 Ok(())
3054}
3055
3056fn evaluate_test_success(
3058 test_result: &TestResult,
3059 test: &RpcTest,
3060 test_criteria_overrides: &[TestCriteriaOverride],
3061) -> bool {
3062 match (&test_result.forest_status, &test_result.lotus_status) {
3063 (TestSummary::Valid, TestSummary::Valid) => true,
3064 (TestSummary::Valid, TestSummary::Timeout) => {
3065 test_criteria_overrides.contains(&TestCriteriaOverride::ValidAndTimeout)
3066 }
3067 (TestSummary::Timeout, TestSummary::Timeout) => {
3068 test_criteria_overrides.contains(&TestCriteriaOverride::TimeoutAndTimeout)
3069 }
3070 (TestSummary::Rejected(reason_forest), TestSummary::Rejected(reason_lotus)) => {
3071 match test.policy_on_rejected {
3072 PolicyOnRejected::Pass => true,
3073 PolicyOnRejected::PassWithIdenticalError => reason_forest == reason_lotus,
3074 PolicyOnRejected::PassWithIdenticalErrorCaseInsensitive => {
3075 reason_forest.eq_ignore_ascii_case(reason_lotus)
3076 }
3077 PolicyOnRejected::PassWithQuasiIdenticalError => {
3078 reason_lotus.contains(reason_forest) || reason_forest.contains(reason_lotus)
3079 }
3080 _ => false,
3081 }
3082 }
3083 _ => false,
3084 }
3085}
3086
3087fn normalized_error_message(s: &str) -> Cow<'_, str> {
3088 let lotus_gateway_error_prefix = lazy_regex::regex!(r#"^RPC\serror\s\(-?\d+\):\s*"#);
3090 lotus_gateway_error_prefix.replace(s, "")
3091}
3092
3093fn dump_test_data(dump_dir: &Path, success: bool, test_dump: &TestDump) -> anyhow::Result<()> {
3095 let dir = dump_dir.join(if success { "valid" } else { "invalid" });
3096 if !dir.is_dir() {
3097 std::fs::create_dir_all(&dir)?;
3098 }
3099 let file_name = format!(
3100 "{}_{}.json",
3101 test_dump
3102 .request
3103 .method_name
3104 .as_ref()
3105 .replace(".", "_")
3106 .to_lowercase(),
3107 Utc::now().timestamp_micros()
3108 );
3109 std::fs::write(
3110 dir.join(file_name),
3111 serde_json::to_string_pretty(test_dump)?,
3112 )?;
3113 Ok(())
3114}
3115
3116fn validate_message_lookup(req: rpc::Request<MessageLookup>) -> RpcTest {
3117 RpcTest::validate(req, |mut forest, mut lotus| {
3118 forest.return_dec = Ipld::Null;
3120 lotus.return_dec = Ipld::Null;
3121 forest == lotus
3122 })
3123}
3124
3125fn validate_tagged_tipset_v2(req: rpc::Request<Option<Tipset>>, offline: bool) -> RpcTest {
3126 RpcTest::validate(req, move |forest, lotus| match (forest, lotus) {
3127 (None, None) => true,
3128 (Some(forest), Some(lotus)) => {
3129 if offline {
3130 true
3131 } else {
3132 (forest.epoch() - lotus.epoch()).abs() <= 2
3133 }
3134 }
3135 _ => false,
3136 })
3137}
3138
3139#[cfg(test)]
3140mod tests {
3141 use super::*;
3142
3143 #[test]
3144 fn test_normalized_error_message_1() {
3145 let s = "RPC error (-32603): exactly one tipset selection criteria must be specified";
3146 let r = normalized_error_message(s);
3147 assert_eq!(
3148 r.as_ref(),
3149 "exactly one tipset selection criteria must be specified"
3150 );
3151 }
3152
3153 #[test]
3154 fn test_normalized_error_message_2() {
3155 let s = "exactly one tipset selection criteria must be specified";
3156 let r = normalized_error_message(s);
3157 assert_eq!(
3158 r.as_ref(),
3159 "exactly one tipset selection criteria must be specified"
3160 );
3161 }
3162}