2021-06-04 08:23:06 -07:00
|
|
|
use {
|
|
|
|
crossbeam_channel::{Receiver, RecvTimeoutError},
|
|
|
|
itertools::izip,
|
|
|
|
solana_ledger::{
|
|
|
|
blockstore::Blockstore,
|
|
|
|
blockstore_processor::{TransactionStatusBatch, TransactionStatusMessage},
|
|
|
|
},
|
|
|
|
solana_runtime::bank::{
|
|
|
|
Bank, InnerInstructionsList, NonceRollbackInfo, TransactionLogMessages,
|
|
|
|
},
|
2021-09-02 23:28:52 -07:00
|
|
|
solana_transaction_status::{
|
|
|
|
extract_and_fmt_memos, InnerInstructions, Reward, TransactionStatusMeta,
|
|
|
|
},
|
2021-06-04 08:23:06 -07:00
|
|
|
std::{
|
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
|
|
|
thread::{self, Builder, JoinHandle},
|
|
|
|
time::Duration,
|
2019-11-20 15:43:10 -08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct TransactionStatusService {
|
|
|
|
thread_hdl: JoinHandle<()>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TransactionStatusService {
|
|
|
|
#[allow(clippy::new_ret_no_self)]
|
|
|
|
pub fn new(
|
2021-03-26 15:47:35 -07:00
|
|
|
write_transaction_status_receiver: Receiver<TransactionStatusMessage>,
|
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: Arc<Blockstore>,
|
2019-11-20 15:43:10 -08:00
|
|
|
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,
|
2021-03-26 15:47:35 -07:00
|
|
|
&max_complete_transaction_status_slot,
|
2020-01-13 13:13:52 -08:00
|
|
|
&blockstore,
|
2019-11-20 15:43:10 -08:00
|
|
|
) {
|
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(
|
2021-03-26 15:47:35 -07:00
|
|
|
write_transaction_status_receiver: &Receiver<TransactionStatusMessage>,
|
|
|
|
max_complete_transaction_status_slot: &Arc<AtomicU64>,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: &Arc<Blockstore>,
|
2020-01-02 19:50:43 -08:00
|
|
|
) -> Result<(), RecvTimeoutError> {
|
2021-03-26 15:47:35 -07:00
|
|
|
match write_transaction_status_receiver.recv_timeout(Duration::from_secs(1))? {
|
|
|
|
TransactionStatusMessage::Batch(TransactionStatusBatch {
|
|
|
|
bank,
|
|
|
|
transactions,
|
|
|
|
statuses,
|
|
|
|
balances,
|
|
|
|
token_balances,
|
|
|
|
inner_instructions,
|
|
|
|
transaction_logs,
|
2021-05-26 14:43:15 -07:00
|
|
|
rent_debits,
|
2021-03-26 15:47:35 -07:00
|
|
|
}) => {
|
|
|
|
let slot = bank.slot();
|
|
|
|
let inner_instructions_iter: Box<
|
|
|
|
dyn Iterator<Item = Option<InnerInstructionsList>>,
|
|
|
|
> = if let Some(inner_instructions) = inner_instructions {
|
|
|
|
Box::new(inner_instructions.into_iter())
|
|
|
|
} else {
|
|
|
|
Box::new(std::iter::repeat_with(|| None))
|
|
|
|
};
|
2021-07-06 12:35:24 -07:00
|
|
|
let transaction_logs_iter: Box<
|
|
|
|
dyn Iterator<Item = Option<TransactionLogMessages>>,
|
|
|
|
> = if let Some(transaction_logs) = transaction_logs {
|
|
|
|
Box::new(transaction_logs.into_iter())
|
|
|
|
} else {
|
|
|
|
Box::new(std::iter::repeat_with(|| None))
|
|
|
|
};
|
2021-03-26 15:47:35 -07:00
|
|
|
for (
|
2021-03-31 16:59:19 -07:00
|
|
|
transaction,
|
2021-03-26 15:47:35 -07:00
|
|
|
(status, nonce_rollback),
|
|
|
|
pre_balances,
|
|
|
|
post_balances,
|
|
|
|
pre_token_balances,
|
|
|
|
post_token_balances,
|
|
|
|
inner_instructions,
|
|
|
|
log_messages,
|
2021-05-26 14:43:15 -07:00
|
|
|
rent_debits,
|
2021-03-26 15:47:35 -07:00
|
|
|
) in izip!(
|
2021-08-17 15:17:56 -07:00
|
|
|
transactions,
|
2021-03-26 15:47:35 -07:00
|
|
|
statuses,
|
|
|
|
balances.pre_balances,
|
|
|
|
balances.post_balances,
|
|
|
|
token_balances.pre_token_balances,
|
|
|
|
token_balances.post_token_balances,
|
|
|
|
inner_instructions_iter,
|
2021-05-26 14:43:15 -07:00
|
|
|
transaction_logs_iter,
|
2021-08-17 15:17:56 -07:00
|
|
|
rent_debits,
|
2021-03-26 15:47:35 -07:00
|
|
|
) {
|
2021-08-17 15:17:56 -07:00
|
|
|
if Bank::can_commit(&status) {
|
2021-03-26 15:47:35 -07:00
|
|
|
let fee_calculator = nonce_rollback
|
|
|
|
.map(|nonce_rollback| nonce_rollback.fee_calculator())
|
|
|
|
.unwrap_or_else(|| {
|
2021-08-13 09:08:20 -07:00
|
|
|
#[allow(deprecated)]
|
2021-08-17 15:17:56 -07:00
|
|
|
bank.get_fee_calculator(transaction.message().recent_blockhash())
|
2021-03-26 15:47:35 -07:00
|
|
|
})
|
|
|
|
.expect("FeeCalculator must exist");
|
2021-08-17 15:17:56 -07:00
|
|
|
let fee = transaction.message().calculate_fee(&fee_calculator);
|
|
|
|
let tx_account_locks = transaction.get_account_locks();
|
2020-09-24 07:36:22 -07:00
|
|
|
|
2021-03-26 15:47:35 -07:00
|
|
|
let inner_instructions = inner_instructions.map(|inner_instructions| {
|
|
|
|
inner_instructions
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, instructions)| InnerInstructions {
|
|
|
|
index: index as u8,
|
|
|
|
instructions,
|
|
|
|
})
|
|
|
|
.filter(|i| !i.instructions.is_empty())
|
|
|
|
.collect()
|
|
|
|
});
|
2020-09-24 07:36:22 -07:00
|
|
|
|
2021-03-26 15:47:35 -07:00
|
|
|
let pre_token_balances = Some(pre_token_balances);
|
|
|
|
let post_token_balances = Some(post_token_balances);
|
2021-05-26 14:43:15 -07:00
|
|
|
let rewards = Some(
|
|
|
|
rent_debits
|
|
|
|
.0
|
|
|
|
.into_iter()
|
|
|
|
.map(|(pubkey, reward_info)| Reward {
|
|
|
|
pubkey: pubkey.to_string(),
|
|
|
|
lamports: reward_info.lamports,
|
|
|
|
post_balance: reward_info.post_balance,
|
|
|
|
reward_type: Some(reward_info.reward_type),
|
2021-07-10 23:18:42 -07:00
|
|
|
commission: reward_info.commission,
|
2021-05-26 14:43:15 -07:00
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
);
|
2020-10-08 12:06:15 -07:00
|
|
|
|
2021-09-02 23:28:52 -07:00
|
|
|
if let Some(memos) = extract_and_fmt_memos(transaction.message()) {
|
|
|
|
blockstore
|
|
|
|
.write_transaction_memos(transaction.signature(), memos)
|
|
|
|
.expect("Expect database write to succeed: TransactionMemos");
|
|
|
|
}
|
|
|
|
|
2021-03-26 15:47:35 -07:00
|
|
|
blockstore
|
|
|
|
.write_transaction_status(
|
|
|
|
slot,
|
2021-08-17 15:17:56 -07:00
|
|
|
*transaction.signature(),
|
|
|
|
tx_account_locks.writable,
|
|
|
|
tx_account_locks.readonly,
|
2021-03-26 15:47:35 -07:00
|
|
|
TransactionStatusMeta {
|
|
|
|
status,
|
|
|
|
fee,
|
|
|
|
pre_balances,
|
|
|
|
post_balances,
|
|
|
|
inner_instructions,
|
|
|
|
log_messages,
|
|
|
|
pre_token_balances,
|
|
|
|
post_token_balances,
|
2021-05-26 14:43:15 -07:00
|
|
|
rewards,
|
2021-03-26 15:47:35 -07:00
|
|
|
},
|
|
|
|
)
|
2021-09-02 23:28:52 -07:00
|
|
|
.expect("Expect database write to succeed: TransactionStatus");
|
2021-03-26 15:47:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TransactionStatusMessage::Freeze(slot) => {
|
|
|
|
max_complete_transaction_status_slot.fetch_max(slot, Ordering::SeqCst);
|
2019-11-20 15:43:10 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn join(self) -> thread::Result<()> {
|
|
|
|
self.thread_hdl.join()
|
|
|
|
}
|
|
|
|
}
|