mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 12:09:37 +00:00
Support extracting timestamps from blocks
This commit is contained in:
parent
92ad689c7e
commit
fa2cf03e61
2 changed files with 69 additions and 4 deletions
|
@ -1,6 +1,6 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use scale::{Encode, Decode};
|
use scale::{Encode, Decode, Compact};
|
||||||
mod scale_value;
|
mod scale_value;
|
||||||
pub(crate) use scale_value::{Value, Composite, scale_value, scale_composite};
|
pub(crate) use scale_value::{Value, Composite, scale_value, scale_composite};
|
||||||
|
|
||||||
|
@ -59,6 +59,14 @@ impl SubxtConfig for SeraiConfig {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block(ChainBlock<SeraiConfig>);
|
pub struct Block(ChainBlock<SeraiConfig>);
|
||||||
impl Block {
|
impl Block {
|
||||||
|
fn new(block: ChainBlock<SeraiConfig>) -> Result<Block, SeraiError> {
|
||||||
|
for extrinsic in &block.extrinsics {
|
||||||
|
if extrinsic.0.len() < 3 {
|
||||||
|
Err(SeraiError::InvalidNode)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Block(block))
|
||||||
|
}
|
||||||
pub fn hash(&self) -> [u8; 32] {
|
pub fn hash(&self) -> [u8; 32] {
|
||||||
self.0.header.hash().into()
|
self.0.header.hash().into()
|
||||||
}
|
}
|
||||||
|
@ -66,6 +74,32 @@ impl Block {
|
||||||
self.0.header.number
|
self.0.header.number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the time of this block, set by its producer, as a unix timestamp.
|
||||||
|
pub fn time(&self) -> Result<u64, SeraiError> {
|
||||||
|
for extrinsic in &self.0.extrinsics {
|
||||||
|
// Inherent/unsigned
|
||||||
|
let inherent = (extrinsic.0[0] >> 7) == 0;
|
||||||
|
|
||||||
|
// To timestamp pallet
|
||||||
|
use serai_runtime::Timestamp;
|
||||||
|
let timestamp =
|
||||||
|
extrinsic.0[1] == u8::try_from(PalletInfo::index::<Timestamp>().unwrap()).unwrap();
|
||||||
|
|
||||||
|
// set call
|
||||||
|
let set = extrinsic.0[2] == 0;
|
||||||
|
|
||||||
|
if inherent && timestamp && set {
|
||||||
|
if extrinsic.0.len() < 4 {
|
||||||
|
Err(SeraiError::InvalidNode)?;
|
||||||
|
}
|
||||||
|
return Ok(
|
||||||
|
Compact::<u64>::decode(&mut &extrinsic.0[3 ..]).map_err(|_| SeraiError::InvalidNode)?.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(SeraiError::InvalidNode)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn header(&self) -> &Header {
|
pub fn header(&self) -> &Header {
|
||||||
&self.0.header
|
&self.0.header
|
||||||
}
|
}
|
||||||
|
@ -146,7 +180,7 @@ impl Serai {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_latest_block(&self) -> Result<Block, SeraiError> {
|
pub async fn get_latest_block(&self) -> Result<Block, SeraiError> {
|
||||||
Ok(Block(
|
Block::new(
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
.rpc()
|
.rpc()
|
||||||
|
@ -155,7 +189,7 @@ impl Serai {
|
||||||
.map_err(SeraiError::RpcError)?
|
.map_err(SeraiError::RpcError)?
|
||||||
.ok_or(SeraiError::InvalidNode)?
|
.ok_or(SeraiError::InvalidNode)?
|
||||||
.block,
|
.block,
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no provided method for this
|
// There is no provided method for this
|
||||||
|
@ -207,7 +241,7 @@ impl Serai {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(Block(res.block)))
|
Ok(Some(Block::new(res.block)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideally, this would be get_block_hash, not get_block_by_number
|
// Ideally, this would be get_block_hash, not get_block_by_number
|
||||||
|
|
31
substrate/client/tests/time.rs
Normal file
31
substrate/client/tests/time.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
|
use serai_client::Serai;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
use common::serai;
|
||||||
|
|
||||||
|
serai_test!(
|
||||||
|
async fn time() {
|
||||||
|
let serai = serai().await;
|
||||||
|
|
||||||
|
let mut number = serai.get_latest_block().await.unwrap().number();
|
||||||
|
let mut done = 0;
|
||||||
|
while done < 3 {
|
||||||
|
// Wait for the next block
|
||||||
|
let block = serai.get_latest_block().await.unwrap();
|
||||||
|
if block.number() == number {
|
||||||
|
sleep(Duration::from_secs(1)).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
number = block.number();
|
||||||
|
|
||||||
|
// Make sure the time we extract from the block is within 5 seconds of now
|
||||||
|
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
assert!(now.saturating_sub(block.time().unwrap()) < 5);
|
||||||
|
done += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
Loading…
Reference in a new issue