113 lines
3.4 KiB
Rust
113 lines
3.4 KiB
Rust
use std::sync::Arc;
|
|
|
|
use dashmap::DashMap;
|
|
|
|
use solana_rpc_client::nonblocking::rpc_client::RpcClient;
|
|
use solana_sdk::commitment_config::CommitmentConfig;
|
|
use tokio::sync::RwLock;
|
|
|
|
use crate::workers::BlockInformation;
|
|
|
|
#[derive(Clone)]
|
|
pub struct BlockStore {
|
|
blocks: Arc<DashMap<String, BlockInformation>>,
|
|
latest_confirmed_blockinfo: Arc<RwLock<BlockInformation>>,
|
|
latest_finalized_blockinfo: Arc<RwLock<BlockInformation>>,
|
|
}
|
|
|
|
impl BlockStore {
|
|
pub async fn new(rpc_client: &RpcClient) -> anyhow::Result<Self> {
|
|
let (confirmed_blockhash, confirmed_block) =
|
|
Self::fetch_latest(rpc_client, CommitmentConfig::confirmed()).await?;
|
|
let (finalized_blockhash, finalized_block) =
|
|
Self::fetch_latest(rpc_client, CommitmentConfig::finalized()).await?;
|
|
|
|
Ok(Self {
|
|
latest_confirmed_blockinfo: Arc::new(RwLock::new(confirmed_block.clone())),
|
|
latest_finalized_blockinfo: Arc::new(RwLock::new(finalized_block.clone())),
|
|
blocks: Arc::new({
|
|
let map = DashMap::new();
|
|
map.insert(confirmed_blockhash, confirmed_block);
|
|
map.insert(finalized_blockhash, finalized_block);
|
|
map
|
|
}),
|
|
})
|
|
}
|
|
|
|
pub async fn fetch_latest(
|
|
rpc_client: &RpcClient,
|
|
commitment_config: CommitmentConfig,
|
|
) -> anyhow::Result<(String, BlockInformation)> {
|
|
let (latest_block_hash, block_height) = rpc_client
|
|
.get_latest_blockhash_with_commitment(commitment_config)
|
|
.await?;
|
|
|
|
let latest_block_hash = latest_block_hash.to_string();
|
|
let slot = rpc_client
|
|
.get_slot_with_commitment(commitment_config)
|
|
.await?;
|
|
|
|
Ok((
|
|
latest_block_hash.clone(),
|
|
BlockInformation {
|
|
slot,
|
|
block_height,
|
|
blockhash: latest_block_hash,
|
|
},
|
|
))
|
|
}
|
|
|
|
pub async fn get_block_info(&self, blockhash: &str) -> Option<BlockInformation> {
|
|
let Some(info) = self.blocks.get(blockhash) else {
|
|
return None;
|
|
};
|
|
|
|
Some(info.value().to_owned())
|
|
}
|
|
|
|
// private
|
|
fn get_latest_blockinfo_lock(
|
|
&self,
|
|
commitment_config: CommitmentConfig,
|
|
) -> Arc<RwLock<BlockInformation>> {
|
|
if commitment_config.is_finalized() {
|
|
self.latest_finalized_blockinfo.clone()
|
|
} else {
|
|
self.latest_confirmed_blockinfo.clone()
|
|
}
|
|
}
|
|
|
|
pub async fn get_latest_block_info(
|
|
&self,
|
|
commitment_config: CommitmentConfig,
|
|
) -> BlockInformation {
|
|
let block_info = self
|
|
.get_latest_blockinfo_lock(commitment_config)
|
|
.read()
|
|
.await
|
|
.clone();
|
|
|
|
block_info
|
|
}
|
|
|
|
pub async fn add_block(
|
|
&self,
|
|
block_info: BlockInformation,
|
|
commitment_config: CommitmentConfig,
|
|
) {
|
|
let blockhash = block_info.blockhash.clone();
|
|
// Write to block store first in order to prevent
|
|
// any race condition i.e prevent some one to
|
|
// ask the map what it doesn't have rn
|
|
self.blocks.insert(blockhash, block_info.clone());
|
|
let last_recent_block = self.get_latest_block_info(commitment_config).await;
|
|
|
|
if last_recent_block.slot < block_info.slot {
|
|
*self
|
|
.get_latest_blockinfo_lock(commitment_config)
|
|
.write()
|
|
.await = block_info;
|
|
}
|
|
}
|
|
}
|