use crate::{
AvailHeader, Client, LegacyBlock, RpcError, Sub,
block::{Block, events::BlockEventsQuery},
};
use avail_rust_core::{H256, rpc::BlockPhaseEvent};
use std::time::Duration;
#[derive(Clone)]
pub struct LegacyBlockSub {
sub: Sub,
}
impl LegacyBlockSub {
pub fn new(client: Client) -> Self {
Self { sub: Sub::new(client) }
}
pub async fn next(&mut self) -> Result<Option<LegacyBlock>, RpcError> {
let info = self.sub.next().await?;
let block = match self
.sub
.client_ref()
.chain()
.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
.legacy_block(Some(info.hash))
.await
{
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
Ok(block)
}
pub async fn prev(&mut self) -> Result<Option<LegacyBlock>, RpcError> {
let info = self.sub.prev().await?;
let block = match self
.sub
.client_ref()
.chain()
.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
.legacy_block(Some(info.hash))
.await
{
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
Ok(block)
}
pub fn should_retry_on_error(&self) -> bool {
self.sub.should_retry_on_error()
}
pub fn use_best_block(&mut self, value: bool) {
self.sub.use_best_block(value);
}
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);
}
}
#[derive(Clone)]
pub struct BlockSubValue {
pub value: Block,
pub block_height: u32,
pub block_hash: H256,
}
#[derive(Clone)]
pub struct BlockSub {
sub: Sub,
}
impl BlockSub {
pub fn new(client: Client) -> Self {
Self { sub: Sub::new(client) }
}
pub async fn next(&mut self) -> Result<BlockSubValue, RpcError> {
let info = self.sub.next().await?;
let value = Block::new(self.sub.client_ref().clone(), info.hash);
Ok(BlockSubValue { value, block_hash: info.hash, block_height: info.height })
}
pub async fn prev(&mut self) -> Result<BlockSubValue, RpcError> {
let info = self.sub.prev().await?;
let value = Block::new(self.sub.client_ref().clone(), info.hash);
Ok(BlockSubValue { value, block_hash: info.hash, block_height: info.height })
}
pub fn should_retry_on_error(&self) -> bool {
self.sub.should_retry_on_error()
}
pub fn use_best_block(&mut self, value: bool) {
self.sub.use_best_block(value);
}
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);
}
}
#[derive(Debug, Clone)]
pub struct BlockEventsSubValue {
pub list: Vec<BlockPhaseEvent>,
pub block_height: u32,
pub block_hash: H256,
}
#[derive(Clone)]
pub struct BlockEventsSub {
sub: Sub,
opts: avail_rust_core::rpc::EventOpts,
}
impl BlockEventsSub {
pub fn new(client: Client, opts: avail_rust_core::rpc::EventOpts) -> Self {
Self { sub: Sub::new(client), opts }
}
pub async fn next(&mut self) -> Result<BlockEventsSubValue, crate::Error> {
loop {
let info = self.sub.next().await?;
let block = BlockEventsQuery::new(self.sub.client_ref().clone(), info.hash);
let events = match block.raw(self.opts.clone()).await {
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
if events.is_empty() {
continue;
}
return Ok(BlockEventsSubValue {
list: events,
block_height: info.height,
block_hash: info.hash,
});
}
}
pub fn set_options(&mut self, value: avail_rust_core::rpc::EventOpts) {
self.opts = value;
}
pub fn should_retry_on_error(&self) -> bool {
self.sub.should_retry_on_error()
}
pub fn use_best_block(&mut self, value: bool) {
self.sub.use_best_block(value);
}
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);
}
}
#[derive(Clone)]
pub struct BlockHeaderSub {
sub: Sub,
}
impl BlockHeaderSub {
pub fn new(client: Client) -> Self {
Self { sub: Sub::new(client) }
}
pub async fn next(&mut self) -> Result<Option<AvailHeader>, crate::Error> {
let info = self.sub.next().await?;
let header = match self
.sub
.client_ref()
.chain()
.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
.block_header(Some(info.hash))
.await
{
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
Ok(header)
}
pub async fn prev(&mut self) -> Result<Option<AvailHeader>, crate::Error> {
let info = self.sub.prev().await?;
let header = match self
.sub
.client_ref()
.chain()
.retry_on(Some(self.sub.should_retry_on_error()), Some(true))
.block_header(Some(info.hash))
.await
{
Ok(x) => x,
Err(err) => {
self.sub.set_block_height(info.height);
return Err(err);
},
};
Ok(header)
}
pub fn should_retry_on_error(&self) -> bool {
self.sub.should_retry_on_error()
}
pub fn use_best_block(&mut self, value: bool) {
self.sub.use_best_block(value);
}
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);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{clients::mock_client::MockClient, error::Error, prelude::*, subxt_rpcs::RpcClient};
#[tokio::test]
async fn block_sub_test() -> Result<(), Error> {
let client = Client::new(TURING_ENDPOINT).await?;
let mut sub = BlockSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.next().await?;
assert_eq!(value.block_height, block_height);
let mut sub = BlockSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.prev().await?;
assert_eq!(value.block_height, block_height - 1);
let block_height = 1900000u32;
let mut sub = BlockSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.next().await?;
assert_eq!(value.block_height, block_height + i);
}
let block_height = 1900000u32;
let mut sub = BlockSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.prev().await?;
assert_eq!(value.block_height, block_height - i - 1);
}
let block_height = 1900000u32;
let mut sub = BlockSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.next().await?;
assert_eq!(value.block_height, block_height);
let value = sub.prev().await?;
assert_eq!(value.block_height, block_height - 1);
let block_height = 1900000u32;
let mut sub = BlockSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.prev().await?;
assert_eq!(value.block_height, block_height - 1);
let value = sub.next().await?;
assert_eq!(value.block_height, block_height);
Ok(())
}
#[tokio::test]
async fn header_sub_test() -> Result<(), Error> {
let (rpc_client, mut commander) = MockClient::new(TURING_ENDPOINT);
let client = Client::from_rpc_client(RpcClient::new(rpc_client)).await?;
let mut sub = BlockHeaderSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height);
let mut sub = BlockHeaderSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.number, block_height - 1);
let block_height = 1900000u32;
let mut sub = BlockHeaderSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height + i);
}
let block_height = 1900000u32;
let mut sub = BlockHeaderSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.number, block_height - i - 1);
}
let block_height = 1900000u32;
let mut sub = BlockHeaderSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height);
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.number, block_height - 1);
let block_height = 1900000u32;
let mut sub = BlockHeaderSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.number, block_height - 1);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height);
let block_height = 1900000u32;
let mut sub = BlockHeaderSub::new(client.clone());
sub.set_retry_on_error(Some(false));
sub.set_block_height(block_height);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height);
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
commander.block_header_err(None);
let _ = sub.next().await.expect_err("Should fail");
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.number, block_height + 1);
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 2);
Ok(())
}
#[tokio::test]
async fn legacy_block_sub_test() -> Result<(), Error> {
let (rpc_client, mut commander) = MockClient::new(TURING_ENDPOINT);
let client = Client::from_rpc_client(RpcClient::new(rpc_client)).await?;
let mut sub = LegacyBlockSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height);
let mut sub = LegacyBlockSub::new(client.clone());
let block_height = client.finalized().block_height().await?;
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height - 1);
let block_height = 1900000u32;
let mut sub = LegacyBlockSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height + i);
}
let block_height = 1900000u32;
let mut sub = LegacyBlockSub::new(client.clone());
sub.set_block_height(block_height);
for i in 0..3 {
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height - i - 1);
}
let block_height = 1900000u32;
let mut sub = LegacyBlockSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height);
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height - 1);
let block_height = 1900000u32;
let mut sub = LegacyBlockSub::new(client.clone());
sub.set_block_height(block_height);
let value = sub.prev().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height - 1);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height);
let block_height = 1900000u32;
let mut sub = LegacyBlockSub::new(client.clone());
sub.set_retry_on_error(Some(false));
sub.set_block_height(block_height);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height);
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
commander.legacy_block_err(None);
let _ = sub.next().await.expect_err("Should fail");
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 1);
let value = sub.next().await?.expect("Should be there");
assert_eq!(value.block.header.number, block_height + 1);
assert_eq!(sub.sub.as_finalized().next_block_height, block_height + 2);
Ok(())
}
}