2019-11-21 13:23:40 -08:00
|
|
|
use crossbeam_channel::{Receiver, RecvTimeoutError};
|
2019-11-20 15:43:10 -08:00
|
|
|
use solana_client::rpc_request::RpcTransactionStatus;
|
|
|
|
use solana_ledger::{blocktree::Blocktree, blocktree_processor::TransactionStatusBatch};
|
2019-12-07 11:54:10 -08:00
|
|
|
use solana_runtime::bank::{Bank, HashAgeKind};
|
2019-11-20 15:43:10 -08:00
|
|
|
use std::{
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
|
|
|
thread::{self, Builder, JoinHandle},
|
|
|
|
time::Duration,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct TransactionStatusService {
|
|
|
|
thread_hdl: JoinHandle<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TransactionStatusService {
|
|
|
|
#[allow(clippy::new_ret_no_self)]
|
|
|
|
pub fn new(
|
|
|
|
write_transaction_status_receiver: Receiver<TransactionStatusBatch>,
|
|
|
|
blocktree: Arc<Blocktree>,
|
|
|
|
exit: &Arc<AtomicBool>,
|
|
|
|
) -> Self {
|
|
|
|
let exit = exit.clone();
|
|
|
|
let thread_hdl = Builder::new()
|
|
|
|
.name("solana-transaction-status-writer".to_string())
|
|
|
|
.spawn(move || loop {
|
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
break;
|
|
|
|
}
|
2020-01-02 19:50:43 -08:00
|
|
|
if let Err(RecvTimeoutError::Disconnected) = Self::write_transaction_status_batch(
|
2019-11-20 15:43:10 -08:00
|
|
|
&write_transaction_status_receiver,
|
|
|
|
&blocktree,
|
|
|
|
) {
|
2020-01-02 19:50:43 -08:00
|
|
|
break;
|
2019-11-20 15:43:10 -08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
Self { thread_hdl }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_transaction_status_batch(
|
|
|
|
write_transaction_status_receiver: &Receiver<TransactionStatusBatch>,
|
|
|
|
blocktree: &Arc<Blocktree>,
|
2020-01-02 19:50:43 -08:00
|
|
|
) -> Result<(), RecvTimeoutError> {
|
2019-11-20 15:43:10 -08:00
|
|
|
let TransactionStatusBatch {
|
|
|
|
bank,
|
|
|
|
transactions,
|
|
|
|
statuses,
|
2019-12-18 09:56:29 -08:00
|
|
|
balances,
|
2019-11-20 15:43:10 -08:00
|
|
|
} = write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))?;
|
|
|
|
|
|
|
|
let slot = bank.slot();
|
2019-12-18 09:56:29 -08:00
|
|
|
for (((transaction, (status, hash_age_kind)), pre_balances), post_balances) in transactions
|
|
|
|
.iter()
|
|
|
|
.zip(statuses)
|
|
|
|
.zip(balances.pre_balances)
|
|
|
|
.zip(balances.post_balances)
|
|
|
|
{
|
2019-11-20 15:43:10 -08:00
|
|
|
if Bank::can_commit(&status) && !transaction.signatures.is_empty() {
|
2019-12-07 11:54:10 -08:00
|
|
|
let fee_hash = if let Some(HashAgeKind::DurableNonce) = hash_age_kind {
|
|
|
|
bank.last_blockhash()
|
|
|
|
} else {
|
|
|
|
transaction.message().recent_blockhash
|
|
|
|
};
|
2019-11-20 15:43:10 -08:00
|
|
|
let fee_calculator = bank
|
2019-12-07 11:54:10 -08:00
|
|
|
.get_fee_calculator(&fee_hash)
|
2019-11-20 15:43:10 -08:00
|
|
|
.expect("FeeCalculator must exist");
|
|
|
|
let fee = fee_calculator.calculate_fee(transaction.message());
|
|
|
|
blocktree
|
|
|
|
.write_transaction_status(
|
|
|
|
(slot, transaction.signatures[0]),
|
2019-12-18 09:56:29 -08:00
|
|
|
&RpcTransactionStatus {
|
|
|
|
status,
|
|
|
|
fee,
|
|
|
|
pre_balances,
|
|
|
|
post_balances,
|
|
|
|
},
|
2019-11-20 15:43:10 -08:00
|
|
|
)
|
|
|
|
.expect("Expect database write to succeed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn join(self) -> thread::Result<()> {
|
|
|
|
self.thread_hdl.join()
|
|
|
|
}
|
|
|
|
}
|