barreleye_common/chain/
mod.rs

1use async_trait::async_trait;
2use chrono::NaiveDateTime;
3use derive_more::Display;
4use eyre::Result;
5use std::{collections::HashSet, ops::AddAssign, sync::Arc};
6
7pub use crate::chain::bitcoin::Bitcoin;
8use crate::{
9	models::{Balance, Link, Network, Transfer},
10	utils, BlockHeight, PrimaryId, RateLimiter, Warehouse,
11};
12pub use evm::Evm;
13pub use u256::U256;
14
15pub mod bitcoin;
16pub mod evm;
17pub mod u256;
18
19pub type BoxedChain = Box<dyn ChainTrait>;
20
21#[repr(u16)]
22#[derive(Display, Debug, Copy, Clone, PartialEq, Eq, Hash)]
23pub enum ModuleId {
24	BitcoinCoinbase = 101,
25	BitcoinTransfer = 102,
26	BitcoinBalance = 103,
27	BitcoinLink = 104,
28	EvmTransfer = 201,
29	EvmBalance = 202,
30	EvmTokenTransfer = 203,
31	EvmTokenBalance = 204,
32}
33
34#[async_trait]
35pub trait ChainTrait: Send + Sync {
36	async fn connect(&mut self) -> Result<bool>;
37	fn is_connected(&self) -> bool;
38
39	fn get_network(&self) -> Network;
40	fn get_rpc(&self) -> Option<String>;
41	fn get_module_ids(&self) -> Vec<ModuleId>;
42	fn format_address(&self, address: &str) -> String;
43	fn get_rate_limiter(&self) -> Option<Arc<RateLimiter>>;
44
45	async fn get_block_height(&self) -> Result<BlockHeight>;
46
47	async fn process_block(
48		&self,
49		block_height: BlockHeight,
50		modules: Vec<ModuleId>,
51	) -> Result<Option<WarehouseData>>;
52
53	async fn rate_limit(&self) {
54		if let Some(rate_limiter) = &self.get_rate_limiter() {
55			rate_limiter.until_ready().await;
56		}
57	}
58}
59
60#[async_trait]
61pub trait ModuleTrait {
62	fn new(network_id: PrimaryId) -> Self
63	where
64		Self: Sized;
65	fn get_id(&self) -> ModuleId;
66}
67
68#[derive(Debug, Default, Clone)]
69pub struct WarehouseData {
70	saved_at: NaiveDateTime,
71	transfers: HashSet<Transfer>,
72	balances: HashSet<Balance>,
73	links: HashSet<Link>,
74}
75
76impl WarehouseData {
77	pub fn new() -> Self {
78		Self { saved_at: utils::now(), ..Default::default() }
79	}
80
81	pub fn len(&self) -> usize {
82		self.transfers.len() + self.balances.len() + self.links.len()
83	}
84
85	pub fn is_empty(&self) -> bool {
86		self.len() == 0
87	}
88
89	pub fn should_commit(&self) -> bool {
90		utils::ago_in_seconds(5) > self.saved_at && self.len() > 10_000
91	}
92
93	pub async fn commit(&mut self, warehouse: &Warehouse) -> Result<()> {
94		if !self.transfers.is_empty() {
95			Transfer::create_many(warehouse, self.transfers.clone().into_iter().collect()).await?;
96		}
97
98		if !self.balances.is_empty() {
99			Balance::create_many(warehouse, self.balances.clone().into_iter().collect()).await?;
100		}
101
102		if !self.links.is_empty() {
103			Link::create_many(warehouse, self.links.clone().into_iter().collect()).await?;
104		}
105
106		self.clear();
107
108		Ok(())
109	}
110
111	pub fn clear(&mut self) {
112		self.saved_at = utils::now();
113
114		self.transfers.clear();
115		self.balances.clear();
116		self.links.clear();
117	}
118}
119
120impl AddAssign for WarehouseData {
121	fn add_assign(&mut self, rhs: WarehouseData) {
122		self.transfers.extend(rhs.transfers);
123		self.balances.extend(rhs.balances);
124		self.links.extend(rhs.links);
125	}
126}