2021-06-04 08:23:06 -07:00
|
|
|
use {
|
2021-08-23 15:32:15 -07:00
|
|
|
crate::tpu_info::TpuInfo,
|
2022-01-11 02:44:46 -08:00
|
|
|
crossbeam_channel::{Receiver, RecvTimeoutError},
|
2021-06-04 08:23:06 -07:00
|
|
|
log::*,
|
2022-06-08 04:57:12 -07:00
|
|
|
solana_client::{connection_cache::ConnectionCache, tpu_connection::TpuConnection},
|
2022-03-21 23:24:21 -07:00
|
|
|
solana_measure::measure::Measure,
|
2022-05-04 17:06:21 -07:00
|
|
|
solana_metrics::datapoint_warn,
|
2021-06-04 08:23:06 -07:00
|
|
|
solana_runtime::{bank::Bank, bank_forks::BankForks},
|
2022-05-04 17:06:21 -07:00
|
|
|
solana_sdk::{
|
|
|
|
hash::Hash, nonce_account, pubkey::Pubkey, saturating_add_assign, signature::Signature,
|
|
|
|
timing::AtomicInterval, transport::TransportError,
|
|
|
|
},
|
2021-06-04 08:23:06 -07:00
|
|
|
std::{
|
2022-04-21 12:43:08 -07:00
|
|
|
collections::{
|
|
|
|
hash_map::{Entry, HashMap},
|
|
|
|
HashSet,
|
|
|
|
},
|
2022-03-21 23:24:21 -07:00
|
|
|
net::SocketAddr,
|
2022-04-21 12:43:08 -07:00
|
|
|
sync::{
|
2022-05-04 17:06:21 -07:00
|
|
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
2022-04-21 12:43:08 -07:00
|
|
|
Arc, Mutex, RwLock,
|
|
|
|
},
|
|
|
|
thread::{self, sleep, Builder, JoinHandle},
|
2021-06-04 08:23:06 -07:00
|
|
|
time::{Duration, Instant},
|
2020-06-05 21:23:13 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Maximum size of the transaction queue
|
|
|
|
const MAX_TRANSACTION_QUEUE_SIZE: usize = 10_000; // This seems like a lot but maybe it needs to be bigger one day
|
2022-04-21 12:43:08 -07:00
|
|
|
|
2021-10-19 16:11:46 -07:00
|
|
|
/// Default retry interval
|
|
|
|
const DEFAULT_RETRY_RATE_MS: u64 = 2_000;
|
2022-04-21 12:43:08 -07:00
|
|
|
|
2021-10-19 16:11:46 -07:00
|
|
|
/// Default number of leaders to forward transactions to
|
|
|
|
const DEFAULT_LEADER_FORWARD_COUNT: u64 = 2;
|
2021-10-19 22:17:06 -07:00
|
|
|
/// Default max number of time the service will retry broadcast
|
|
|
|
const DEFAULT_SERVICE_MAX_RETRIES: usize = usize::MAX;
|
2020-06-05 21:23:13 -07:00
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
/// Default batch size for sending transaction in batch
|
|
|
|
/// When this size is reached, send out the transactions.
|
|
|
|
const DEFAULT_TRANSACTION_BATCH_SIZE: usize = 1;
|
|
|
|
|
|
|
|
// The maximum transaction batch size
|
|
|
|
pub const MAX_TRANSACTION_BATCH_SIZE: usize = 10_000;
|
|
|
|
|
|
|
|
/// Maximum transaction sends per second
|
|
|
|
pub const MAX_TRANSACTION_SENDS_PER_SECOND: u64 = 1_000;
|
|
|
|
|
|
|
|
/// Default maximum batch waiting time in ms. If this time is reached,
|
|
|
|
/// whatever transactions are cached will be sent.
|
|
|
|
const DEFAULT_BATCH_SEND_RATE_MS: u64 = 1;
|
|
|
|
|
|
|
|
// The maximum transaction batch send rate in MS
|
|
|
|
pub const MAX_BATCH_SEND_RATE_MS: usize = 100_000;
|
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
pub struct SendTransactionService {
|
2022-04-21 12:43:08 -07:00
|
|
|
receive_txn_thread: JoinHandle<()>,
|
|
|
|
retry_thread: JoinHandle<()>,
|
|
|
|
exit: Arc<AtomicBool>,
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
|
2020-07-10 18:14:41 -07:00
|
|
|
pub struct TransactionInfo {
|
2020-08-07 07:45:17 -07:00
|
|
|
pub signature: Signature,
|
|
|
|
pub wire_transaction: Vec<u8>,
|
2021-08-11 00:04:00 -07:00
|
|
|
pub last_valid_block_height: u64,
|
2020-12-29 08:48:43 -08:00
|
|
|
pub durable_nonce_info: Option<(Pubkey, Hash)>,
|
2021-08-24 21:44:13 -07:00
|
|
|
pub max_retries: Option<usize>,
|
|
|
|
retries: usize,
|
2022-04-21 12:43:08 -07:00
|
|
|
/// Last time the transaction was sent
|
|
|
|
last_sent_time: Option<Instant>,
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
|
2020-07-10 18:14:41 -07:00
|
|
|
impl TransactionInfo {
|
2020-12-29 08:48:43 -08:00
|
|
|
pub fn new(
|
|
|
|
signature: Signature,
|
|
|
|
wire_transaction: Vec<u8>,
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height: u64,
|
2020-12-29 08:48:43 -08:00
|
|
|
durable_nonce_info: Option<(Pubkey, Hash)>,
|
2021-08-24 21:44:13 -07:00
|
|
|
max_retries: Option<usize>,
|
2022-04-21 12:43:08 -07:00
|
|
|
last_sent_time: Option<Instant>,
|
2020-12-29 08:48:43 -08:00
|
|
|
) -> Self {
|
2020-07-10 18:14:41 -07:00
|
|
|
Self {
|
|
|
|
signature,
|
|
|
|
wire_transaction,
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2020-12-29 08:48:43 -08:00
|
|
|
durable_nonce_info,
|
2021-08-24 21:44:13 -07:00
|
|
|
max_retries,
|
|
|
|
retries: 0,
|
2022-04-21 12:43:08 -07:00
|
|
|
last_sent_time,
|
2020-07-10 18:14:41 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-22 18:00:42 -07:00
|
|
|
#[derive(Default, Debug, PartialEq, Eq)]
|
2020-06-05 21:23:13 -07:00
|
|
|
struct ProcessTransactionsResult {
|
|
|
|
rooted: u64,
|
|
|
|
expired: u64,
|
|
|
|
retried: u64,
|
2021-08-24 21:44:13 -07:00
|
|
|
max_retries_elapsed: u64,
|
2020-06-05 21:23:13 -07:00
|
|
|
failed: u64,
|
|
|
|
retained: u64,
|
|
|
|
}
|
|
|
|
|
2021-10-19 16:11:46 -07:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Config {
|
|
|
|
pub retry_rate_ms: u64,
|
|
|
|
pub leader_forward_count: u64,
|
2021-10-19 22:17:06 -07:00
|
|
|
pub default_max_retries: Option<usize>,
|
|
|
|
pub service_max_retries: usize,
|
2022-04-21 12:43:08 -07:00
|
|
|
/// The batch size for sending transactions in batches
|
|
|
|
pub batch_size: usize,
|
|
|
|
/// How frequently batches are sent
|
|
|
|
pub batch_send_rate_ms: u64,
|
2021-10-19 16:11:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
retry_rate_ms: DEFAULT_RETRY_RATE_MS,
|
|
|
|
leader_forward_count: DEFAULT_LEADER_FORWARD_COUNT,
|
2021-10-19 22:17:06 -07:00
|
|
|
default_max_retries: None,
|
|
|
|
service_max_retries: DEFAULT_SERVICE_MAX_RETRIES,
|
2022-04-21 12:43:08 -07:00
|
|
|
batch_size: DEFAULT_TRANSACTION_BATCH_SIZE,
|
|
|
|
batch_send_rate_ms: DEFAULT_BATCH_SEND_RATE_MS,
|
2021-10-19 16:11:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-28 08:35:42 -07:00
|
|
|
/// The maximum duration the retry thread may be configured to sleep before
|
|
|
|
/// processing the transactions that need to be retried.
|
|
|
|
pub const MAX_RETRY_SLEEP_MS: u64 = 1000;
|
|
|
|
|
|
|
|
/// The leader info refresh rate.
|
|
|
|
pub const LEADER_INFO_REFRESH_RATE_MS: u64 = 1000;
|
|
|
|
|
|
|
|
/// A struct responsible for holding up-to-date leader information
|
|
|
|
/// used for sending transactions.
|
|
|
|
pub struct CurrentLeaderInfo<T>
|
|
|
|
where
|
|
|
|
T: TpuInfo + std::marker::Send + 'static,
|
|
|
|
{
|
|
|
|
/// The last time the leader info was refreshed
|
|
|
|
last_leader_refresh: Option<Instant>,
|
|
|
|
|
|
|
|
/// The leader info
|
|
|
|
leader_info: Option<T>,
|
|
|
|
|
|
|
|
/// How often to refresh the leader info
|
|
|
|
refresh_rate: Duration,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> CurrentLeaderInfo<T>
|
|
|
|
where
|
|
|
|
T: TpuInfo + std::marker::Send + 'static,
|
|
|
|
{
|
|
|
|
/// Get the leader info, refresh if expired
|
|
|
|
pub fn get_leader_info(&mut self) -> Option<&T> {
|
|
|
|
if let Some(leader_info) = self.leader_info.as_mut() {
|
|
|
|
let now = Instant::now();
|
|
|
|
let need_refresh = self
|
|
|
|
.last_leader_refresh
|
|
|
|
.map(|last| now.duration_since(last) >= self.refresh_rate)
|
|
|
|
.unwrap_or(true);
|
|
|
|
|
|
|
|
if need_refresh {
|
|
|
|
leader_info.refresh_recent_peers();
|
|
|
|
self.last_leader_refresh = Some(now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.leader_info.as_ref()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new(leader_info: Option<T>) -> Self {
|
|
|
|
Self {
|
|
|
|
last_leader_refresh: None,
|
|
|
|
leader_info,
|
|
|
|
refresh_rate: Duration::from_millis(LEADER_INFO_REFRESH_RATE_MS),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-04 17:06:21 -07:00
|
|
|
/// Metrics of the send-transaction-service.
|
|
|
|
#[derive(Default)]
|
|
|
|
struct SendTransactionServiceStats {
|
|
|
|
/// Count of the received transactions
|
|
|
|
received_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of the received duplicate transactions
|
|
|
|
received_duplicate_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of transactions sent in batch
|
|
|
|
sent_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of transactions not being added to retry queue
|
|
|
|
/// due to queue size limit
|
|
|
|
retry_queue_overflow: AtomicU64,
|
|
|
|
|
|
|
|
/// retry queue size
|
|
|
|
retry_queue_size: AtomicU64,
|
|
|
|
|
|
|
|
/// The count of calls of sending transactions which can be in batch or single.
|
|
|
|
send_attempt_count: AtomicU64,
|
|
|
|
|
|
|
|
/// Time spent on transactions in micro seconds
|
|
|
|
send_us: AtomicU64,
|
|
|
|
|
|
|
|
/// Send failure count
|
|
|
|
send_failure_count: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of nonced transactions
|
|
|
|
nonced_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of rooted transactions
|
|
|
|
rooted_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of expired transactions
|
|
|
|
expired_transactions: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of transactions exceeding max retries
|
|
|
|
transactions_exceeding_max_retries: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of retries of transactions
|
|
|
|
retries: AtomicU64,
|
|
|
|
|
|
|
|
/// Count of transactions failed
|
|
|
|
failed_transactions: AtomicU64,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct SendTransactionServiceStatsReport {
|
|
|
|
stats: SendTransactionServiceStats,
|
|
|
|
last_report: AtomicInterval,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SendTransactionServiceStatsReport {
|
|
|
|
/// report metrics of the send transaction service
|
|
|
|
fn report(&self) {
|
|
|
|
if self
|
|
|
|
.last_report
|
|
|
|
.should_update(SEND_TRANSACTION_METRICS_REPORT_RATE_MS)
|
|
|
|
{
|
|
|
|
datapoint_info!(
|
|
|
|
"send_transaction_service",
|
|
|
|
(
|
|
|
|
"recv-tx",
|
|
|
|
self.stats.received_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"recv-duplicate",
|
|
|
|
self.stats
|
|
|
|
.received_duplicate_transactions
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"sent-tx",
|
|
|
|
self.stats.sent_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"retry-queue-overflow",
|
|
|
|
self.stats.retry_queue_overflow.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"retry-queue-size",
|
|
|
|
self.stats.retry_queue_size.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"send-us",
|
|
|
|
self.stats.send_us.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"send-attempt-count",
|
|
|
|
self.stats.send_attempt_count.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"send-failure-count",
|
|
|
|
self.stats.send_failure_count.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"nonced-tx",
|
|
|
|
self.stats.nonced_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"rooted-tx",
|
|
|
|
self.stats.rooted_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"expired-tx",
|
|
|
|
self.stats.expired_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"max-retries-exceeded-tx",
|
|
|
|
self.stats
|
|
|
|
.transactions_exceeding_max_retries
|
|
|
|
.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"retries",
|
|
|
|
self.stats.retries.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"failed-tx",
|
|
|
|
self.stats.failed_transactions.swap(0, Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Report the send transaction memtrics for every 5 seconds.
|
|
|
|
const SEND_TRANSACTION_METRICS_REPORT_RATE_MS: u64 = 5000;
|
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
impl SendTransactionService {
|
2022-04-28 08:35:42 -07:00
|
|
|
pub fn new<T: TpuInfo + std::marker::Send + 'static>(
|
2020-07-08 18:13:42 -07:00
|
|
|
tpu_address: SocketAddr,
|
2020-06-05 21:23:13 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2021-08-23 15:32:15 -07:00
|
|
|
leader_info: Option<T>,
|
2020-07-10 18:14:41 -07:00
|
|
|
receiver: Receiver<TransactionInfo>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2020-12-17 14:37:22 -08:00
|
|
|
retry_rate_ms: u64,
|
|
|
|
leader_forward_count: u64,
|
2021-10-19 16:11:46 -07:00
|
|
|
) -> Self {
|
|
|
|
let config = Config {
|
|
|
|
retry_rate_ms,
|
|
|
|
leader_forward_count,
|
|
|
|
..Config::default()
|
|
|
|
};
|
2022-06-08 04:57:12 -07:00
|
|
|
Self::new_with_config(
|
|
|
|
tpu_address,
|
|
|
|
bank_forks,
|
|
|
|
leader_info,
|
|
|
|
receiver,
|
|
|
|
connection_cache,
|
|
|
|
config,
|
|
|
|
)
|
2021-10-19 16:11:46 -07:00
|
|
|
}
|
|
|
|
|
2022-04-28 08:35:42 -07:00
|
|
|
pub fn new_with_config<T: TpuInfo + std::marker::Send + 'static>(
|
2021-10-19 16:11:46 -07:00
|
|
|
tpu_address: SocketAddr,
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
|
|
|
leader_info: Option<T>,
|
|
|
|
receiver: Receiver<TransactionInfo>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2021-10-19 16:11:46 -07:00
|
|
|
config: Config,
|
2020-06-05 21:23:13 -07:00
|
|
|
) -> Self {
|
2022-05-04 17:06:21 -07:00
|
|
|
let stats_report = Arc::new(SendTransactionServiceStatsReport::default());
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
let retry_transactions = Arc::new(Mutex::new(HashMap::new()));
|
2022-04-28 08:35:42 -07:00
|
|
|
|
|
|
|
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(leader_info)));
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let receive_txn_thread = Self::receive_txn_thread(
|
2020-12-17 14:37:22 -08:00
|
|
|
tpu_address,
|
|
|
|
receiver,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider.clone(),
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache.clone(),
|
2022-04-21 12:43:08 -07:00
|
|
|
config.clone(),
|
|
|
|
retry_transactions.clone(),
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report.clone(),
|
2022-04-21 12:43:08 -07:00
|
|
|
exit.clone(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let retry_thread = Self::retry_thread(
|
|
|
|
tpu_address,
|
2020-12-17 14:37:22 -08:00
|
|
|
bank_forks.clone(),
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache.clone(),
|
2021-10-19 16:11:46 -07:00
|
|
|
config,
|
2022-04-21 12:43:08 -07:00
|
|
|
retry_transactions,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report,
|
2022-04-21 12:43:08 -07:00
|
|
|
exit.clone(),
|
2020-12-17 14:37:22 -08:00
|
|
|
);
|
2022-04-21 12:43:08 -07:00
|
|
|
Self {
|
|
|
|
receive_txn_thread,
|
|
|
|
retry_thread,
|
|
|
|
exit,
|
|
|
|
}
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
/// Thread responsible for receiving transactions from RPC clients.
|
|
|
|
fn receive_txn_thread<T: TpuInfo + std::marker::Send + 'static>(
|
2020-09-08 02:00:49 -07:00
|
|
|
tpu_address: SocketAddr,
|
2020-06-05 21:23:13 -07:00
|
|
|
receiver: Receiver<TransactionInfo>,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: Arc<ConnectionCache>,
|
2021-10-19 16:11:46 -07:00
|
|
|
config: Config,
|
2022-04-21 12:43:08 -07:00
|
|
|
retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report: Arc<SendTransactionServiceStatsReport>,
|
2022-04-21 12:43:08 -07:00
|
|
|
exit: Arc<AtomicBool>,
|
2020-06-05 21:23:13 -07:00
|
|
|
) -> JoinHandle<()> {
|
2022-04-21 12:43:08 -07:00
|
|
|
let mut last_batch_sent = Instant::now();
|
2020-06-05 21:23:13 -07:00
|
|
|
let mut transactions = HashMap::new();
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
info!(
|
|
|
|
"Starting send-transaction-service::receive_txn_thread with config {:?}",
|
|
|
|
config
|
|
|
|
);
|
2020-06-05 21:23:13 -07:00
|
|
|
Builder::new()
|
2022-04-21 12:43:08 -07:00
|
|
|
.name("send-tx-receive".to_string())
|
2020-06-05 21:23:13 -07:00
|
|
|
.spawn(move || loop {
|
2022-04-21 12:43:08 -07:00
|
|
|
let recv_timeout_ms = config.batch_send_rate_ms;
|
2022-05-04 17:06:21 -07:00
|
|
|
let stats = &stats_report.stats;
|
2022-04-28 08:35:42 -07:00
|
|
|
match receiver.recv_timeout(Duration::from_millis(recv_timeout_ms)) {
|
2022-04-21 12:43:08 -07:00
|
|
|
Err(RecvTimeoutError::Disconnected) => {
|
|
|
|
info!("Terminating send-transaction-service.");
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
break;
|
|
|
|
}
|
2020-09-18 09:17:04 -07:00
|
|
|
Err(RecvTimeoutError::Timeout) => {}
|
|
|
|
Ok(transaction_info) => {
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.received_transactions.fetch_add(1, Ordering::Relaxed);
|
2022-01-30 11:27:42 -08:00
|
|
|
let entry = transactions.entry(transaction_info.signature);
|
2022-04-21 12:43:08 -07:00
|
|
|
let mut new_transaction = false;
|
2022-01-30 11:27:42 -08:00
|
|
|
if let Entry::Vacant(_) = entry {
|
2022-04-21 12:43:08 -07:00
|
|
|
if !retry_transactions
|
|
|
|
.lock()
|
|
|
|
.unwrap()
|
|
|
|
.contains_key(&transaction_info.signature)
|
|
|
|
{
|
2022-01-30 11:27:42 -08:00
|
|
|
entry.or_insert(transaction_info);
|
2022-04-21 12:43:08 -07:00
|
|
|
new_transaction = true;
|
2022-01-30 11:27:42 -08:00
|
|
|
}
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
if !new_transaction {
|
2022-05-04 17:06:21 -07:00
|
|
|
stats
|
|
|
|
.received_duplicate_transactions
|
|
|
|
.fetch_add(1, Ordering::Relaxed);
|
2020-09-18 09:17:04 -07:00
|
|
|
}
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
if (!transactions.is_empty()
|
|
|
|
&& last_batch_sent.elapsed().as_millis() as u64 >= config.batch_send_rate_ms)
|
|
|
|
|| transactions.len() >= config.batch_size
|
|
|
|
{
|
2022-05-04 17:06:21 -07:00
|
|
|
stats
|
|
|
|
.sent_transactions
|
|
|
|
.fetch_add(transactions.len() as u64, Ordering::Relaxed);
|
2022-05-22 09:17:59 -07:00
|
|
|
Self::send_transactions_in_batch(
|
2022-04-21 12:43:08 -07:00
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider.lock().unwrap().get_leader_info(),
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2022-04-21 12:43:08 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats,
|
2022-04-21 12:43:08 -07:00
|
|
|
);
|
|
|
|
let last_sent_time = Instant::now();
|
|
|
|
{
|
|
|
|
// take a lock of retry_transactions and move the batch to the retry set.
|
|
|
|
let mut retry_transactions = retry_transactions.lock().unwrap();
|
2022-05-04 17:06:21 -07:00
|
|
|
let transactions_to_retry = transactions.len();
|
|
|
|
let mut transactions_added_to_retry: usize = 0;
|
2022-04-21 12:43:08 -07:00
|
|
|
for (signature, mut transaction_info) in transactions.drain() {
|
|
|
|
let retry_len = retry_transactions.len();
|
|
|
|
let entry = retry_transactions.entry(signature);
|
|
|
|
if let Entry::Vacant(_) = entry {
|
|
|
|
if retry_len >= MAX_TRANSACTION_QUEUE_SIZE {
|
|
|
|
datapoint_warn!("send_transaction_service-queue-overflow");
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
transaction_info.last_sent_time = Some(last_sent_time);
|
2022-05-04 17:06:21 -07:00
|
|
|
saturating_add_assign!(transactions_added_to_retry, 1);
|
2022-04-21 12:43:08 -07:00
|
|
|
entry.or_insert(transaction_info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.retry_queue_overflow.fetch_add(
|
|
|
|
transactions_to_retry.saturating_sub(transactions_added_to_retry)
|
|
|
|
as u64,
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
stats
|
|
|
|
.retry_queue_size
|
|
|
|
.store(retry_transactions.len() as u64, Ordering::Relaxed);
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
2022-04-21 12:43:08 -07:00
|
|
|
last_batch_sent = Instant::now();
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report.report();
|
2020-06-05 21:23:13 -07:00
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
/// Thread responsible for retrying transactions
|
|
|
|
fn retry_thread<T: TpuInfo + std::marker::Send + 'static>(
|
|
|
|
tpu_address: SocketAddr,
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: Arc<ConnectionCache>,
|
2022-04-21 12:43:08 -07:00
|
|
|
config: Config,
|
|
|
|
retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report: Arc<SendTransactionServiceStatsReport>,
|
2022-04-21 12:43:08 -07:00
|
|
|
exit: Arc<AtomicBool>,
|
|
|
|
) -> JoinHandle<()> {
|
|
|
|
info!(
|
|
|
|
"Starting send-transaction-service::retry_thread with config {:?}",
|
|
|
|
config
|
|
|
|
);
|
|
|
|
Builder::new()
|
|
|
|
.name("send-tx-retry".to_string())
|
|
|
|
.spawn(move || loop {
|
|
|
|
let retry_interval_ms = config.retry_rate_ms;
|
2022-05-04 17:06:21 -07:00
|
|
|
let stats = &stats_report.stats;
|
2022-04-28 08:35:42 -07:00
|
|
|
sleep(Duration::from_millis(
|
|
|
|
MAX_RETRY_SLEEP_MS.min(retry_interval_ms),
|
|
|
|
));
|
2022-04-21 12:43:08 -07:00
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
let mut transactions = retry_transactions.lock().unwrap();
|
|
|
|
if !transactions.is_empty() {
|
2022-05-04 17:06:21 -07:00
|
|
|
stats
|
|
|
|
.retry_queue_size
|
|
|
|
.store(transactions.len() as u64, Ordering::Relaxed);
|
2022-04-21 12:43:08 -07:00
|
|
|
let (root_bank, working_bank) = {
|
|
|
|
let bank_forks = bank_forks.read().unwrap();
|
|
|
|
(
|
|
|
|
bank_forks.root_bank().clone(),
|
|
|
|
bank_forks.working_bank().clone(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
let _result = Self::process_transactions(
|
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2022-04-21 12:43:08 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats,
|
2022-04-21 12:43:08 -07:00
|
|
|
);
|
2022-05-04 17:06:21 -07:00
|
|
|
stats_report.report();
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Process transactions in batch.
|
|
|
|
fn send_transactions_in_batch<T: TpuInfo>(
|
|
|
|
tpu_address: &SocketAddr,
|
|
|
|
transactions: &mut HashMap<Signature, TransactionInfo>,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info: Option<&T>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2022-04-21 12:43:08 -07:00
|
|
|
config: &Config,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats: &SendTransactionServiceStats,
|
2022-04-21 12:43:08 -07:00
|
|
|
) {
|
|
|
|
// Processing the transactions in batch
|
|
|
|
let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config);
|
|
|
|
|
|
|
|
let wire_transactions = transactions
|
|
|
|
.iter()
|
|
|
|
.map(|(_, transaction_info)| transaction_info.wire_transaction.as_ref())
|
|
|
|
.collect::<Vec<&[u8]>>();
|
|
|
|
|
|
|
|
for address in &addresses {
|
2022-06-08 04:57:12 -07:00
|
|
|
Self::send_transactions(address, &wire_transactions, connection_cache, stats);
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Retry transactions sent before.
|
2022-04-28 08:35:42 -07:00
|
|
|
fn process_transactions<T: TpuInfo + std::marker::Send + 'static>(
|
2020-06-05 21:23:13 -07:00
|
|
|
working_bank: &Arc<Bank>,
|
|
|
|
root_bank: &Arc<Bank>,
|
|
|
|
tpu_address: &SocketAddr,
|
|
|
|
transactions: &mut HashMap<Signature, TransactionInfo>,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info_provider: &Arc<Mutex<CurrentLeaderInfo<T>>>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2021-10-19 16:11:46 -07:00
|
|
|
config: &Config,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats: &SendTransactionServiceStats,
|
2020-06-05 21:23:13 -07:00
|
|
|
) -> ProcessTransactionsResult {
|
|
|
|
let mut result = ProcessTransactionsResult::default();
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
let mut batched_transactions = HashSet::new();
|
|
|
|
let retry_rate = Duration::from_millis(config.retry_rate_ms);
|
|
|
|
|
2021-08-24 21:44:13 -07:00
|
|
|
transactions.retain(|signature, mut transaction_info| {
|
2020-12-29 08:48:43 -08:00
|
|
|
if transaction_info.durable_nonce_info.is_some() {
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.nonced_transactions.fetch_add(1, Ordering::Relaxed);
|
2020-12-29 08:48:43 -08:00
|
|
|
}
|
2020-06-05 21:23:13 -07:00
|
|
|
if root_bank.has_signature(signature) {
|
|
|
|
info!("Transaction is rooted: {}", signature);
|
|
|
|
result.rooted += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.rooted_transactions.fetch_add(1, Ordering::Relaxed);
|
2020-12-29 08:48:43 -08:00
|
|
|
return false;
|
|
|
|
}
|
2022-04-21 12:43:08 -07:00
|
|
|
let signature_status = working_bank.get_signature_status_slot(signature);
|
2020-12-29 08:48:43 -08:00
|
|
|
if let Some((nonce_pubkey, durable_nonce)) = transaction_info.durable_nonce_info {
|
|
|
|
let nonce_account = working_bank.get_account(&nonce_pubkey).unwrap_or_default();
|
2022-04-21 12:43:08 -07:00
|
|
|
let now = Instant::now();
|
|
|
|
let expired = transaction_info
|
|
|
|
.last_sent_time
|
|
|
|
.map(|last| now.duration_since(last) >= retry_rate)
|
|
|
|
.unwrap_or(false);
|
2022-06-09 08:28:37 -07:00
|
|
|
let verify_nonce_account = nonce_account::verify_nonce_account(
|
|
|
|
&nonce_account,
|
|
|
|
&durable_nonce,
|
|
|
|
working_bank.separate_nonce_from_blockhash(),
|
|
|
|
);
|
|
|
|
if verify_nonce_account.is_none() && signature_status.is_none() && expired {
|
2020-12-29 08:48:43 -08:00
|
|
|
info!("Dropping expired durable-nonce transaction: {}", signature);
|
|
|
|
result.expired += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.expired_transactions.fetch_add(1, Ordering::Relaxed);
|
2020-12-29 08:48:43 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-08-11 00:04:00 -07:00
|
|
|
if transaction_info.last_valid_block_height < root_bank.block_height() {
|
2020-06-05 21:23:13 -07:00
|
|
|
info!("Dropping expired transaction: {}", signature);
|
|
|
|
result.expired += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.expired_transactions.fetch_add(1, Ordering::Relaxed);
|
2020-12-29 08:48:43 -08:00
|
|
|
return false;
|
|
|
|
}
|
2021-10-19 22:17:06 -07:00
|
|
|
|
|
|
|
let max_retries = transaction_info
|
|
|
|
.max_retries
|
|
|
|
.or(config.default_max_retries)
|
|
|
|
.map(|max_retries| max_retries.min(config.service_max_retries));
|
|
|
|
|
|
|
|
if let Some(max_retries) = max_retries {
|
2021-08-24 21:44:13 -07:00
|
|
|
if transaction_info.retries >= max_retries {
|
|
|
|
info!("Dropping transaction due to max retries: {}", signature);
|
|
|
|
result.max_retries_elapsed += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats
|
|
|
|
.transactions_exceeding_max_retries
|
|
|
|
.fetch_add(1, Ordering::Relaxed);
|
2021-08-24 21:44:13 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-12-29 08:48:43 -08:00
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
match signature_status {
|
2020-12-29 08:48:43 -08:00
|
|
|
None => {
|
2022-04-21 12:43:08 -07:00
|
|
|
let now = Instant::now();
|
|
|
|
let need_send = transaction_info
|
|
|
|
.last_sent_time
|
|
|
|
.map(|last| now.duration_since(last) >= retry_rate)
|
|
|
|
.unwrap_or(true);
|
|
|
|
if need_send {
|
|
|
|
if transaction_info.last_sent_time.is_some() {
|
|
|
|
// Transaction sent before is unknown to the working bank, it might have been
|
|
|
|
// dropped or landed in another fork. Re-send it
|
|
|
|
|
|
|
|
info!("Retrying transaction: {}", signature);
|
|
|
|
result.retried += 1;
|
|
|
|
transaction_info.retries += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.retries.fetch_add(1, Ordering::Relaxed);
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
batched_transactions.insert(*signature);
|
|
|
|
transaction_info.last_sent_time = Some(now);
|
2021-01-13 10:14:22 -08:00
|
|
|
}
|
2020-12-29 08:48:43 -08:00
|
|
|
true
|
|
|
|
}
|
|
|
|
Some((_slot, status)) => {
|
|
|
|
if status.is_err() {
|
|
|
|
info!("Dropping failed transaction: {}", signature);
|
|
|
|
result.failed += 1;
|
2022-05-04 17:06:21 -07:00
|
|
|
stats.failed_transactions.fetch_add(1, Ordering::Relaxed);
|
2020-12-29 08:48:43 -08:00
|
|
|
false
|
|
|
|
} else {
|
|
|
|
result.retained += 1;
|
|
|
|
true
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-04-21 12:43:08 -07:00
|
|
|
if !batched_transactions.is_empty() {
|
|
|
|
// Processing the transactions in batch
|
|
|
|
let wire_transactions = transactions
|
|
|
|
.iter()
|
|
|
|
.filter(|(signature, _)| batched_transactions.contains(signature))
|
|
|
|
.map(|(_, transaction_info)| transaction_info.wire_transaction.as_ref())
|
|
|
|
.collect::<Vec<&[u8]>>();
|
|
|
|
|
2022-04-28 08:35:42 -07:00
|
|
|
let iter = wire_transactions.chunks(config.batch_size);
|
|
|
|
for chunk in iter {
|
|
|
|
let mut leader_info_provider = leader_info_provider.lock().unwrap();
|
|
|
|
let leader_info = leader_info_provider.get_leader_info();
|
|
|
|
let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config);
|
|
|
|
|
|
|
|
for address in &addresses {
|
2022-06-08 04:57:12 -07:00
|
|
|
Self::send_transactions(address, chunk, connection_cache, stats);
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-05 21:23:13 -07:00
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2022-05-04 17:06:21 -07:00
|
|
|
fn send_transaction(
|
|
|
|
tpu_address: &SocketAddr,
|
|
|
|
wire_transaction: &[u8],
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2022-05-04 17:06:21 -07:00
|
|
|
) -> Result<(), TransportError> {
|
2022-06-08 04:57:12 -07:00
|
|
|
let conn = connection_cache.get_connection(tpu_address);
|
2022-05-26 08:21:16 -07:00
|
|
|
conn.send_wire_transaction_async(wire_transaction.to_vec())
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
|
2022-05-04 17:06:21 -07:00
|
|
|
fn send_transactions_with_metrics(
|
|
|
|
tpu_address: &SocketAddr,
|
|
|
|
wire_transactions: &[&[u8]],
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2022-05-04 17:06:21 -07:00
|
|
|
) -> Result<(), TransportError> {
|
2022-04-21 12:43:08 -07:00
|
|
|
let wire_transactions = wire_transactions.iter().map(|t| t.to_vec()).collect();
|
2022-06-08 04:57:12 -07:00
|
|
|
let conn = connection_cache.get_connection(tpu_address);
|
2022-05-26 08:21:16 -07:00
|
|
|
conn.send_wire_transaction_batch_async(wire_transactions)
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
|
2022-05-04 17:06:21 -07:00
|
|
|
fn send_transactions(
|
|
|
|
tpu_address: &SocketAddr,
|
|
|
|
wire_transactions: &[&[u8]],
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &Arc<ConnectionCache>,
|
2022-05-04 17:06:21 -07:00
|
|
|
stats: &SendTransactionServiceStats,
|
|
|
|
) {
|
|
|
|
let mut measure = Measure::start("send-us");
|
|
|
|
let result = if wire_transactions.len() == 1 {
|
2022-06-08 04:57:12 -07:00
|
|
|
Self::send_transaction(tpu_address, wire_transactions[0], connection_cache)
|
2022-04-21 12:43:08 -07:00
|
|
|
} else {
|
2022-06-08 04:57:12 -07:00
|
|
|
Self::send_transactions_with_metrics(tpu_address, wire_transactions, connection_cache)
|
2022-05-04 17:06:21 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
if let Err(err) = result {
|
|
|
|
warn!(
|
|
|
|
"Failed to send transaction transaction to {}: {:?}",
|
|
|
|
tpu_address, err
|
|
|
|
);
|
|
|
|
stats.send_failure_count.fetch_add(1, Ordering::Relaxed);
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
2022-05-04 17:06:21 -07:00
|
|
|
|
|
|
|
measure.stop();
|
|
|
|
stats.send_us.fetch_add(measure.as_us(), Ordering::Relaxed);
|
|
|
|
stats.send_attempt_count.fetch_add(1, Ordering::Relaxed);
|
2022-04-21 12:43:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_tpu_addresses<'a, T: TpuInfo>(
|
|
|
|
tpu_address: &'a SocketAddr,
|
2022-04-28 08:35:42 -07:00
|
|
|
leader_info: Option<&'a T>,
|
2022-04-21 12:43:08 -07:00
|
|
|
config: &'a Config,
|
|
|
|
) -> Vec<&'a SocketAddr> {
|
|
|
|
let addresses = leader_info
|
|
|
|
.as_ref()
|
|
|
|
.map(|leader_info| leader_info.get_leader_tpus(config.leader_forward_count));
|
|
|
|
addresses
|
|
|
|
.map(|address_list| {
|
|
|
|
if address_list.is_empty() {
|
|
|
|
vec![tpu_address]
|
|
|
|
} else {
|
|
|
|
address_list
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap_or_else(|| vec![tpu_address])
|
|
|
|
}
|
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
pub fn join(self) -> thread::Result<()> {
|
2022-04-21 12:43:08 -07:00
|
|
|
self.receive_txn_thread.join()?;
|
|
|
|
self.exit.store(true, Ordering::Relaxed);
|
|
|
|
self.retry_thread.join()
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2021-06-04 08:23:06 -07:00
|
|
|
use {
|
|
|
|
super::*,
|
2021-08-23 15:32:15 -07:00
|
|
|
crate::tpu_info::NullTpuInfo,
|
2022-01-11 02:44:46 -08:00
|
|
|
crossbeam_channel::unbounded,
|
2021-06-04 08:23:06 -07:00
|
|
|
solana_sdk::{
|
2022-06-03 07:36:27 -07:00
|
|
|
account::AccountSharedData,
|
|
|
|
genesis_config::create_genesis_config,
|
|
|
|
nonce::{self, state::DurableNonce},
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::Signer,
|
|
|
|
system_program, system_transaction,
|
2021-06-04 08:23:06 -07:00
|
|
|
},
|
2022-04-21 12:43:08 -07:00
|
|
|
std::ops::Sub,
|
2020-07-08 18:13:42 -07:00
|
|
|
};
|
2020-06-05 21:23:13 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn service_exit() {
|
2020-07-08 18:13:42 -07:00
|
|
|
let tpu_address = "127.0.0.1:0".parse().unwrap();
|
2021-08-05 09:53:29 -07:00
|
|
|
let bank = Bank::default_for_tests();
|
2020-07-08 18:13:42 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-01-11 02:44:46 -08:00
|
|
|
let (sender, receiver) = unbounded();
|
2020-06-05 21:23:13 -07:00
|
|
|
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = Arc::new(ConnectionCache::default());
|
2021-08-23 15:32:15 -07:00
|
|
|
let send_tranaction_service = SendTransactionService::new::<NullTpuInfo>(
|
|
|
|
tpu_address,
|
|
|
|
&bank_forks,
|
|
|
|
None,
|
|
|
|
receiver,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-08-23 15:32:15 -07:00
|
|
|
1000,
|
|
|
|
1,
|
|
|
|
);
|
2020-06-05 21:23:13 -07:00
|
|
|
|
2020-09-18 09:17:04 -07:00
|
|
|
drop(sender);
|
2020-06-05 21:23:13 -07:00
|
|
|
send_tranaction_service.join().unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn process_transactions() {
|
|
|
|
solana_logger::setup();
|
|
|
|
|
2020-07-08 18:13:42 -07:00
|
|
|
let (genesis_config, mint_keypair) = create_genesis_config(4);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-07-08 18:13:42 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let tpu_address = "127.0.0.1:0".parse().unwrap();
|
2021-10-19 16:11:46 -07:00
|
|
|
let config = Config {
|
|
|
|
leader_forward_count: 1,
|
|
|
|
..Config::default()
|
|
|
|
};
|
2020-06-05 21:23:13 -07:00
|
|
|
|
|
|
|
let root_bank = Arc::new(Bank::new_from_parent(
|
|
|
|
&bank_forks.read().unwrap().working_bank(),
|
|
|
|
&Pubkey::default(),
|
|
|
|
1,
|
|
|
|
));
|
|
|
|
let rooted_signature = root_bank
|
|
|
|
.transfer(1, &mint_keypair, &mint_keypair.pubkey())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let working_bank = Arc::new(Bank::new_from_parent(&root_bank, &Pubkey::default(), 2));
|
|
|
|
|
|
|
|
let non_rooted_signature = working_bank
|
|
|
|
.transfer(2, &mint_keypair, &mint_keypair.pubkey())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let failed_signature = {
|
|
|
|
let blockhash = working_bank.last_blockhash();
|
2020-07-08 18:13:42 -07:00
|
|
|
let transaction =
|
|
|
|
system_transaction::transfer(&mint_keypair, &Pubkey::default(), 1, blockhash);
|
2020-06-05 21:23:13 -07:00
|
|
|
let signature = transaction.signatures[0];
|
|
|
|
working_bank.process_transaction(&transaction).unwrap_err();
|
|
|
|
signature
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut transactions = HashMap::new();
|
|
|
|
|
2020-12-29 08:48:43 -08:00
|
|
|
info!("Expired transactions are dropped...");
|
2022-04-28 08:35:42 -07:00
|
|
|
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None)));
|
2022-05-04 17:06:21 -07:00
|
|
|
let stats = SendTransactionServiceStats::default();
|
2020-06-05 21:23:13 -07:00
|
|
|
transactions.insert(
|
|
|
|
Signature::default(),
|
2021-08-11 00:04:00 -07:00
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
|
|
|
root_bank.block_height() - 1,
|
|
|
|
None,
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2021-08-11 00:04:00 -07:00
|
|
|
),
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = Arc::new(ConnectionCache::default());
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-06-05 21:23:13 -07:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
expired: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
info!("Rooted transactions are dropped...");
|
|
|
|
transactions.insert(
|
|
|
|
rooted_signature,
|
2021-08-24 21:44:13 -07:00
|
|
|
TransactionInfo::new(
|
|
|
|
rooted_signature,
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2021-08-24 21:44:13 -07:00
|
|
|
),
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-06-05 21:23:13 -07:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
rooted: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
info!("Failed transactions are dropped...");
|
|
|
|
transactions.insert(
|
|
|
|
failed_signature,
|
2021-08-24 21:44:13 -07:00
|
|
|
TransactionInfo::new(
|
|
|
|
failed_signature,
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2021-08-24 21:44:13 -07:00
|
|
|
),
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-06-05 21:23:13 -07:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
failed: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
info!("Non-rooted transactions are kept...");
|
|
|
|
transactions.insert(
|
|
|
|
non_rooted_signature,
|
2021-08-11 00:04:00 -07:00
|
|
|
TransactionInfo::new(
|
|
|
|
non_rooted_signature,
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2021-08-11 00:04:00 -07:00
|
|
|
),
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-06-05 21:23:13 -07:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 1);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
retained: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
transactions.clear();
|
|
|
|
|
|
|
|
info!("Unknown transactions are retried...");
|
|
|
|
transactions.insert(
|
|
|
|
Signature::default(),
|
2021-08-11 00:04:00 -07:00
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now().sub(Duration::from_millis(4000))),
|
2021-08-24 21:44:13 -07:00
|
|
|
),
|
|
|
|
);
|
2022-04-21 12:43:08 -07:00
|
|
|
|
2021-08-24 21:44:13 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2021-08-24 21:44:13 -07:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 1);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
retried: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
transactions.clear();
|
|
|
|
|
|
|
|
info!("Transactions are only retried until max_retries");
|
|
|
|
transactions.insert(
|
|
|
|
Signature::new(&[1; 64]),
|
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
|
|
|
Some(0),
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2021-08-24 21:44:13 -07:00
|
|
|
),
|
|
|
|
);
|
|
|
|
transactions.insert(
|
|
|
|
Signature::new(&[2; 64]),
|
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
|
|
|
working_bank.block_height(),
|
|
|
|
None,
|
|
|
|
Some(1),
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now().sub(Duration::from_millis(4000))),
|
2021-08-11 00:04:00 -07:00
|
|
|
),
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 1);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
retried: 1,
|
2021-08-24 21:44:13 -07:00
|
|
|
max_retries_elapsed: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2021-08-24 21:44:13 -07:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
max_retries_elapsed: 1,
|
2020-12-29 08:48:43 -08:00
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_retry_durable_nonce_transactions() {
|
|
|
|
solana_logger::setup();
|
|
|
|
|
|
|
|
let (genesis_config, mint_keypair) = create_genesis_config(4);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-12-29 08:48:43 -08:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let tpu_address = "127.0.0.1:0".parse().unwrap();
|
2021-10-19 16:11:46 -07:00
|
|
|
let config = Config {
|
|
|
|
leader_forward_count: 1,
|
|
|
|
..Config::default()
|
|
|
|
};
|
2020-12-29 08:48:43 -08:00
|
|
|
|
|
|
|
let root_bank = Arc::new(Bank::new_from_parent(
|
|
|
|
&bank_forks.read().unwrap().working_bank(),
|
|
|
|
&Pubkey::default(),
|
|
|
|
1,
|
|
|
|
));
|
|
|
|
let rooted_signature = root_bank
|
|
|
|
.transfer(1, &mint_keypair, &mint_keypair.pubkey())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let nonce_address = Pubkey::new_unique();
|
2022-06-03 07:36:27 -07:00
|
|
|
let durable_nonce =
|
|
|
|
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
2022-06-09 08:28:37 -07:00
|
|
|
let nonce_state = nonce::state::Versions::new(
|
|
|
|
nonce::State::Initialized(nonce::state::Data::new(
|
|
|
|
Pubkey::default(),
|
|
|
|
durable_nonce,
|
|
|
|
42,
|
|
|
|
)),
|
|
|
|
true, // separate_domains
|
|
|
|
);
|
2021-03-09 13:06:07 -08:00
|
|
|
let nonce_account =
|
|
|
|
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
|
2020-12-29 08:48:43 -08:00
|
|
|
root_bank.store_account(&nonce_address, &nonce_account);
|
|
|
|
|
|
|
|
let working_bank = Arc::new(Bank::new_from_parent(&root_bank, &Pubkey::default(), 2));
|
|
|
|
let non_rooted_signature = working_bank
|
|
|
|
.transfer(2, &mint_keypair, &mint_keypair.pubkey())
|
|
|
|
.unwrap();
|
|
|
|
|
2021-08-11 00:04:00 -07:00
|
|
|
let last_valid_block_height = working_bank.block_height() + 300;
|
2020-12-29 08:48:43 -08:00
|
|
|
|
|
|
|
let failed_signature = {
|
|
|
|
let blockhash = working_bank.last_blockhash();
|
|
|
|
let transaction =
|
|
|
|
system_transaction::transfer(&mint_keypair, &Pubkey::default(), 1, blockhash);
|
|
|
|
let signature = transaction.signatures[0];
|
|
|
|
working_bank.process_transaction(&transaction).unwrap_err();
|
|
|
|
signature
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut transactions = HashMap::new();
|
|
|
|
|
|
|
|
info!("Rooted durable-nonce transactions are dropped...");
|
|
|
|
transactions.insert(
|
|
|
|
rooted_signature,
|
|
|
|
TransactionInfo::new(
|
|
|
|
rooted_signature,
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2022-06-03 07:36:27 -07:00
|
|
|
Some((nonce_address, *durable_nonce.as_hash())),
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2022-04-28 08:35:42 -07:00
|
|
|
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None)));
|
2022-05-04 17:06:21 -07:00
|
|
|
let stats = SendTransactionServiceStats::default();
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = Arc::new(ConnectionCache::default());
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
rooted: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
// Nonce expired case
|
|
|
|
transactions.insert(
|
|
|
|
rooted_signature,
|
|
|
|
TransactionInfo::new(
|
|
|
|
rooted_signature,
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2020-12-29 08:48:43 -08:00
|
|
|
Some((nonce_address, Hash::new_unique())),
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
rooted: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// Expired durable-nonce transactions are dropped; nonce has advanced...
|
|
|
|
info!("Expired durable-nonce transactions are dropped...");
|
|
|
|
transactions.insert(
|
|
|
|
Signature::default(),
|
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2020-12-29 08:48:43 -08:00
|
|
|
Some((nonce_address, Hash::new_unique())),
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now().sub(Duration::from_millis(4000))),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
expired: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
2021-08-11 00:04:00 -07:00
|
|
|
// ... or last_valid_block_height timeout has passed
|
2020-12-29 08:48:43 -08:00
|
|
|
transactions.insert(
|
|
|
|
Signature::default(),
|
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
root_bank.block_height() - 1,
|
2022-06-03 07:36:27 -07:00
|
|
|
Some((nonce_address, *durable_nonce.as_hash())),
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
expired: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
info!("Failed durable-nonce transactions are dropped...");
|
|
|
|
transactions.insert(
|
|
|
|
failed_signature,
|
|
|
|
TransactionInfo::new(
|
|
|
|
failed_signature,
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2020-12-29 08:48:43 -08:00
|
|
|
Some((nonce_address, Hash::new_unique())), // runtime should advance nonce on failed transactions
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert!(transactions.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
failed: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
info!("Non-rooted durable-nonce transactions are kept...");
|
|
|
|
transactions.insert(
|
|
|
|
non_rooted_signature,
|
|
|
|
TransactionInfo::new(
|
|
|
|
non_rooted_signature,
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2020-12-29 08:48:43 -08:00
|
|
|
Some((nonce_address, Hash::new_unique())), // runtime advances nonce when transaction lands
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now()),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 1);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
retained: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
transactions.clear();
|
|
|
|
|
|
|
|
info!("Unknown durable-nonce transactions are retried until nonce advances...");
|
2022-04-21 12:43:08 -07:00
|
|
|
// simulate there was a nonce transaction sent 4 seconds ago (> the retry rate which is 2 seconds)
|
2020-12-29 08:48:43 -08:00
|
|
|
transactions.insert(
|
|
|
|
Signature::default(),
|
|
|
|
TransactionInfo::new(
|
|
|
|
Signature::default(),
|
|
|
|
vec![],
|
2021-08-11 00:04:00 -07:00
|
|
|
last_valid_block_height,
|
2022-06-03 07:36:27 -07:00
|
|
|
Some((nonce_address, *durable_nonce.as_hash())),
|
2021-08-24 21:44:13 -07:00
|
|
|
None,
|
2022-04-21 12:43:08 -07:00
|
|
|
Some(Instant::now().sub(Duration::from_millis(4000))),
|
2020-12-29 08:48:43 -08:00
|
|
|
),
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-06-05 21:23:13 -07:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-06-05 21:23:13 -07:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 1);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
retried: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
2022-04-21 12:43:08 -07:00
|
|
|
// Advance nonce, simulate the transaction was again last sent 4 seconds ago.
|
|
|
|
// This time the transaction should have been dropped.
|
|
|
|
for mut transaction in transactions.values_mut() {
|
|
|
|
transaction.last_sent_time = Some(Instant::now().sub(Duration::from_millis(4000)));
|
|
|
|
}
|
2022-06-03 07:36:27 -07:00
|
|
|
let new_durable_nonce =
|
|
|
|
DurableNonce::from_blockhash(&Hash::new_unique(), /*separate_domains:*/ true);
|
2022-06-09 08:28:37 -07:00
|
|
|
let new_nonce_state = nonce::state::Versions::new(
|
|
|
|
nonce::State::Initialized(nonce::state::Data::new(
|
|
|
|
Pubkey::default(),
|
|
|
|
new_durable_nonce,
|
|
|
|
42,
|
|
|
|
)),
|
|
|
|
true, // separate_domains
|
|
|
|
);
|
2021-03-09 13:06:07 -08:00
|
|
|
let nonce_account =
|
|
|
|
AccountSharedData::new_data(43, &new_nonce_state, &system_program::id()).unwrap();
|
2020-12-29 08:48:43 -08:00
|
|
|
working_bank.store_account(&nonce_address, &nonce_account);
|
2021-08-23 15:32:15 -07:00
|
|
|
let result = SendTransactionService::process_transactions::<NullTpuInfo>(
|
2020-12-29 08:48:43 -08:00
|
|
|
&working_bank,
|
|
|
|
&root_bank,
|
|
|
|
&tpu_address,
|
|
|
|
&mut transactions,
|
2022-04-28 08:35:42 -07:00
|
|
|
&leader_info_provider,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2021-10-19 16:11:46 -07:00
|
|
|
&config,
|
2022-05-04 17:06:21 -07:00
|
|
|
&stats,
|
2020-12-29 08:48:43 -08:00
|
|
|
);
|
|
|
|
assert_eq!(transactions.len(), 0);
|
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
ProcessTransactionsResult {
|
|
|
|
expired: 1,
|
|
|
|
..ProcessTransactionsResult::default()
|
|
|
|
}
|
|
|
|
);
|
2020-06-05 21:23:13 -07:00
|
|
|
}
|
|
|
|
}
|