Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 80 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ cosmrs = { version = "0.22.0" }
cosmos-sdk-proto = { version = "0.27.0" }
ibc-proto = { version = "0.52.0" }
tendermint = "0.40.4"
tendermint-light-client = "0.40.4"
tendermint-rpc = "0.40.4"
prost = { version = "0.13", default-features = false }

Expand Down
1 change: 1 addition & 0 deletions common/client-libs/validator-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ required-features = ["http-client"]
[features]
default = ["http-client"]
http-client = ["cosmrs/rpc"]
mocks = []
generate-ts = []
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
# Features below are added to make clippy happy, it seems like they're unused we should remove them
Expand Down
4 changes: 2 additions & 2 deletions common/client-libs/validator-client/src/nyxd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ pub use cosmrs::{
query::{PageRequest, PageResponse},
tendermint::{
abci::{response::DeliverTx, types::ExecTxResult, Event, EventAttribute},
block::Height,
block::{signed_header::SignedHeader, Height},
hash::{self, Algorithm, Hash},
validator::Info as TendermintValidatorInfo,
validator::{Info as TendermintValidatorInfo, Set as ValidatorSet},
Time as TendermintTime,
},
tx::{self, Msg},
Expand Down
150 changes: 150 additions & 0 deletions common/client-libs/validator-client/src/rpc/mocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2026 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0

use crate::nyxd::Height;
use crate::rpc::TendermintRpcClient;
use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use tendermint_rpc::endpoint::{commit, validators};
use tendermint_rpc::{Error, PageNumber, Paging, PerPage, SimpleRequest};

// reimplementation of `Paging` that derives `Hash`
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
enum PagingWrapper {
Default,
All,
Specific {
page_number: PageNumberWrapper,
per_page: PerPageWrapper,
},
}

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
struct PageNumberWrapper(usize);
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
struct PerPageWrapper(u8);

#[allow(clippy::unwrap_used)]
impl From<Paging> for PagingWrapper {
fn from(value: Paging) -> Self {
match value {
Paging::Default => PagingWrapper::Default,
Paging::All => PagingWrapper::All,
Paging::Specific {
page_number,
per_page,
} => PagingWrapper::Specific {
page_number: PageNumberWrapper(page_number.to_string().parse().unwrap()),
per_page: PerPageWrapper(per_page.to_string().parse().unwrap()),
},
}
}
}

impl From<PagingWrapper> for Paging {
fn from(value: PagingWrapper) -> Self {
match value {
PagingWrapper::All => Paging::All,
PagingWrapper::Default => Paging::Default,
PagingWrapper::Specific {
page_number,
per_page,
} => Paging::Specific {
page_number: PageNumber::from(page_number.0),
per_page: PerPage::from(per_page.0),
},
}
}
}

#[derive(Default)]
struct CallLog {
commit: Vec<Height>,
validators: Vec<(Height, Paging)>,
}

// very naive mock for rpc queries that currently only support tiny subset of pre-registered queries
#[derive(Clone, Default)]
pub struct MockRpcClient {
commits: HashMap<Height, Result<commit::Response, Error>>,
validators: HashMap<(Height, PagingWrapper), Result<validators::Response, Error>>,

call_log: Arc<Mutex<CallLog>>,
}

impl MockRpcClient {
/// Heights passed to `commit`, in call order.
pub fn commit_calls(&self) -> Vec<Height> {
self.call_log.lock().unwrap().commit.clone()
}

/// Heights passed to `validators`, in call order.
pub fn validators_calls(&self) -> Vec<(Height, Paging)> {
self.call_log.lock().unwrap().validators.clone()
}

pub fn with_commit_response<H>(
&mut self,
height: H,
response: Result<commit::Response, Error>,
) -> &mut Self
where
H: Into<Height> + Send,
{
self.commits.insert(height.into(), response);
self
}

pub fn with_validators_response<H>(
&mut self,
height: H,
paging: Paging,
response: Result<validators::Response, Error>,
) -> &mut Self
where
H: Into<Height> + Send,
{
self.validators
.insert((height.into(), paging.into()), response);
self
}
}

#[async_trait]
impl TendermintRpcClient for MockRpcClient {
async fn commit<H>(&self, height: H) -> Result<commit::Response, Error>
where
H: Into<Height> + Send,
{
let height = height.into();
self.call_log.lock().unwrap().commit.push(height);
self.commits
.get(&height)
.unwrap_or_else(|| panic!("unregistered response for commit at height {height}"))
.clone()
}

async fn validators<H>(&self, height: H, paging: Paging) -> Result<validators::Response, Error>
where
H: Into<Height> + Send,
{
let height = height.into();
self.call_log
.lock()
.unwrap()
.validators
.push((height, paging));
self.validators
.get(&(height, paging.into()))
.unwrap_or_else(|| panic!("unregistered response for validators at height {height} with pagination {paging:#?}"))
.clone()
}

async fn perform<R>(&self, _: R) -> Result<R::Output, Error>
where
R: SimpleRequest,
{
unimplemented!()
}
}
8 changes: 7 additions & 1 deletion common/client-libs/validator-client/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::nyxd::cosmwasm_client::types::{Account, SequenceResponse, SimulateRes
use crate::nyxd::error::NyxdError;
use crate::nyxd::helpers::{create_pagination, next_page_key};
use crate::nyxd::{BlockResponse, Coin, TxResponse};
use crate::rpc::types::ProvableAbciQueryResponse;
use async_trait::async_trait;
use cosmrs::proto::cosmos::auth::v1beta1::{QueryAccountRequest, QueryAccountResponse};
use cosmrs::proto::cosmos::bank::v1beta1::{
Expand Down Expand Up @@ -49,12 +50,13 @@ use tokio::time::sleep;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::Instant;

use crate::rpc::types::ProvableAbciQueryResponse;
#[cfg(target_arch = "wasm32")]
use wasmtimer::std::Instant;
#[cfg(target_arch = "wasm32")]
use wasmtimer::tokio::sleep;

#[cfg(feature = "mocks")]
pub mod mocks;
pub mod reqwest;
pub mod types;

Expand Down Expand Up @@ -421,6 +423,10 @@ pub trait TendermintRpcClientExt: TendermintRpcClient {

res.try_into()
}

async fn get_all_validators(&self, height: Height) -> Result<validators::Response, NyxdError> {
Ok(self.validators(height, Paging::All).await?)
}
}

impl<T> TendermintRpcClientExt for T where T: TendermintRpcClient {}
Expand Down
8 changes: 8 additions & 0 deletions common/nym-directory-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ async-trait = { workspace = true }
ics23 = { workspace = true, features = ["host-functions"] }
prost = { workspace = true }
cosmrs = { workspace = true }
serde = { workspace = true }
tracing = { workspace = true }
tokio = { workspace = true, features = ["sync"] }
tendermint-light-client = { workspace = true, optional = true }

nym-lthash = { workspace = true }
nym-crypto = { workspace = true, features = ["asymmetric"] }
Expand All @@ -32,6 +35,11 @@ nym-crypto = { workspace = true, features = ["rand"] }
nym-test-utils = { workspace = true }
anyhow = { workspace = true }
cw-storage-plus = { workspace = true }
nym-validator-client = { workspace = true, features = ["mocks"] }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }

[features]
light-client = ["tendermint-light-client"]

[lints]
workspace = true
Loading
Loading