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};
#[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)>,
}
#[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 {
pub fn commit_calls(&self) -> Vec<Height> {
self.call_log.lock().unwrap().commit.clone()
}
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!()
}
}