Skip to content

Commit 43ad5ef

Browse files
committed
parity tests
1 parent 5307602 commit 43ad5ef

File tree

10 files changed

+161
-45
lines changed

10 files changed

+161
-45
lines changed

src/rpc/client.rs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use std::fmt::{self, Debug};
1414
use std::sync::LazyLock;
1515
use std::time::Duration;
1616

17-
use anyhow::{Context as _, bail};
18-
use enumflags2::BitFlags;
17+
use anyhow::bail;
1918
use futures::future::Either;
2019
use http::{HeaderMap, HeaderValue, header};
2120
use jsonrpsee::core::ClientError;
@@ -93,15 +92,17 @@ impl Client {
9392
&self,
9493
req: Request<T>,
9594
) -> Result<T, ClientError> {
95+
let max_api_path = req
96+
.api_path()
97+
.map_err(|e| ClientError::Custom(e.to_string()))?;
9698
let Request {
9799
method_name,
98100
params,
99-
api_paths,
100101
timeout,
101102
..
102103
} = req;
103104
let method_name = method_name.as_ref();
104-
let client = self.get_or_init_client(api_paths).await?;
105+
let client = self.get_or_init_client(max_api_path).await?;
105106
let span = tracing::debug_span!("request", method = %method_name, url = %client.url);
106107
let work = async {
107108
// jsonrpsee's clients have a global `timeout`, but not a per-request timeout, which
@@ -149,31 +150,16 @@ impl Client {
149150
};
150151
work.instrument(span.or_current()).await
151152
}
152-
async fn get_or_init_client(
153-
&self,
154-
version: BitFlags<ApiPaths>,
155-
) -> Result<&UrlClient, ClientError> {
156-
let path = version
157-
.iter()
158-
.max()
159-
.context("No supported versions")
160-
.map_err(|e| ClientError::Custom(e.to_string()))?;
153+
async fn get_or_init_client(&self, path: ApiPaths) -> Result<&UrlClient, ClientError> {
161154
match path {
162155
ApiPaths::V0 => &self.v0,
163156
ApiPaths::V1 => &self.v1,
164157
ApiPaths::V2 => &self.v2,
165158
}
166159
.get_or_try_init(|| async {
167-
let url = self
168-
.base_url
169-
.join(match path {
170-
ApiPaths::V0 => "rpc/v0",
171-
ApiPaths::V1 => "rpc/v1",
172-
ApiPaths::V2 => "rpc/v2",
173-
})
174-
.map_err(|it| {
175-
ClientError::Custom(format!("creating url for endpoint failed: {it}"))
176-
})?;
160+
let url = self.base_url.join(path.path()).map_err(|it| {
161+
ClientError::Custom(format!("creating url for endpoint failed: {it}"))
162+
})?;
177163
UrlClient::new(url, self.token.clone()).await
178164
})
179165
.await

src/rpc/methods/chain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2019-2025 ChainSafe Systems
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

4-
mod types;
4+
pub mod types;
55
use enumflags2::{BitFlags, make_bitflags};
66
use types::*;
77

src/rpc/methods/chain/types.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
use super::*;
55

6+
#[cfg(test)]
7+
mod tests;
8+
69
#[derive(Serialize, Deserialize, JsonSchema, Clone, Debug, Eq, PartialEq, Default)]
710
#[serde(rename_all = "PascalCase")]
811
pub struct ObjStat {
@@ -11,14 +14,18 @@ pub struct ObjStat {
1114
}
1215
lotus_json_with_self!(ObjStat);
1316

14-
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
17+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1518
pub struct TipsetSelector {
16-
#[serde(with = "crate::lotus_json")]
19+
#[serde(
20+
with = "crate::lotus_json",
21+
skip_serializing_if = "ApiTipsetKey::is_none",
22+
default
23+
)]
1724
#[schemars(with = "LotusJson<TipsetKey>")]
1825
pub key: ApiTipsetKey,
19-
#[serde(skip_serializing_if = "Option::is_none")]
26+
#[serde(skip_serializing_if = "Option::is_none", default)]
2027
pub height: Option<TipsetHeight>,
21-
#[serde(skip_serializing_if = "Option::is_none")]
28+
#[serde(skip_serializing_if = "Option::is_none", default)]
2229
pub tag: Option<TipsetTag>,
2330
}
2431
lotus_json_with_self!(TipsetSelector);
@@ -49,7 +56,7 @@ impl TipsetSelector {
4956
}
5057
}
5158

52-
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
5360
pub struct TipsetHeight {
5461
pub at: ChainEpoch,
5562
pub previous: bool,
@@ -83,7 +90,7 @@ impl TipsetHeight {
8390
}
8491
}
8592

86-
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
93+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
8794
pub struct TipsetAnchor {
8895
#[serde(with = "crate::lotus_json")]
8996
#[schemars(with = "LotusJson<TipsetKey>")]
@@ -109,9 +116,19 @@ impl TipsetAnchor {
109116
}
110117

111118
#[derive(
112-
Debug, Clone, Copy, strum::Display, strum::EnumString, Serialize, Deserialize, JsonSchema,
119+
Debug,
120+
Clone,
121+
Copy,
122+
strum::Display,
123+
strum::EnumString,
124+
Serialize,
125+
Deserialize,
126+
PartialEq,
127+
Eq,
128+
JsonSchema,
113129
)]
114130
#[strum(serialize_all = "lowercase")]
131+
#[serde(rename_all = "lowercase")]
115132
pub enum TipsetTag {
116133
Latest,
117134
Finalized,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2019-2025 ChainSafe Systems
2+
// SPDX-License-Identifier: Apache-2.0, MIT
3+
4+
use super::*;
5+
6+
#[test]
7+
fn test_tipset_selector_serde() {
8+
let s = TipsetSelector {
9+
key: None.into(),
10+
height: None,
11+
tag: None,
12+
};
13+
let json = serde_json::to_value(&s).unwrap();
14+
println!("{json}");
15+
let s2: TipsetSelector = serde_json::from_value(json).unwrap();
16+
assert_eq!(s, s2);
17+
}

src/rpc/reflect/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,14 @@ impl ApiPaths {
162162
uri.path().split("/").last().expect("infallible"),
163163
)?)
164164
}
165+
166+
pub fn path(&self) -> &'static str {
167+
match self {
168+
Self::V0 => "rpc/v0",
169+
Self::V1 => "rpc/v1",
170+
Self::V2 => "rpc/v2",
171+
}
172+
}
165173
}
166174

167175
/// Utility methods, defined as an extension trait to avoid having to specify

src/rpc/request.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

44
use super::ApiPaths;
5+
use anyhow::Context as _;
56
use enumflags2::BitFlags;
67
use jsonrpsee::core::traits::ToRpcParams;
78
use serde::{Deserialize, Serialize};
@@ -41,6 +42,14 @@ impl<T> Request<T> {
4142
timeout: self.timeout,
4243
}
4344
}
45+
46+
pub fn max_api_path(api_paths: BitFlags<ApiPaths>) -> anyhow::Result<ApiPaths> {
47+
api_paths.iter().max().context("No supported versions")
48+
}
49+
50+
pub fn api_path(&self) -> anyhow::Result<ApiPaths> {
51+
Self::max_api_path(self.api_paths)
52+
}
4453
}
4554

4655
impl<T> ToRpcParams for Request<T> {

src/rpc/types/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,15 @@ lotus_json_with_self!(MessageLookup);
157157
derive_more::From,
158158
derive_more::Into,
159159
)]
160-
pub struct ApiTipsetKey(pub Option<TipsetKey>);
160+
pub struct ApiTipsetKey(
161+
#[serde(skip_serializing_if = "Option::is_none", default)] pub Option<TipsetKey>,
162+
);
163+
164+
impl ApiTipsetKey {
165+
pub fn is_none(&self) -> bool {
166+
self.0.is_none()
167+
}
168+
}
161169

162170
/// This wrapper is needed because of a bug in Lotus.
163171
/// See: <https://github.com/filecoin-project/lotus/issues/11461>.

src/tool/subcommands/api_cmd.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ use crate::db::db_engine::db_root;
1414
use crate::eth::EthChainId as EthChainIdType;
1515
use crate::lotus_json::HasLotusJson;
1616
use crate::networks::NetworkChain;
17-
use crate::rpc;
18-
use crate::rpc::eth::types::*;
19-
use crate::rpc::prelude::*;
17+
use crate::rpc::{self, ApiPaths, eth::types::*, prelude::*};
2018
use crate::shim::address::Address;
2119
use crate::tool::offline_server::start_offline_server;
2220
use crate::tool::subcommands::api_cmd::stateful_tests::TestTransaction;
@@ -122,6 +120,9 @@ pub enum ApiCommands {
122120
/// Empty lines and lines starting with `#` are ignored.
123121
#[arg(long)]
124122
filter_file: Option<PathBuf>,
123+
/// Filter methods for the specific API version.
124+
#[arg(long)]
125+
filter_version: Option<ApiPaths>,
125126
/// Cancel test run on the first failure
126127
#[arg(long)]
127128
fail_fast: bool,
@@ -285,6 +286,7 @@ impl ApiCommands {
285286
lotus: UrlFromMultiAddr(lotus),
286287
filter,
287288
filter_file,
289+
filter_version,
288290
fail_fast,
289291
run_ignored,
290292
max_concurrent_requests,
@@ -300,16 +302,17 @@ impl ApiCommands {
300302

301303
api_compare_tests::run_tests(
302304
tests,
303-
forest.clone(),
304-
lotus.clone(),
305+
forest,
306+
lotus,
305307
max_concurrent_requests,
306-
filter_file.clone(),
307-
filter.clone(),
308+
filter_file,
309+
filter,
310+
filter_version,
308311
run_ignored,
309312
fail_fast,
310-
dump_dir.clone(),
313+
dump_dir,
311314
&test_criteria_overrides,
312-
report_dir.clone(),
315+
report_dir,
313316
report_mode,
314317
)
315318
.await?;
@@ -366,8 +369,7 @@ impl ApiCommands {
366369
},
367370
index,
368371
db,
369-
// https://github.com/ChainSafe/forest/issues/6220
370-
api_path: None,
372+
api_path: Some(test_dump.path),
371373
}
372374
};
373375

0 commit comments

Comments
 (0)