lite-rpc/src/workers/block_listenser.rs

216 lines
7.2 KiB
Rust
Raw Normal View History

2022-12-16 18:35:49 -08:00
use std::sync::Arc;
2022-12-23 11:58:42 -08:00
use anyhow::{bail, Context};
2022-12-27 02:11:06 -08:00
use dashmap::DashMap;
2022-12-16 18:35:49 -08:00
use futures::StreamExt;
2023-01-04 05:21:00 -08:00
use jsonrpsee::SubscriptionSink;
2023-01-08 09:36:37 -08:00
use log::info;
2023-01-04 08:19:38 -08:00
use solana_client::{
nonblocking::{pubsub_client::PubsubClient, rpc_client::RpcClient},
2023-01-11 21:35:09 -08:00
rpc_client::SerializableTransaction,
2023-01-04 08:19:38 -08:00
rpc_config::{RpcBlockSubscribeConfig, RpcBlockSubscribeFilter},
2023-01-06 22:00:20 -08:00
rpc_response::{Response as RpcResponse, RpcResponseContext},
};
use solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel};
2023-01-04 02:58:25 -08:00
2023-01-10 11:57:20 -08:00
use solana_transaction_status::{
2023-01-27 12:35:29 -08:00
TransactionConfirmationStatus, TransactionStatus, UiConfirmedBlock, UiTransactionStatusMeta,
2023-01-10 11:57:20 -08:00
};
2023-01-27 12:35:29 -08:00
use tokio::{
sync::{mpsc::Sender, RwLock},
task::JoinHandle,
};
use crate::postgres::{Postgres, PostgresBlock, PostgresTx};
2022-12-16 18:35:49 -08:00
2023-01-27 12:35:29 -08:00
use super::{TxProps, TxSender};
2023-01-10 06:56:41 -08:00
2022-12-16 18:35:49 -08:00
/// Background worker which listen's to new blocks
/// and keeps a track of confirmed txs
#[derive(Clone)]
pub struct BlockListener {
pub_sub_client: Arc<PubsubClient>,
2023-01-04 02:58:25 -08:00
commitment_config: CommitmentConfig,
2023-01-10 06:56:41 -08:00
tx_sender: TxSender,
2023-01-04 08:18:27 -08:00
latest_block_info: Arc<RwLock<BlockInformation>>,
2023-01-10 06:56:41 -08:00
pub signature_subscribers: Arc<DashMap<String, SubscriptionSink>>,
2022-12-16 18:35:49 -08:00
}
2023-01-04 08:18:27 -08:00
struct BlockInformation {
pub slot: u64,
pub blockhash: String,
pub block_height: u64,
}
2023-01-27 12:35:29 -08:00
pub struct BlockListnerNotificatons {
pub block: Sender<UiConfirmedBlock>,
pub tx: Sender<TxProps>,
}
2022-12-16 18:35:49 -08:00
impl BlockListener {
2023-01-04 02:58:25 -08:00
pub async fn new(
2023-01-08 06:13:33 -08:00
pub_sub_client: Arc<PubsubClient>,
2023-01-04 02:58:25 -08:00
rpc_client: Arc<RpcClient>,
2023-01-10 06:56:41 -08:00
tx_sender: TxSender,
2023-01-04 02:58:25 -08:00
commitment_config: CommitmentConfig,
) -> anyhow::Result<Self> {
let (latest_block_hash, block_height) = rpc_client
.get_latest_blockhash_with_commitment(commitment_config)
.await?;
2022-12-16 18:35:49 -08:00
Ok(Self {
pub_sub_client,
2023-01-10 06:56:41 -08:00
tx_sender,
2023-01-04 08:18:27 -08:00
latest_block_info: Arc::new(RwLock::new(BlockInformation {
slot: rpc_client.get_slot().await?,
blockhash: latest_block_hash.to_string(),
block_height,
})),
2023-01-04 02:58:25 -08:00
commitment_config,
2023-01-04 05:21:00 -08:00
signature_subscribers: Default::default(),
2022-12-16 18:35:49 -08:00
})
}
2023-01-07 04:40:56 -08:00
pub async fn num_of_sigs_commited(&self, sigs: &[String]) -> usize {
let mut num_of_sigs_commited = 0;
for sig in sigs {
2023-01-10 06:56:41 -08:00
if self.tx_sender.txs_sent.contains_key(sig) {
2023-01-07 04:40:56 -08:00
num_of_sigs_commited += 1;
}
}
num_of_sigs_commited
}
2023-01-04 08:18:27 -08:00
pub async fn get_slot(&self) -> u64 {
self.latest_block_info.read().await.slot
2022-12-16 18:35:49 -08:00
}
2023-01-04 02:58:25 -08:00
pub async fn get_latest_blockhash(&self) -> (String, u64) {
2023-01-04 08:18:27 -08:00
let block = self.latest_block_info.read().await;
(block.blockhash.clone(), block.block_height)
2023-01-04 02:58:25 -08:00
}
2023-01-04 05:21:00 -08:00
pub fn signature_subscribe(&self, signature: String, sink: SubscriptionSink) {
2023-01-05 02:54:00 -08:00
let _ = self.signature_subscribers.insert(signature, sink);
2023-01-04 05:21:00 -08:00
}
pub fn signature_un_subscribe(&self, signature: String) {
self.signature_subscribers.remove(&signature);
}
2023-01-27 12:35:29 -08:00
pub fn listen(self, postgres: Option<Postgres>) -> JoinHandle<anyhow::Result<()>> {
2022-12-16 18:35:49 -08:00
tokio::spawn(async move {
info!("Subscribing to blocks");
2023-01-04 02:58:25 -08:00
let commitment = self.commitment_config.commitment;
let comfirmation_status = match commitment {
2023-01-02 03:44:07 -08:00
CommitmentLevel::Finalized => TransactionConfirmationStatus::Finalized,
_ => TransactionConfirmationStatus::Confirmed,
};
2022-12-23 11:58:42 -08:00
let (mut recv, _) = self
2022-12-16 18:35:49 -08:00
.pub_sub_client
.block_subscribe(
RpcBlockSubscribeFilter::All,
Some(RpcBlockSubscribeConfig {
2023-01-04 02:58:25 -08:00
commitment: Some(self.commitment_config),
2022-12-16 18:35:49 -08:00
encoding: None,
transaction_details: Some(
2023-01-12 05:59:33 -08:00
solana_transaction_status::TransactionDetails::Full,
2022-12-16 18:35:49 -08:00
),
show_rewards: None,
max_supported_transaction_version: None,
}),
)
.await
.context("Error calling block_subscribe")?;
2022-12-27 02:11:06 -08:00
info!("Listening to {commitment:?} blocks");
2022-12-16 18:35:49 -08:00
while let Some(block) = recv.as_mut().next().await {
2023-01-02 03:44:07 -08:00
let slot = block.value.slot;
2022-12-16 18:35:49 -08:00
let Some(block) = block.value.block else {
continue;
};
2023-01-04 02:58:25 -08:00
let Some(block_height) = block.block_height else {
continue;
};
let blockhash = block.blockhash;
2023-01-10 11:57:20 -08:00
let Some(transactions) = block.transactions else {
continue;
};
2022-12-16 18:35:49 -08:00
2023-01-04 08:18:27 -08:00
*self.latest_block_info.write().await = BlockInformation {
slot,
blockhash,
block_height,
};
2023-01-04 02:58:25 -08:00
2023-01-27 12:35:29 -08:00
if let Some(postgres) = &postgres {
postgres.send_block(PostgresBlock {
slot: slot as i64,
leader_id: 0, //FIX:
parent_slot: 0, //FIX:
}).await?;
}
2023-01-11 21:35:09 -08:00
for tx in transactions {
let Some(UiTransactionStatusMeta { err, status, .. }) = tx.meta else {
info!("tx with no meta");
continue;
};
2023-01-10 11:57:20 -08:00
2023-01-11 21:35:09 -08:00
let Some(tx) = tx.transaction.decode() else {
info!("unable to decode tx");
continue;
};
2023-01-10 22:22:10 -08:00
2023-01-11 21:35:09 -08:00
let sig = tx.get_signature().to_string();
2023-01-10 11:57:20 -08:00
2023-01-10 06:56:41 -08:00
if let Some(mut tx_status) = self.tx_sender.txs_sent.get_mut(&sig) {
2023-01-27 12:35:29 -08:00
if let Some(postgres) = &postgres {
postgres.send_tx(PostgresTx {
signature: tx.get_signature().as_ref(),
recent_slot: slot as i64,
forwarded_slot: 0,
processed_slot: None,
cu_consumed: None,
cu_requested: None,
quic_response: 0,
}).await?;
}
2023-01-10 06:56:41 -08:00
tx_status.value_mut().status = Some(TransactionStatus {
slot,
confirmations: None, //TODO: talk about this
2023-01-10 11:57:20 -08:00
status,
err: err.clone(),
confirmation_status: Some(comfirmation_status.clone()),
});
2023-01-08 06:13:33 -08:00
};
2023-01-04 05:21:00 -08:00
// subscribers
2023-01-08 09:32:40 -08:00
if let Some((_sig, mut sink)) = self.signature_subscribers.remove(&sig) {
2023-01-04 05:21:00 -08:00
// none if transaction succeeded
2023-01-06 22:00:20 -08:00
sink.send(&RpcResponse {
context: RpcResponseContext {
slot,
api_version: None,
},
value: serde_json::json!({ "err": err }),
2023-01-12 05:55:04 -08:00
})?;
2023-01-04 05:21:00 -08:00
}
2022-12-16 18:35:49 -08:00
}
}
2022-12-27 02:11:06 -08:00
bail!("Stopped Listening to {commitment:?} blocks")
2022-12-16 18:35:49 -08:00
})
}
}