use avail_rust_core::H256;
use crate::{Client, GrandpaJustification, RpcError, Sub};
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct GrandpaJustificationSubValue {
pub value: Option<GrandpaJustification>,
pub block_height: u32,
pub block_hash: H256,
}
#[derive(Clone)]
pub struct GrandpaJustificationSub {
sub: Sub,
}
impl GrandpaJustificationSub {
pub fn new(client: Client) -> Self {
Self { sub: Sub::new(client) }
}
pub async fn next(&mut self) -> Result<GrandpaJustificationSubValue, RpcError> {
let info = self.sub.next().await?;
let justification = match self.fetch_justification(info.height).await {
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
return Ok(GrandpaJustificationSubValue {
value: justification,
block_hash: info.hash,
block_height: info.height,
});
}
pub async fn prev(&mut self) -> Result<GrandpaJustificationSubValue, RpcError> {
let info = self.sub.prev().await?;
let justification = match self.fetch_justification(info.height).await {
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
return Ok(GrandpaJustificationSubValue {
value: justification,
block_hash: info.hash,
block_height: info.height,
});
}
pub fn set_block_height(&mut self, block_height: u32) {
self.sub.set_block_height(block_height);
}
pub fn set_pool_rate(&mut self, value: Duration) {
self.sub.set_pool_rate(value);
}
pub fn set_retry_on_error(&mut self, value: Option<bool>) {
self.sub.set_retry_on_error(value);
}
pub fn should_retry_on_error(&self) -> bool {
self.sub.should_retry_on_error()
}
async fn fetch_justification(&self, height: u32) -> Result<Option<GrandpaJustification>, RpcError> {
let retry = Some(self.should_retry_on_error());
let chain = self.sub.client_ref().chain().retry_on(retry, None);
chain.grandpa_block_justification(height).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{clients::mock_client::MockClient, error::Error, prelude::*, subxt_rpcs::RpcClient};
#[tokio::test]
async fn grandpa_justification_sub_test() -> Result<(), Error> {
_ = Client::init_tracing(false);
let (rpc_client, mut commander) = MockClient::new(MAINNET_ENDPOINT);
let client = Client::from_rpc_client(RpcClient::new(rpc_client)).await?;
let mut sub = GrandpaJustificationSub::new(client.clone());
sub.set_block_height(1900031);
let n = sub.next().await?;
assert_eq!(n.block_height, 1900031);
assert!(n.value.is_none());
sub.set_block_height(1900122);
let n = sub.next().await?;
assert_eq!(n.block_height, 1900122);
assert_eq!(n.value.unwrap().commit.target_number, 1900122);
sub.set_block_height(1);
assert_eq!(sub.sub.as_finalized().next_block_height, 1);
commander.justification_ok(Some(GrandpaJustification::default())); commander.justification_ok(None); commander.justification_ok(Some(GrandpaJustification::default())); commander.justification_err(None); commander.justification_ok(Some(GrandpaJustification::default()));
let v = sub.next().await?;
assert!(v.value.is_some());
assert_eq!(v.block_height, 1);
let v = sub.next().await?;
assert!(v.value.is_none());
assert_eq!(v.block_height, 2);
let v = sub.next().await?;
assert!(v.value.is_some());
assert_eq!(v.block_height, 3);
sub.set_retry_on_error(Some(false));
let _ = sub.next().await.expect_err("Expect Error");
assert_eq!(sub.sub.as_finalized().next_block_height, 4);
let v = sub.next().await?;
assert!(v.value.is_some());
assert_eq!(v.block_height, 4);
Ok(())
}
}