mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
Cache the block's events within TemporalSerai
Event retrieval was prior: - Retrieve all events in the block, which may be hundreds of KB - Filter to just a few Since it's frequent to want multiple sets of events, each filtered in their own way, this caused the retrieval to happen multiple times. Now, it only will happen once. Also has the scoped clients take a reference, not an owned TemporalSerai.
This commit is contained in:
@@ -11,18 +11,18 @@ const PALLET: &str = "Coins";
|
||||
pub type CoinsEvent = serai_abi::coins::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiCoins<'a>(pub(crate) TemporalSerai<'a>);
|
||||
pub struct SeraiCoins<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||
impl<'a> SeraiCoins<'a> {
|
||||
pub fn into_inner(self) -> TemporalSerai<'a> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub async fn mint_events(&self) -> Result<Vec<CoinsEvent>, SeraiError> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::Coins(event) = event {
|
||||
Some(event).filter(|event| matches!(event, CoinsEvent::Mint { .. }))
|
||||
if matches!(event, CoinsEvent::Mint { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -35,7 +35,11 @@ impl<'a> SeraiCoins<'a> {
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::Coins(event) = event {
|
||||
Some(event).filter(|event| matches!(event, CoinsEvent::BurnWithInstruction { .. }))
|
||||
if matches!(event, CoinsEvent::BurnWithInstruction { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -6,12 +6,14 @@ use crate::{SeraiError, TemporalSerai};
|
||||
pub type DexEvent = serai_abi::dex::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiDex<'a>(pub(crate) TemporalSerai<'a>);
|
||||
pub struct SeraiDex<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||
impl<'a> SeraiDex<'a> {
|
||||
pub async fn events(&self) -> Result<Vec<DexEvent>, SeraiError> {
|
||||
self
|
||||
.0
|
||||
.events(|event| if let serai_abi::Event::Dex(event) = event { Some(event) } else { None })
|
||||
.events(
|
||||
|event| if let serai_abi::Event::Dex(event) = event { Some(event.clone()) } else { None },
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,8 @@ pub type InInstructionsEvent = serai_abi::in_instructions::Event;
|
||||
const PALLET: &str = "InInstructions";
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiInInstructions<'a>(pub(crate) TemporalSerai<'a>);
|
||||
pub struct SeraiInInstructions<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||
impl<'a> SeraiInInstructions<'a> {
|
||||
pub fn into_inner(self) -> TemporalSerai<'a> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub async fn latest_block_for_network(
|
||||
&self,
|
||||
network: NetworkId,
|
||||
@@ -36,7 +32,11 @@ impl<'a> SeraiInInstructions<'a> {
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::InInstructions(event) = event {
|
||||
Some(event).filter(|event| matches!(event, InInstructionsEvent::Batch { .. }))
|
||||
if matches!(event, InInstructionsEvent::Batch { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use thiserror::Error;
|
||||
|
||||
use async_lock::RwLock;
|
||||
use simple_request::{hyper, Request, Client};
|
||||
|
||||
use scale::{Encode, Decode, Compact};
|
||||
@@ -69,8 +70,17 @@ pub struct Serai {
|
||||
genesis: [u8; 32],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TemporalSerai<'a>(pub(crate) &'a Serai, pub(crate) [u8; 32]);
|
||||
type EventsInBlock = Vec<frame_system::EventRecord<Event, [u8; 32]>>;
|
||||
pub struct TemporalSerai<'a> {
|
||||
serai: &'a Serai,
|
||||
block: [u8; 32],
|
||||
events: RwLock<Option<EventsInBlock>>,
|
||||
}
|
||||
impl<'a> Clone for TemporalSerai<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { serai: self.serai, block: self.block, events: RwLock::new(None) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serai {
|
||||
pub async fn call<Req: Serialize, Res: DeserializeOwned>(
|
||||
@@ -289,27 +299,35 @@ impl Serai {
|
||||
/// itself.
|
||||
pub async fn as_of_latest_finalized_block(&self) -> Result<TemporalSerai, SeraiError> {
|
||||
let latest = self.latest_finalized_block_hash().await?;
|
||||
Ok(TemporalSerai(self, latest))
|
||||
Ok(TemporalSerai { serai: self, block: latest, events: RwLock::new(None) })
|
||||
}
|
||||
|
||||
/// Returns a TemporalSerai able to retrieve state as of the specified block.
|
||||
pub fn as_of(&self, block: [u8; 32]) -> TemporalSerai {
|
||||
TemporalSerai(self, block)
|
||||
TemporalSerai { serai: self, block, events: RwLock::new(None) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TemporalSerai<'a> {
|
||||
pub fn into_inner(&self) -> &Serai {
|
||||
self.0
|
||||
}
|
||||
async fn events<E>(
|
||||
&self,
|
||||
filter_map: impl Fn(&Event) -> Option<E>,
|
||||
) -> Result<Vec<E>, SeraiError> {
|
||||
let mut events = self.events.read().await;
|
||||
if events.is_none() {
|
||||
drop(events);
|
||||
let mut events_write = self.events.write().await;
|
||||
#[allow(clippy::unwrap_or_default)]
|
||||
if events_write.is_none() {
|
||||
*events_write = Some(self.storage("System", "Events", ()).await?.unwrap_or(vec![]));
|
||||
}
|
||||
drop(events_write);
|
||||
events = self.events.read().await;
|
||||
}
|
||||
|
||||
async fn events<E>(&self, filter_map: impl Fn(Event) -> Option<E>) -> Result<Vec<E>, SeraiError> {
|
||||
let mut res = vec![];
|
||||
let all_events: Option<Vec<frame_system::EventRecord<Event, [u8; 32]>>> =
|
||||
self.storage("System", "Events", ()).await?;
|
||||
#[allow(clippy::unwrap_or_default)]
|
||||
for event in all_events.unwrap_or(vec![]) {
|
||||
if let Some(event) = filter_map(event.event) {
|
||||
for event in events.as_ref().unwrap() {
|
||||
if let Some(event) = filter_map(&event.event) {
|
||||
res.push(event);
|
||||
}
|
||||
}
|
||||
@@ -328,7 +346,7 @@ impl<'a> TemporalSerai<'a> {
|
||||
full_key.extend(key.encode());
|
||||
|
||||
let res: Option<String> =
|
||||
self.0.call("state_getStorage", [hex::encode(full_key), hex::encode(self.1)]).await?;
|
||||
self.serai.call("state_getStorage", [hex::encode(full_key), hex::encode(self.block)]).await?;
|
||||
let Some(res) = res else { return Ok(None) };
|
||||
let res = Serai::hex_decode(res)?;
|
||||
Ok(Some(R::decode(&mut res.as_slice()).map_err(|_| {
|
||||
@@ -336,19 +354,19 @@ impl<'a> TemporalSerai<'a> {
|
||||
})?))
|
||||
}
|
||||
|
||||
pub fn coins(self) -> SeraiCoins<'a> {
|
||||
pub fn coins(&'a self) -> SeraiCoins<'a> {
|
||||
SeraiCoins(self)
|
||||
}
|
||||
|
||||
pub fn dex(self) -> SeraiDex<'a> {
|
||||
pub fn dex(&'a self) -> SeraiDex<'a> {
|
||||
SeraiDex(self)
|
||||
}
|
||||
|
||||
pub fn in_instructions(self) -> SeraiInInstructions<'a> {
|
||||
pub fn in_instructions(&'a self) -> SeraiInInstructions<'a> {
|
||||
SeraiInInstructions(self)
|
||||
}
|
||||
|
||||
pub fn validator_sets(self) -> SeraiValidatorSets<'a> {
|
||||
pub fn validator_sets(&'a self) -> SeraiValidatorSets<'a> {
|
||||
SeraiValidatorSets(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,18 +16,18 @@ const PALLET: &str = "ValidatorSets";
|
||||
pub type ValidatorSetsEvent = serai_abi::validator_sets::Event;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SeraiValidatorSets<'a>(pub(crate) TemporalSerai<'a>);
|
||||
pub struct SeraiValidatorSets<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||
impl<'a> SeraiValidatorSets<'a> {
|
||||
pub fn into_inner(self) -> TemporalSerai<'a> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub async fn new_set_events(&self) -> Result<Vec<ValidatorSetsEvent>, SeraiError> {
|
||||
self
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::NewSet { .. }))
|
||||
if matches!(event, ValidatorSetsEvent::NewSet { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -40,7 +40,11 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::KeyGen { .. }))
|
||||
if matches!(event, ValidatorSetsEvent::KeyGen { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -53,7 +57,11 @@ impl<'a> SeraiValidatorSets<'a> {
|
||||
.0
|
||||
.events(|event| {
|
||||
if let serai_abi::Event::ValidatorSets(event) = event {
|
||||
Some(event).filter(|event| matches!(event, ValidatorSetsEvent::SetRetired { .. }))
|
||||
if matches!(event, ValidatorSetsEvent::SetRetired { .. }) {
|
||||
Some(event.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user