2018-06-06 08:58:49 -07:00
|
|
|
//! The `banking_stage` processes Transaction messages. It is intended to be used
|
2022-03-21 16:35:31 -07:00
|
|
|
//! to construct a software pipeline. The stage uses all available CPU cores and
|
2018-06-06 08:58:49 -07:00
|
|
|
//! can do its processing in parallel with signature verification on the GPU.
|
2022-08-09 22:39:01 -07:00
|
|
|
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
2022-02-11 00:07:45 -08:00
|
|
|
crate::{
|
2022-07-05 21:24:58 -07:00
|
|
|
forward_packet_batches_by_accounts::ForwardPacketBatchesByAccounts,
|
2022-08-09 22:39:01 -07:00
|
|
|
immutable_deserialized_packet::ImmutableDeserializedPacket,
|
2022-10-20 14:10:48 -07:00
|
|
|
latest_unprocessed_votes::{LatestUnprocessedVotes, VoteSource},
|
2022-02-11 00:07:45 -08:00
|
|
|
leader_slot_banking_stage_metrics::{LeaderSlotMetricsTracker, ProcessTransactionsSummary},
|
2022-02-16 22:14:32 -08:00
|
|
|
leader_slot_banking_stage_timing_metrics::{
|
|
|
|
LeaderExecuteAndCommitTimings, RecordTransactionsTimings,
|
|
|
|
},
|
2022-09-01 08:00:48 -07:00
|
|
|
packet_deserializer::{PacketDeserializer, ReceivePacketResults},
|
2022-02-11 00:07:45 -08:00
|
|
|
qos_service::QosService,
|
2022-06-08 22:25:37 -07:00
|
|
|
sigverify::SigverifyTracerPacketStats,
|
|
|
|
tracer_packet_stats::TracerPacketStats,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_packet_batches::*,
|
|
|
|
unprocessed_transaction_storage::{
|
|
|
|
ThreadType, UnprocessedTransactionStorage, UNPROCESSED_BUFFER_STEP_SIZE,
|
|
|
|
},
|
2022-02-11 00:07:45 -08:00
|
|
|
},
|
2022-06-21 05:56:11 -07:00
|
|
|
core::iter::repeat,
|
2022-05-24 14:01:41 -07:00
|
|
|
crossbeam_channel::{
|
|
|
|
Receiver as CrossbeamReceiver, RecvTimeoutError, Sender as CrossbeamSender,
|
|
|
|
},
|
2022-01-19 00:13:07 -08:00
|
|
|
histogram::Histogram,
|
2021-12-03 09:00:31 -08:00
|
|
|
itertools::Itertools,
|
|
|
|
solana_entry::entry::hash_transactions,
|
|
|
|
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
|
2022-08-04 23:20:27 -07:00
|
|
|
solana_ledger::{
|
|
|
|
blockstore_processor::TransactionStatusSender, token_balances::collect_token_balances,
|
|
|
|
},
|
2022-06-06 18:21:05 -07:00
|
|
|
solana_measure::{measure, measure::Measure},
|
2021-12-22 13:39:59 -08:00
|
|
|
solana_metrics::inc_new_counter_info,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_perf::{
|
|
|
|
data_budget::DataBudget,
|
Banking stage: Deserialize packets only once
Benchmarks show roughly a 6% improvement. The impact could be more
significant when transactions need to be retried a lot.
after patch:
{'name': 'banking_bench_total', 'median': '72767.43'}
{'name': 'banking_bench_tx_total', 'median': '80240.38'}
{'name': 'banking_bench_success_tx_total', 'median': '72767.43'}
test bench_banking_stage_multi_accounts
... bench: 6,137,264 ns/iter (+/- 1,364,111)
test bench_banking_stage_multi_programs
... bench: 10,086,435 ns/iter (+/- 2,921,440)
before patch:
{'name': 'banking_bench_total', 'median': '68572.26'}
{'name': 'banking_bench_tx_total', 'median': '75704.75'}
{'name': 'banking_bench_success_tx_total', 'median': '68572.26'}
test bench_banking_stage_multi_accounts
... bench: 6,521,007 ns/iter (+/- 1,926,741)
test bench_banking_stage_multi_programs
... bench: 10,526,433 ns/iter (+/- 2,736,530)
2022-04-11 08:37:45 -07:00
|
|
|
packet::{Packet, PacketBatch, PACKETS_PER_BATCH},
|
2021-01-14 14:14:16 -08:00
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_poh::poh_recorder::{BankStart, PohRecorder, PohRecorderError, TransactionRecorder},
|
2022-01-04 00:23:56 -08:00
|
|
|
solana_program_runtime::timings::ExecuteTimings,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_runtime::{
|
2022-10-29 12:36:57 -07:00
|
|
|
accounts::TransactionLoadResult,
|
2022-02-03 00:56:36 -08:00
|
|
|
bank::{
|
2022-05-09 06:19:32 -07:00
|
|
|
Bank, CommitTransactionCounts, LoadAndExecuteTransactionsOutput,
|
2022-10-29 12:36:57 -07:00
|
|
|
TransactionBalancesSet, TransactionCheckResult, TransactionExecutionResult,
|
|
|
|
TransactionResults,
|
2022-02-03 00:56:36 -08:00
|
|
|
},
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks::BankForks,
|
2021-12-03 09:00:31 -08:00
|
|
|
bank_utils,
|
2022-01-14 15:44:18 -08:00
|
|
|
cost_model::{CostModel, TransactionCost},
|
2021-12-03 09:00:31 -08:00
|
|
|
transaction_batch::TransactionBatch,
|
2022-04-23 16:10:47 -07:00
|
|
|
transaction_error_metrics::TransactionErrorMetrics,
|
2021-12-03 09:00:31 -08:00
|
|
|
vote_sender_types::ReplayVoteSender,
|
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
clock::{
|
2022-10-20 14:10:48 -07:00
|
|
|
Slot, DEFAULT_TICKS_PER_SLOT, FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET,
|
|
|
|
HOLD_TRANSACTIONS_SLOT_OFFSET, MAX_PROCESSING_AGE,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
2022-10-20 14:10:48 -07:00
|
|
|
feature_set::allow_votes_to_directly_update_vote_state,
|
2021-12-03 09:00:31 -08:00
|
|
|
pubkey::Pubkey,
|
2022-03-13 08:58:57 -07:00
|
|
|
saturating_add_assign,
|
2021-12-03 09:00:31 -08:00
|
|
|
timing::{duration_as_ms, timestamp, AtomicInterval},
|
2022-07-05 21:24:58 -07:00
|
|
|
transaction::{self, SanitizedTransaction, TransactionError, VersionedTransaction},
|
2022-03-25 08:31:40 -07:00
|
|
|
transport::TransportError,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
2022-06-21 05:56:11 -07:00
|
|
|
solana_streamer::sendmmsg::batch_send,
|
2022-08-24 09:47:02 -07:00
|
|
|
solana_tpu_client::{connection_cache::ConnectionCache, tpu_connection::TpuConnection},
|
2022-10-29 12:36:57 -07:00
|
|
|
solana_transaction_status::{
|
|
|
|
token_balances::TransactionTokenBalancesSet, TransactionTokenBalance,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
std::{
|
|
|
|
cmp,
|
2022-03-10 19:19:03 -08:00
|
|
|
collections::HashMap,
|
2021-12-03 09:00:31 -08:00
|
|
|
env,
|
2022-06-21 05:56:11 -07:00
|
|
|
net::{SocketAddr, UdpSocket},
|
2021-12-03 09:00:31 -08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicU64, AtomicUsize, Ordering},
|
2022-07-05 07:29:44 -07:00
|
|
|
Arc, RwLock,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
thread::{self, Builder, JoinHandle},
|
|
|
|
time::{Duration, Instant},
|
2019-09-19 10:06:08 -07:00
|
|
|
},
|
2019-05-10 14:28:38 -07:00
|
|
|
};
|
2018-05-14 16:31:13 -07:00
|
|
|
|
2019-06-28 01:55:24 -07:00
|
|
|
// Fixed thread size seems to be fastest on GCP setup
|
2022-05-15 07:52:47 -07:00
|
|
|
pub const NUM_THREADS: u32 = 6;
|
2019-06-28 01:55:24 -07:00
|
|
|
|
2022-05-15 07:52:47 -07:00
|
|
|
const TOTAL_BUFFERED_PACKETS: usize = 700_000;
|
2018-09-26 05:52:13 -07:00
|
|
|
|
2022-05-15 07:52:47 -07:00
|
|
|
const MAX_NUM_TRANSACTIONS_PER_BATCH: usize = 64;
|
2019-09-10 11:04:03 -07:00
|
|
|
|
2021-10-07 02:38:23 -07:00
|
|
|
const NUM_VOTE_PROCESSING_THREADS: u32 = 2;
|
|
|
|
const MIN_THREADS_BANKING: u32 = 1;
|
2022-03-02 07:08:08 -08:00
|
|
|
const MIN_TOTAL_THREADS: u32 = NUM_VOTE_PROCESSING_THREADS + MIN_THREADS_BANKING;
|
2021-10-07 02:38:23 -07:00
|
|
|
|
2022-05-18 13:37:47 -07:00
|
|
|
const SLOT_BOUNDARY_CHECK_PERIOD: Duration = Duration::from_millis(10);
|
2022-06-08 22:25:37 -07:00
|
|
|
pub type BankingPacketBatch = (Vec<PacketBatch>, Option<SigverifyTracerPacketStats>);
|
2022-05-24 14:01:41 -07:00
|
|
|
pub type BankingPacketSender = CrossbeamSender<BankingPacketBatch>;
|
|
|
|
pub type BankingPacketReceiver = CrossbeamReceiver<BankingPacketBatch>;
|
2022-05-18 13:37:47 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
pub struct ProcessTransactionBatchOutput {
|
|
|
|
// The number of transactions filtered out by the cost model
|
|
|
|
cost_model_throttled_transactions_count: usize,
|
2022-02-16 22:14:32 -08:00
|
|
|
// Amount of time spent running the cost model
|
|
|
|
cost_model_us: u64,
|
2022-02-03 00:56:36 -08:00
|
|
|
execute_and_commit_transactions_output: ExecuteAndCommitTransactionsOutput,
|
|
|
|
}
|
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
struct RecordTransactionsSummary {
|
|
|
|
// Metrics describing how time was spent recording transactions
|
|
|
|
record_transactions_timings: RecordTransactionsTimings,
|
|
|
|
// Result of trying to record the transactions into the PoH stream
|
2022-04-21 06:06:26 -07:00
|
|
|
result: Result<(), PohRecorderError>,
|
2022-06-23 12:37:38 -07:00
|
|
|
// Index in the slot of the first transaction recorded
|
|
|
|
starting_transaction_index: Option<usize>,
|
2022-02-16 22:14:32 -08:00
|
|
|
}
|
|
|
|
|
2022-05-22 18:00:42 -07:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2022-04-21 00:38:07 -07:00
|
|
|
pub enum CommitTransactionDetails {
|
|
|
|
Committed { compute_units: u64 },
|
|
|
|
NotCommitted,
|
|
|
|
}
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
pub struct ExecuteAndCommitTransactionsOutput {
|
|
|
|
// Total number of transactions that were passed as candidates for execution
|
|
|
|
transactions_attempted_execution_count: usize,
|
|
|
|
// The number of transactions of that were executed. See description of in `ProcessTransactionsSummary`
|
|
|
|
// for possible outcomes of execution.
|
|
|
|
executed_transactions_count: usize,
|
|
|
|
// Total number of the executed transactions that returned success/not
|
|
|
|
// an error.
|
|
|
|
executed_with_successful_result_count: usize,
|
|
|
|
// Transactions that either were not executed, or were executed and failed to be committed due
|
|
|
|
// to the block ending.
|
|
|
|
retryable_transaction_indexes: Vec<usize>,
|
|
|
|
// A result that indicates whether transactions were successfully
|
2022-04-21 00:38:07 -07:00
|
|
|
// committed into the Poh stream.
|
|
|
|
commit_transactions_result: Result<Vec<CommitTransactionDetails>, PohRecorderError>,
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings: LeaderExecuteAndCommitTimings,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters: TransactionErrorMetrics,
|
2022-02-03 00:56:36 -08:00
|
|
|
}
|
|
|
|
|
2021-02-12 03:27:37 -08:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct BankingStageStats {
|
2021-07-28 18:16:36 -07:00
|
|
|
last_report: AtomicInterval,
|
2021-02-12 03:27:37 -08:00
|
|
|
id: u32,
|
2021-12-16 09:44:10 -08:00
|
|
|
receive_and_buffer_packets_count: AtomicUsize,
|
2021-09-15 13:53:55 -07:00
|
|
|
dropped_packets_count: AtomicUsize,
|
2021-12-22 21:05:10 -08:00
|
|
|
pub(crate) dropped_duplicated_packets_count: AtomicUsize,
|
2021-02-12 03:27:37 -08:00
|
|
|
newly_buffered_packets_count: AtomicUsize,
|
|
|
|
current_buffered_packets_count: AtomicUsize,
|
|
|
|
rebuffered_packets_count: AtomicUsize,
|
|
|
|
consumed_buffered_packets_count: AtomicUsize,
|
2022-06-02 11:14:58 -07:00
|
|
|
forwarded_transaction_count: AtomicUsize,
|
|
|
|
forwarded_vote_count: AtomicUsize,
|
2022-01-19 00:13:07 -08:00
|
|
|
batch_packet_indexes_len: Histogram,
|
2021-04-12 23:28:08 -07:00
|
|
|
|
|
|
|
// Timing
|
|
|
|
consume_buffered_packets_elapsed: AtomicU64,
|
2021-12-16 09:44:10 -08:00
|
|
|
receive_and_buffer_packets_elapsed: AtomicU64,
|
2021-04-12 23:28:08 -07:00
|
|
|
filter_pending_packets_elapsed: AtomicU64,
|
|
|
|
packet_conversion_elapsed: AtomicU64,
|
|
|
|
transaction_processing_elapsed: AtomicU64,
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BankingStageStats {
|
|
|
|
pub fn new(id: u32) -> Self {
|
|
|
|
BankingStageStats {
|
|
|
|
id,
|
2022-01-19 00:13:07 -08:00
|
|
|
batch_packet_indexes_len: Histogram::configure()
|
|
|
|
.max_value(PACKETS_PER_BATCH as u64)
|
|
|
|
.build()
|
|
|
|
.unwrap(),
|
2021-02-12 03:27:37 -08:00
|
|
|
..BankingStageStats::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-14 13:52:45 -08:00
|
|
|
fn is_empty(&self) -> bool {
|
2021-12-16 09:44:10 -08:00
|
|
|
0 == self
|
|
|
|
.receive_and_buffer_packets_count
|
|
|
|
.load(Ordering::Relaxed) as u64
|
2021-12-14 13:52:45 -08:00
|
|
|
+ self.dropped_packets_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self
|
|
|
|
.dropped_duplicated_packets_count
|
|
|
|
.load(Ordering::Relaxed) as u64
|
|
|
|
+ self.newly_buffered_packets_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self.current_buffered_packets_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self.rebuffered_packets_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self.consumed_buffered_packets_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self
|
|
|
|
.consume_buffered_packets_elapsed
|
|
|
|
.load(Ordering::Relaxed)
|
2021-12-16 09:44:10 -08:00
|
|
|
+ self
|
|
|
|
.receive_and_buffer_packets_elapsed
|
|
|
|
.load(Ordering::Relaxed)
|
2021-12-14 13:52:45 -08:00
|
|
|
+ self.filter_pending_packets_elapsed.load(Ordering::Relaxed)
|
|
|
|
+ self.packet_conversion_elapsed.load(Ordering::Relaxed)
|
|
|
|
+ self.transaction_processing_elapsed.load(Ordering::Relaxed)
|
2022-06-02 11:14:58 -07:00
|
|
|
+ self.forwarded_transaction_count.load(Ordering::Relaxed) as u64
|
|
|
|
+ self.forwarded_vote_count.load(Ordering::Relaxed) as u64
|
2022-01-19 00:13:07 -08:00
|
|
|
+ self.batch_packet_indexes_len.entries()
|
2021-12-14 13:52:45 -08:00
|
|
|
}
|
|
|
|
|
2022-01-19 00:13:07 -08:00
|
|
|
fn report(&mut self, report_interval_ms: u64) {
|
2022-03-21 16:35:31 -07:00
|
|
|
// skip reporting metrics if stats is empty
|
2021-12-14 13:52:45 -08:00
|
|
|
if self.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
2021-07-28 18:16:36 -07:00
|
|
|
if self.last_report.should_update(report_interval_ms) {
|
2021-02-12 03:27:37 -08:00
|
|
|
datapoint_info!(
|
|
|
|
"banking_stage-loop-stats",
|
|
|
|
("id", self.id as i64, i64),
|
|
|
|
(
|
2021-12-16 09:44:10 -08:00
|
|
|
"receive_and_buffer_packets_count",
|
|
|
|
self.receive_and_buffer_packets_count
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
2021-02-12 03:27:37 -08:00
|
|
|
i64
|
|
|
|
),
|
2021-09-15 13:53:55 -07:00
|
|
|
(
|
|
|
|
"dropped_packets_count",
|
|
|
|
self.dropped_packets_count.swap(0, Ordering::Relaxed) as i64,
|
2021-02-12 03:27:37 -08:00
|
|
|
i64
|
|
|
|
),
|
2021-10-20 19:56:48 -07:00
|
|
|
(
|
|
|
|
"dropped_duplicated_packets_count",
|
|
|
|
self.dropped_duplicated_packets_count
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
2021-02-12 03:27:37 -08:00
|
|
|
(
|
|
|
|
"newly_buffered_packets_count",
|
|
|
|
self.newly_buffered_packets_count.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"current_buffered_packets_count",
|
|
|
|
self.current_buffered_packets_count
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"rebuffered_packets_count",
|
|
|
|
self.rebuffered_packets_count.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
2021-09-15 07:19:39 -07:00
|
|
|
(
|
|
|
|
"consumed_buffered_packets_count",
|
|
|
|
self.consumed_buffered_packets_count
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
2022-06-02 11:14:58 -07:00
|
|
|
(
|
|
|
|
"forwarded_transaction_count",
|
|
|
|
self.forwarded_transaction_count.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"forwarded_vote_count",
|
|
|
|
self.forwarded_vote_count.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
2021-04-12 23:28:08 -07:00
|
|
|
(
|
|
|
|
"consume_buffered_packets_elapsed",
|
|
|
|
self.consume_buffered_packets_elapsed
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
2021-12-16 09:44:10 -08:00
|
|
|
"receive_and_buffer_packets_elapsed",
|
|
|
|
self.receive_and_buffer_packets_elapsed
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
2021-04-12 23:28:08 -07:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"filter_pending_packets_elapsed",
|
|
|
|
self.filter_pending_packets_elapsed
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"packet_conversion_elapsed",
|
|
|
|
self.packet_conversion_elapsed.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"transaction_processing_elapsed",
|
|
|
|
self.transaction_processing_elapsed
|
|
|
|
.swap(0, Ordering::Relaxed) as i64,
|
|
|
|
i64
|
|
|
|
),
|
2022-01-19 00:13:07 -08:00
|
|
|
(
|
|
|
|
"packet_batch_indices_len_min",
|
|
|
|
self.batch_packet_indexes_len.minimum().unwrap_or(0) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"packet_batch_indices_len_max",
|
|
|
|
self.batch_packet_indexes_len.maximum().unwrap_or(0) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"packet_batch_indices_len_mean",
|
|
|
|
self.batch_packet_indexes_len.mean().unwrap_or(0) as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"packet_batch_indices_len_90pct",
|
|
|
|
self.batch_packet_indexes_len.percentile(90.0).unwrap_or(0) as i64,
|
|
|
|
i64
|
|
|
|
)
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
2022-01-19 00:13:07 -08:00
|
|
|
self.batch_packet_indexes_len.clear();
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-29 12:36:57 -07:00
|
|
|
#[derive(Default)]
|
|
|
|
struct PreBalanceInfo {
|
|
|
|
native: Vec<Vec<u64>>,
|
|
|
|
token: Vec<Vec<TransactionTokenBalance>>,
|
|
|
|
mint_decimals: HashMap<Pubkey, u8>,
|
|
|
|
}
|
|
|
|
|
2022-03-13 08:58:57 -07:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct BatchedTransactionDetails {
|
|
|
|
pub costs: BatchedTransactionCostDetails,
|
|
|
|
pub errors: BatchedTransactionErrorDetails,
|
|
|
|
}
|
|
|
|
|
2022-01-14 15:44:18 -08:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct BatchedTransactionCostDetails {
|
|
|
|
pub batched_signature_cost: u64,
|
|
|
|
pub batched_write_lock_cost: u64,
|
|
|
|
pub batched_data_bytes_cost: u64,
|
2022-04-19 11:25:47 -07:00
|
|
|
pub batched_builtins_execute_cost: u64,
|
|
|
|
pub batched_bpf_execute_cost: u64,
|
2022-01-14 15:44:18 -08:00
|
|
|
}
|
|
|
|
|
2022-03-13 08:58:57 -07:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct BatchedTransactionErrorDetails {
|
|
|
|
pub batched_retried_txs_per_block_limit_count: u64,
|
|
|
|
pub batched_retried_txs_per_vote_limit_count: u64,
|
|
|
|
pub batched_retried_txs_per_account_limit_count: u64,
|
|
|
|
pub batched_retried_txs_per_account_data_block_limit_count: u64,
|
|
|
|
pub batched_dropped_txs_per_account_data_total_limit_count: u64,
|
|
|
|
}
|
|
|
|
|
2018-06-06 08:58:49 -07:00
|
|
|
/// Stores the stage's thread handle and output receiver.
|
2018-05-14 16:31:13 -07:00
|
|
|
pub struct BankingStage {
|
2019-03-03 16:44:06 -08:00
|
|
|
bank_thread_hdls: Vec<JoinHandle<()>>,
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
2021-03-15 17:11:15 -07:00
|
|
|
#[derive(Debug, Clone)]
|
2019-04-13 23:19:54 -07:00
|
|
|
pub enum BufferedPacketsDecision {
|
2021-03-15 17:11:15 -07:00
|
|
|
Consume(u128),
|
2019-04-13 23:19:54 -07:00
|
|
|
Forward,
|
2021-03-03 10:23:05 -08:00
|
|
|
ForwardAndHold,
|
2019-04-13 23:19:54 -07:00
|
|
|
Hold,
|
|
|
|
}
|
|
|
|
|
2021-10-07 02:38:23 -07:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum ForwardOption {
|
|
|
|
NotForward,
|
|
|
|
ForwardTpuVote,
|
|
|
|
ForwardTransaction,
|
|
|
|
}
|
|
|
|
|
2022-09-14 10:40:44 -07:00
|
|
|
#[derive(Debug, Default)]
|
2022-07-05 21:24:58 -07:00
|
|
|
pub struct FilterForwardingResults {
|
2022-09-14 10:40:44 -07:00
|
|
|
pub(crate) total_forwardable_packets: usize,
|
|
|
|
pub(crate) total_tracer_packets_in_buffer: usize,
|
|
|
|
pub(crate) total_forwardable_tracer_packets: usize,
|
2022-09-29 14:33:40 -07:00
|
|
|
pub(crate) total_packet_conversion_us: u64,
|
|
|
|
pub(crate) total_filter_packets_us: u64,
|
2022-06-08 22:25:37 -07:00
|
|
|
}
|
|
|
|
|
2018-05-14 16:31:13 -07:00
|
|
|
impl BankingStage {
|
2018-07-05 14:41:53 -07:00
|
|
|
/// Create the stage using `bank`. Exit when `verified_receiver` is dropped.
|
2018-12-07 19:01:28 -08:00
|
|
|
#[allow(clippy::new_ret_no_self)]
|
2022-07-05 21:24:58 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2018-05-14 16:31:13 -07:00
|
|
|
pub fn new(
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: &Arc<ClusterInfo>,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_receiver: BankingPacketReceiver,
|
|
|
|
tpu_verified_vote_receiver: BankingPacketReceiver,
|
|
|
|
verified_vote_receiver: BankingPacketReceiver,
|
2019-11-20 15:43:10 -08:00
|
|
|
transaction_status_sender: Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: ReplayVoteSender,
|
2021-10-19 12:37:33 -07:00
|
|
|
cost_model: Arc<RwLock<CostModel>>,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: Arc<ConnectionCache>,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2019-03-18 22:08:21 -07:00
|
|
|
) -> Self {
|
|
|
|
Self::new_num_threads(
|
|
|
|
cluster_info,
|
|
|
|
poh_recorder,
|
|
|
|
verified_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
tpu_verified_vote_receiver,
|
2019-04-17 21:07:45 -07:00
|
|
|
verified_vote_receiver,
|
2019-06-28 01:55:24 -07:00
|
|
|
Self::num_threads(),
|
2019-11-20 15:43:10 -08:00
|
|
|
transaction_status_sender,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-10-19 12:37:33 -07:00
|
|
|
cost_model,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2019-03-18 22:08:21 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-12-22 21:05:10 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
banking-bench: Add and rearrange options
- Add write-lock-contention option, replacing same_payer
- write-lock-contention also has a same-batch-only value, where
contention happens only inside batches, not between them
- Rename num-threads to batches-per-iteration, which is closer to what
it is actually doing.
- Add num-banking-threads as a new option
- Rename packets-per-chunk to packets-per-batch, because this is closer
to what's happening; and it was previously confusing that num-chunks
had little to do with packets-per-chunk.
Example output for a iterations=100 and a permutation of inputs:
contention,threads,batchsize,batchcount,tps
none, 3,192, 4,65290.30
none, 4,192, 4,77358.06
none, 5,192, 4,86436.65
none, 3, 12,64,43944.57
none, 4, 12,64,65852.15
none, 5, 12,64,70674.37
same-batch-only,3,192, 4,3928.21
same-batch-only,4,192, 4,6460.15
same-batch-only,5,192, 4,7242.85
same-batch-only,3, 12,64,11377.58
same-batch-only,4, 12,64,19582.79
same-batch-only,5, 12,64,24648.45
full, 3,192, 4,3914.26
full, 4,192, 4,2102.99
full, 5,192, 4,3041.87
full, 3, 12,64,11316.17
full, 4, 12,64,2224.99
full, 5, 12,64,5240.32
2022-04-14 06:54:38 -07:00
|
|
|
pub fn new_num_threads(
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: &Arc<ClusterInfo>,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_receiver: BankingPacketReceiver,
|
|
|
|
tpu_verified_vote_receiver: BankingPacketReceiver,
|
|
|
|
verified_vote_receiver: BankingPacketReceiver,
|
2019-03-18 22:08:21 -07:00
|
|
|
num_threads: u32,
|
2019-11-20 15:43:10 -08:00
|
|
|
transaction_status_sender: Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: ReplayVoteSender,
|
2021-10-19 12:37:33 -07:00
|
|
|
cost_model: Arc<RwLock<CostModel>>,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: Arc<ConnectionCache>,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2019-03-03 16:44:06 -08:00
|
|
|
) -> Self {
|
2022-03-02 07:08:08 -08:00
|
|
|
assert!(num_threads >= MIN_TOTAL_THREADS);
|
2018-09-26 05:52:13 -07:00
|
|
|
// Single thread to generate entries from many banks.
|
|
|
|
// This thread talks to poh_service and broadcasts the entries once they have been recorded.
|
2019-03-02 10:25:16 -08:00
|
|
|
// Once an entry has been recorded, its blockhash is registered with the bank.
|
2021-09-21 08:49:41 -07:00
|
|
|
let data_budget = Arc::new(DataBudget::default());
|
2022-05-04 19:50:56 -07:00
|
|
|
let batch_limit =
|
|
|
|
TOTAL_BUFFERED_PACKETS / ((num_threads - NUM_VOTE_PROCESSING_THREADS) as usize);
|
2022-10-20 14:10:48 -07:00
|
|
|
// Keeps track of extraneous vote transactions for the vote threads
|
|
|
|
let latest_unprocessed_votes = Arc::new(LatestUnprocessedVotes::new());
|
|
|
|
let should_split_voting_threads = bank_forks
|
|
|
|
.read()
|
|
|
|
.map(|bank_forks| {
|
|
|
|
let bank = bank_forks.root_bank();
|
|
|
|
bank.feature_set
|
|
|
|
.is_active(&allow_votes_to_directly_update_vote_state::id())
|
|
|
|
})
|
|
|
|
.unwrap_or(false);
|
2018-09-26 05:52:13 -07:00
|
|
|
// Many banks that process transactions in parallel.
|
2019-03-27 04:37:36 -07:00
|
|
|
let bank_thread_hdls: Vec<JoinHandle<()>> = (0..num_threads)
|
2019-04-17 21:07:45 -07:00
|
|
|
.map(|i| {
|
2022-10-20 14:10:48 -07:00
|
|
|
let (verified_receiver, unprocessed_transaction_storage) =
|
|
|
|
match (i, should_split_voting_threads) {
|
|
|
|
(0, false) => (
|
|
|
|
verified_vote_receiver.clone(),
|
|
|
|
UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
UnprocessedPacketBatches::with_capacity(batch_limit),
|
|
|
|
ThreadType::Voting(VoteSource::Gossip),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(0, true) => (
|
|
|
|
verified_vote_receiver.clone(),
|
|
|
|
UnprocessedTransactionStorage::new_vote_storage(
|
|
|
|
latest_unprocessed_votes.clone(),
|
|
|
|
VoteSource::Gossip,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(1, false) => (
|
|
|
|
tpu_verified_vote_receiver.clone(),
|
|
|
|
UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
UnprocessedPacketBatches::with_capacity(batch_limit),
|
|
|
|
ThreadType::Voting(VoteSource::Tpu),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(1, true) => (
|
|
|
|
tpu_verified_vote_receiver.clone(),
|
|
|
|
UnprocessedTransactionStorage::new_vote_storage(
|
|
|
|
latest_unprocessed_votes.clone(),
|
|
|
|
VoteSource::Tpu,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
_ => (
|
|
|
|
verified_receiver.clone(),
|
|
|
|
UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
UnprocessedPacketBatches::with_capacity(batch_limit),
|
|
|
|
ThreadType::Transactions,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
};
|
2019-04-17 21:07:45 -07:00
|
|
|
|
2022-09-01 08:00:48 -07:00
|
|
|
let mut packet_deserializer = PacketDeserializer::new(verified_receiver);
|
2019-03-03 16:44:06 -08:00
|
|
|
let poh_recorder = poh_recorder.clone();
|
|
|
|
let cluster_info = cluster_info.clone();
|
2019-04-09 11:17:15 -07:00
|
|
|
let mut recv_start = Instant::now();
|
2019-11-20 15:43:10 -08:00
|
|
|
let transaction_status_sender = transaction_status_sender.clone();
|
2020-08-07 11:21:35 -07:00
|
|
|
let gossip_vote_sender = gossip_vote_sender.clone();
|
2021-09-21 08:49:41 -07:00
|
|
|
let data_budget = data_budget.clone();
|
2021-12-22 13:39:59 -08:00
|
|
|
let cost_model = cost_model.clone();
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = connection_cache.clone();
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank_forks = bank_forks.clone();
|
2018-09-26 05:52:13 -07:00
|
|
|
Builder::new()
|
2022-08-17 08:40:23 -07:00
|
|
|
.name(format!("solBanknStgTx{:02}", i))
|
2018-09-26 05:52:13 -07:00
|
|
|
.spawn(move || {
|
2019-04-09 11:17:15 -07:00
|
|
|
Self::process_loop(
|
2022-09-01 08:00:48 -07:00
|
|
|
&mut packet_deserializer,
|
2019-04-09 11:17:15 -07:00
|
|
|
&poh_recorder,
|
|
|
|
&cluster_info,
|
|
|
|
&mut recv_start,
|
2019-05-20 09:15:00 -07:00
|
|
|
i,
|
2020-08-07 11:21:35 -07:00
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
2021-09-21 08:49:41 -07:00
|
|
|
&data_budget,
|
2021-12-22 13:39:59 -08:00
|
|
|
cost_model,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache,
|
2022-07-05 21:24:58 -07:00
|
|
|
&bank_forks,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage,
|
2019-04-09 11:17:15 -07:00
|
|
|
);
|
2018-12-07 19:01:28 -08:00
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
})
|
|
|
|
.collect();
|
2019-03-03 16:44:06 -08:00
|
|
|
Self { bank_thread_hdls }
|
|
|
|
}
|
|
|
|
|
2022-02-11 00:07:45 -08:00
|
|
|
/// Forwards all valid, unprocessed packets in the buffer, up to a rate limit. Returns
|
|
|
|
/// the number of successfully forwarded packets in second part of tuple
|
2022-07-05 21:24:58 -07:00
|
|
|
fn forward_buffered_packets<'a>(
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &ConnectionCache,
|
2022-06-02 11:14:58 -07:00
|
|
|
forward_option: &ForwardOption,
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2022-06-21 05:56:11 -07:00
|
|
|
socket: &UdpSocket,
|
2022-07-05 21:24:58 -07:00
|
|
|
forwardable_packets: impl Iterator<Item = &'a Packet>,
|
2021-09-21 08:49:41 -07:00
|
|
|
data_budget: &DataBudget,
|
2022-06-02 11:14:58 -07:00
|
|
|
banking_stage_stats: &BankingStageStats,
|
2022-07-05 21:24:58 -07:00
|
|
|
) -> (
|
|
|
|
std::result::Result<(), TransportError>,
|
|
|
|
usize,
|
|
|
|
Option<Pubkey>,
|
|
|
|
) {
|
2022-06-08 22:25:37 -07:00
|
|
|
let leader_and_addr = match forward_option {
|
2022-07-05 21:24:58 -07:00
|
|
|
ForwardOption::NotForward => return (Ok(()), 0, None),
|
2022-06-02 11:14:58 -07:00
|
|
|
ForwardOption::ForwardTransaction => {
|
|
|
|
next_leader_tpu_forwards(cluster_info, poh_recorder)
|
|
|
|
}
|
|
|
|
|
|
|
|
ForwardOption::ForwardTpuVote => next_leader_tpu_vote(cluster_info, poh_recorder),
|
|
|
|
};
|
2022-06-08 22:25:37 -07:00
|
|
|
let (leader_pubkey, addr) = match leader_and_addr {
|
|
|
|
Some(leader_and_addr) => leader_and_addr,
|
2022-07-05 21:24:58 -07:00
|
|
|
None => return (Ok(()), 0, None),
|
2022-06-02 11:14:58 -07:00
|
|
|
};
|
|
|
|
|
2021-09-21 08:49:41 -07:00
|
|
|
const INTERVAL_MS: u64 = 100;
|
2022-07-24 18:44:22 -07:00
|
|
|
// 12 MB outbound limit per second
|
|
|
|
const MAX_BYTES_PER_SECOND: usize = 12_000_000;
|
2021-09-21 08:49:41 -07:00
|
|
|
const MAX_BYTES_PER_INTERVAL: usize = MAX_BYTES_PER_SECOND * INTERVAL_MS as usize / 1000;
|
|
|
|
const MAX_BYTES_BUDGET: usize = MAX_BYTES_PER_INTERVAL * 5;
|
|
|
|
data_budget.update(INTERVAL_MS, |bytes| {
|
2021-12-29 10:34:31 -08:00
|
|
|
std::cmp::min(
|
|
|
|
bytes.saturating_add(MAX_BYTES_PER_INTERVAL),
|
|
|
|
MAX_BYTES_BUDGET,
|
|
|
|
)
|
2021-09-21 08:49:41 -07:00
|
|
|
});
|
2021-09-29 20:49:43 -07:00
|
|
|
|
2022-06-08 22:25:37 -07:00
|
|
|
let packet_vec: Vec<_> = forwardable_packets
|
2021-12-29 10:34:31 -08:00
|
|
|
.filter_map(|p| {
|
2022-01-02 09:10:32 -08:00
|
|
|
if !p.meta.forwarded() && data_budget.take(p.meta.size) {
|
2022-06-02 18:05:06 -07:00
|
|
|
Some(p.data(..)?.to_vec())
|
2021-12-29 10:34:31 -08:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2022-05-20 21:20:47 -07:00
|
|
|
let packet_vec_len = packet_vec.len();
|
2022-03-25 08:31:40 -07:00
|
|
|
// TODO: see https://github.com/solana-labs/solana/issues/23819
|
|
|
|
// fix this so returns the correct number of succeeded packets
|
|
|
|
// when there's an error sending the batch. This was left as-is for now
|
|
|
|
// in favor of shipping Quic support, which was considered higher-priority
|
2021-12-29 10:34:31 -08:00
|
|
|
if !packet_vec.is_empty() {
|
2022-05-20 21:20:47 -07:00
|
|
|
inc_new_counter_info!("banking_stage-forwarded_packets", packet_vec_len);
|
2022-03-25 08:31:40 -07:00
|
|
|
|
|
|
|
let mut measure = Measure::start("banking_stage-forward-us");
|
|
|
|
|
2022-06-21 05:56:11 -07:00
|
|
|
let res = if let ForwardOption::ForwardTpuVote = forward_option {
|
|
|
|
// The vote must be forwarded using only UDP.
|
2022-06-02 11:14:58 -07:00
|
|
|
banking_stage_stats
|
|
|
|
.forwarded_vote_count
|
|
|
|
.fetch_add(packet_vec_len, Ordering::Relaxed);
|
2022-06-21 05:56:11 -07:00
|
|
|
let pkts: Vec<_> = packet_vec.into_iter().zip(repeat(addr)).collect();
|
|
|
|
batch_send(socket, &pkts).map_err(|err| err.into())
|
2022-06-02 11:14:58 -07:00
|
|
|
} else {
|
|
|
|
// All other transactions can be forwarded using QUIC, get_connection() will use
|
|
|
|
// system wide setting to pick the correct connection object.
|
|
|
|
banking_stage_stats
|
|
|
|
.forwarded_transaction_count
|
|
|
|
.fetch_add(packet_vec_len, Ordering::Relaxed);
|
2022-06-21 05:56:11 -07:00
|
|
|
let conn = connection_cache.get_connection(&addr);
|
|
|
|
conn.send_wire_transaction_batch_async(packet_vec)
|
2022-06-02 11:14:58 -07:00
|
|
|
};
|
2022-03-25 08:31:40 -07:00
|
|
|
|
|
|
|
measure.stop();
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"banking_stage-forward-us",
|
|
|
|
measure.as_us() as usize,
|
|
|
|
1000,
|
|
|
|
1000
|
|
|
|
);
|
|
|
|
|
|
|
|
if let Err(err) = res {
|
|
|
|
inc_new_counter_info!("banking_stage-forward_packets-failed-batches", 1);
|
2022-07-05 21:24:58 -07:00
|
|
|
return (Err(err), 0, Some(leader_pubkey));
|
2021-09-21 08:49:41 -07:00
|
|
|
}
|
2019-03-09 02:47:41 -08:00
|
|
|
}
|
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
(Ok(()), packet_vec_len, Some(leader_pubkey))
|
2019-03-03 16:44:06 -08:00
|
|
|
}
|
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
fn do_process_packets(
|
|
|
|
max_tx_ingestion_ns: u128,
|
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
|
|
|
recorder: &TransactionRecorder,
|
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
|
|
|
banking_stage_stats: &BankingStageStats,
|
|
|
|
qos_service: &QosService,
|
|
|
|
log_messages_bytes_limit: Option<usize>,
|
|
|
|
consumed_buffered_packets_count: &mut usize,
|
|
|
|
rebuffered_packet_count: &mut usize,
|
|
|
|
reached_end_of_slot: &mut bool,
|
|
|
|
test_fn: &Option<impl Fn()>,
|
|
|
|
packets_to_process: &Vec<Arc<ImmutableDeserializedPacket>>,
|
|
|
|
) -> Option<Vec<usize>> {
|
|
|
|
// TODO: Right now we iterate through buffer and try the highest weighted transaction once
|
|
|
|
// but we should retry the highest weighted transactions more often.
|
|
|
|
let (bank_start, poh_recorder_lock_time) = measure!(
|
|
|
|
poh_recorder.read().unwrap().bank_start(),
|
|
|
|
"poh_recorder.read",
|
|
|
|
);
|
|
|
|
slot_metrics_tracker.increment_consume_buffered_packets_poh_recorder_lock_us(
|
|
|
|
poh_recorder_lock_time.as_us(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let packets_to_process_len = packets_to_process.len();
|
|
|
|
if let Some(BankStart {
|
|
|
|
working_bank,
|
|
|
|
bank_creation_time,
|
|
|
|
}) = bank_start
|
|
|
|
{
|
|
|
|
let (process_transactions_summary, process_packets_transactions_time) = measure!(
|
|
|
|
Self::process_packets_transactions(
|
|
|
|
&working_bank,
|
|
|
|
&bank_creation_time,
|
|
|
|
recorder,
|
|
|
|
packets_to_process.iter().map(|p| &**p),
|
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
|
|
|
banking_stage_stats,
|
|
|
|
qos_service,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
log_messages_bytes_limit
|
|
|
|
),
|
|
|
|
"process_packets_transactions",
|
|
|
|
);
|
|
|
|
slot_metrics_tracker.increment_process_packets_transactions_us(
|
|
|
|
process_packets_transactions_time.as_us(),
|
|
|
|
);
|
|
|
|
|
|
|
|
let ProcessTransactionsSummary {
|
|
|
|
reached_max_poh_height,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = process_transactions_summary;
|
|
|
|
|
|
|
|
if reached_max_poh_height
|
|
|
|
|| !Bank::should_bank_still_be_processing_txs(
|
|
|
|
&bank_creation_time,
|
|
|
|
max_tx_ingestion_ns,
|
|
|
|
)
|
|
|
|
{
|
|
|
|
*reached_end_of_slot = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The difference between all transactions passed to execution and the ones that
|
|
|
|
// are retryable were the ones that were either:
|
|
|
|
// 1) Committed into the block
|
|
|
|
// 2) Dropped without being committed because they had some fatal error (too old,
|
|
|
|
// duplicate signature, etc.)
|
|
|
|
//
|
|
|
|
// Note: This assumes that every packet deserializes into one transaction!
|
|
|
|
*consumed_buffered_packets_count +=
|
|
|
|
packets_to_process_len.saturating_sub(retryable_transaction_indexes.len());
|
|
|
|
|
|
|
|
// Out of the buffered packets just retried, collect any still unprocessed
|
|
|
|
// transactions in this batch for forwarding
|
|
|
|
*rebuffered_packet_count += retryable_transaction_indexes.len();
|
|
|
|
if let Some(test_fn) = test_fn {
|
|
|
|
test_fn();
|
|
|
|
}
|
|
|
|
|
|
|
|
slot_metrics_tracker
|
|
|
|
.increment_retryable_packets_count(retryable_transaction_indexes.len() as u64);
|
|
|
|
|
|
|
|
Some(retryable_transaction_indexes)
|
|
|
|
} else if *reached_end_of_slot {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
// mark as end-of-slot to avoid aggressively lock poh for the remaining for
|
|
|
|
// packet batches in buffer
|
|
|
|
*reached_end_of_slot = true;
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-01 07:16:17 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-05-20 09:15:00 -07:00
|
|
|
pub fn consume_buffered_packets(
|
2022-07-05 21:24:58 -07:00
|
|
|
_my_pubkey: &Pubkey,
|
2021-03-15 17:11:15 -07:00
|
|
|
max_tx_ingestion_ns: u128,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
|
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
2021-02-12 03:27:37 -08:00
|
|
|
test_fn: Option<impl Fn()>,
|
2021-04-12 23:28:08 -07:00
|
|
|
banking_stage_stats: &BankingStageStats,
|
2021-03-23 07:10:04 -07:00
|
|
|
recorder: &TransactionRecorder,
|
2021-12-22 13:39:59 -08:00
|
|
|
qos_service: &QosService,
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
2022-05-04 19:50:56 -07:00
|
|
|
num_packets_to_process_per_iteration: usize,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2021-02-12 03:27:37 -08:00
|
|
|
) {
|
2021-12-11 06:44:15 -08:00
|
|
|
let mut rebuffered_packet_count = 0;
|
2022-02-03 00:56:36 -08:00
|
|
|
let mut consumed_buffered_packets_count = 0;
|
2019-06-29 06:34:49 -07:00
|
|
|
let mut proc_start = Measure::start("consume_buffered_process");
|
2022-07-05 21:24:58 -07:00
|
|
|
let mut reached_end_of_slot = false;
|
2022-10-20 14:10:48 -07:00
|
|
|
let num_packets_to_process = unprocessed_transaction_storage.len();
|
|
|
|
let bank = poh_recorder.read().unwrap().bank();
|
2022-02-16 22:14:32 -08:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage.process_packets(
|
|
|
|
bank,
|
|
|
|
num_packets_to_process_per_iteration,
|
|
|
|
|packets_to_process| {
|
|
|
|
Self::do_process_packets(
|
|
|
|
max_tx_ingestion_ns,
|
|
|
|
poh_recorder,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
recorder,
|
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
|
|
|
banking_stage_stats,
|
|
|
|
qos_service,
|
|
|
|
log_messages_bytes_limit,
|
|
|
|
&mut consumed_buffered_packets_count,
|
|
|
|
&mut rebuffered_packet_count,
|
|
|
|
&mut reached_end_of_slot,
|
|
|
|
&test_fn,
|
|
|
|
packets_to_process,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
if reached_end_of_slot {
|
2022-10-20 14:10:48 -07:00
|
|
|
slot_metrics_tracker.set_end_of_slot_unprocessed_buffer_len(
|
|
|
|
unprocessed_transaction_storage.len() as u64,
|
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
|
|
|
|
// We've hit the end of this slot, no need to perform more processing,
|
2022-09-29 14:33:40 -07:00
|
|
|
// Packet filtering will be done before forwarding.
|
2022-05-04 19:50:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
proc_start.stop();
|
2019-05-20 09:15:00 -07:00
|
|
|
debug!(
|
|
|
|
"@{:?} done processing buffered batches: {} time: {:?}ms tx count: {} tx/s: {}",
|
2019-09-06 14:30:56 -07:00
|
|
|
timestamp(),
|
2022-10-20 14:10:48 -07:00
|
|
|
num_packets_to_process,
|
2019-06-29 06:34:49 -07:00
|
|
|
proc_start.as_ms(),
|
2022-02-03 00:56:36 -08:00
|
|
|
consumed_buffered_packets_count,
|
|
|
|
(consumed_buffered_packets_count as f32) / (proc_start.as_s())
|
2019-05-20 09:15:00 -07:00
|
|
|
);
|
|
|
|
|
2021-04-12 23:28:08 -07:00
|
|
|
banking_stage_stats
|
|
|
|
.consume_buffered_packets_elapsed
|
|
|
|
.fetch_add(proc_start.as_us(), Ordering::Relaxed);
|
|
|
|
banking_stage_stats
|
|
|
|
.rebuffered_packets_count
|
2021-12-11 06:44:15 -08:00
|
|
|
.fetch_add(rebuffered_packet_count, Ordering::Relaxed);
|
2021-04-12 23:28:08 -07:00
|
|
|
banking_stage_stats
|
|
|
|
.consumed_buffered_packets_count
|
2022-02-03 00:56:36 -08:00
|
|
|
.fetch_add(consumed_buffered_packets_count, Ordering::Relaxed);
|
2019-04-11 17:23:45 -07:00
|
|
|
}
|
2019-03-29 11:20:36 -07:00
|
|
|
|
2019-05-01 15:13:10 -07:00
|
|
|
fn consume_or_forward_packets(
|
2019-07-18 14:54:27 -07:00
|
|
|
my_pubkey: &Pubkey,
|
2019-05-23 23:20:04 -07:00
|
|
|
leader_pubkey: Option<Pubkey>,
|
2021-03-15 17:11:15 -07:00
|
|
|
bank_still_processing_txs: Option<&Arc<Bank>>,
|
2019-04-23 11:56:30 -07:00
|
|
|
would_be_leader: bool,
|
2021-03-03 10:23:05 -08:00
|
|
|
would_be_leader_shortly: bool,
|
2019-04-13 23:19:54 -07:00
|
|
|
) -> BufferedPacketsDecision {
|
2022-02-03 13:29:41 -08:00
|
|
|
// If has active bank, then immediately process buffered packets
|
|
|
|
// otherwise, based on leader schedule to either forward or hold packets
|
|
|
|
if let Some(bank) = bank_still_processing_txs {
|
|
|
|
// If the bank is available, this node is the leader
|
|
|
|
BufferedPacketsDecision::Consume(bank.ns_per_slot)
|
|
|
|
} else if would_be_leader_shortly {
|
|
|
|
// If the node will be the leader soon, hold the packets for now
|
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
} else if would_be_leader {
|
|
|
|
// Node will be leader within ~20 slots, hold the transactions in
|
|
|
|
// case it is the only node which produces an accepted slot.
|
|
|
|
BufferedPacketsDecision::ForwardAndHold
|
|
|
|
} else if let Some(x) = leader_pubkey {
|
|
|
|
if x != *my_pubkey {
|
|
|
|
// If the current node is not the leader, forward the buffered packets
|
|
|
|
BufferedPacketsDecision::Forward
|
|
|
|
} else {
|
|
|
|
// If the current node is the leader, return the buffered packets as is
|
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// We don't know the leader. Hold the packets for now
|
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
}
|
2019-04-13 23:19:54 -07:00
|
|
|
}
|
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-05-01 15:13:10 -07:00
|
|
|
fn process_buffered_packets(
|
2019-06-21 15:21:49 -07:00
|
|
|
my_pubkey: &Pubkey,
|
2022-06-21 05:56:11 -07:00
|
|
|
socket: &UdpSocket,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: &ClusterInfo,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
|
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
2021-02-12 03:27:37 -08:00
|
|
|
banking_stage_stats: &BankingStageStats,
|
2021-03-23 07:10:04 -07:00
|
|
|
recorder: &TransactionRecorder,
|
2021-09-21 08:49:41 -07:00
|
|
|
data_budget: &DataBudget,
|
2021-12-22 13:39:59 -08:00
|
|
|
qos_service: &QosService,
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &ConnectionCache,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats: &mut TracerPacketStats,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2022-05-18 13:37:47 -07:00
|
|
|
) {
|
2022-10-20 14:10:48 -07:00
|
|
|
if unprocessed_transaction_storage.should_not_process() {
|
|
|
|
return;
|
|
|
|
}
|
2022-06-13 15:03:34 -07:00
|
|
|
let ((metrics_action, decision), make_decision_time) = measure!(
|
2022-06-06 18:21:05 -07:00
|
|
|
{
|
2022-02-16 22:14:32 -08:00
|
|
|
let bank_start;
|
|
|
|
let (
|
|
|
|
leader_at_slot_offset,
|
|
|
|
bank_still_processing_txs,
|
|
|
|
would_be_leader,
|
|
|
|
would_be_leader_shortly,
|
|
|
|
) = {
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh = poh_recorder.read().unwrap();
|
2022-02-16 22:14:32 -08:00
|
|
|
bank_start = poh.bank_start();
|
|
|
|
(
|
|
|
|
poh.leader_after_n_slots(FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET),
|
|
|
|
PohRecorder::get_working_bank_if_not_expired(&bank_start.as_ref()),
|
|
|
|
poh.would_be_leader(HOLD_TRANSACTIONS_SLOT_OFFSET * DEFAULT_TICKS_PER_SLOT),
|
|
|
|
poh.would_be_leader(
|
|
|
|
(FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET - 1)
|
|
|
|
* DEFAULT_TICKS_PER_SLOT,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
};
|
2022-06-13 15:03:34 -07:00
|
|
|
|
|
|
|
(
|
|
|
|
slot_metrics_tracker.check_leader_slot_boundary(&bank_start),
|
|
|
|
Self::consume_or_forward_packets(
|
|
|
|
my_pubkey,
|
|
|
|
leader_at_slot_offset,
|
|
|
|
bank_still_processing_txs,
|
|
|
|
would_be_leader,
|
|
|
|
would_be_leader_shortly,
|
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
)
|
|
|
|
},
|
|
|
|
"make_decision",
|
2019-07-18 14:54:27 -07:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
slot_metrics_tracker.increment_make_decision_us(make_decision_time.as_us());
|
2019-07-18 14:54:27 -07:00
|
|
|
|
2019-04-13 23:19:54 -07:00
|
|
|
match decision {
|
2021-03-15 17:11:15 -07:00
|
|
|
BufferedPacketsDecision::Consume(max_tx_ingestion_ns) => {
|
2022-06-13 15:03:34 -07:00
|
|
|
// Take metrics action before consume packets (potentially resetting the
|
|
|
|
// slot metrics tracker to the next slot) so that we don't count the
|
|
|
|
// packet processing metrics from the next slot towards the metrics
|
|
|
|
// of the previous slot
|
|
|
|
slot_metrics_tracker.apply_action(metrics_action);
|
2022-06-06 18:21:05 -07:00
|
|
|
let (_, consume_buffered_packets_time) = measure!(
|
|
|
|
Self::consume_buffered_packets(
|
|
|
|
my_pubkey,
|
|
|
|
max_tx_ingestion_ns,
|
|
|
|
poh_recorder,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage,
|
2022-06-06 18:21:05 -07:00
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
|
|
|
None::<Box<dyn Fn()>>,
|
|
|
|
banking_stage_stats,
|
|
|
|
recorder,
|
|
|
|
qos_service,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
UNPROCESSED_BUFFER_STEP_SIZE,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"consume_buffered_packets",
|
2020-01-02 19:50:43 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
slot_metrics_tracker
|
|
|
|
.increment_consume_buffered_packets_us(consume_buffered_packets_time.as_us());
|
2019-04-13 23:19:54 -07:00
|
|
|
}
|
|
|
|
BufferedPacketsDecision::Forward => {
|
2022-06-06 18:21:05 -07:00
|
|
|
let (_, forward_time) = measure!(
|
|
|
|
Self::handle_forwarding(
|
|
|
|
cluster_info,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage,
|
2022-06-06 18:21:05 -07:00
|
|
|
poh_recorder,
|
2022-06-21 05:56:11 -07:00
|
|
|
socket,
|
2022-06-06 18:21:05 -07:00
|
|
|
false,
|
|
|
|
data_budget,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
banking_stage_stats,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"forward",
|
2021-03-03 10:23:05 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
slot_metrics_tracker.increment_forward_us(forward_time.as_us());
|
2022-06-13 15:03:34 -07:00
|
|
|
// Take metrics action after forwarding packets to include forwarded
|
|
|
|
// metrics into current slot
|
|
|
|
slot_metrics_tracker.apply_action(metrics_action);
|
2021-03-03 10:23:05 -08:00
|
|
|
}
|
|
|
|
BufferedPacketsDecision::ForwardAndHold => {
|
2022-06-06 18:21:05 -07:00
|
|
|
let (_, forward_and_hold_time) = measure!(
|
|
|
|
Self::handle_forwarding(
|
|
|
|
cluster_info,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage,
|
2022-06-06 18:21:05 -07:00
|
|
|
poh_recorder,
|
2022-06-21 05:56:11 -07:00
|
|
|
socket,
|
2022-06-06 18:21:05 -07:00
|
|
|
true,
|
|
|
|
data_budget,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
banking_stage_stats,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"forward_and_hold",
|
2021-03-03 10:23:05 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
slot_metrics_tracker.increment_forward_and_hold_us(forward_and_hold_time.as_us());
|
2022-06-13 15:03:34 -07:00
|
|
|
// Take metrics action after forwarding packets
|
|
|
|
slot_metrics_tracker.apply_action(metrics_action);
|
2019-04-13 23:19:54 -07:00
|
|
|
}
|
2020-01-02 19:50:43 -08:00
|
|
|
_ => (),
|
2019-03-08 16:48:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 22:25:37 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-03-03 10:23:05 -08:00
|
|
|
fn handle_forwarding(
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2022-06-21 05:56:11 -07:00
|
|
|
socket: &UdpSocket,
|
2021-03-03 10:23:05 -08:00
|
|
|
hold: bool,
|
2021-09-21 08:49:41 -07:00
|
|
|
data_budget: &DataBudget,
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
2022-06-02 11:14:58 -07:00
|
|
|
banking_stage_stats: &BankingStageStats,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: &ConnectionCache,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats: &mut TracerPacketStats,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2021-03-03 10:23:05 -08:00
|
|
|
) {
|
2022-10-20 14:10:48 -07:00
|
|
|
let forward_option = unprocessed_transaction_storage.forward_option();
|
2022-02-11 00:07:45 -08:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
// get current root bank from bank_forks, use it to sanitize transaction and
|
|
|
|
// load all accounts from address loader;
|
|
|
|
let current_bank = bank_forks.read().unwrap().root_bank();
|
2022-09-29 14:33:40 -07:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
let mut forward_packet_batches_by_accounts =
|
2022-09-29 14:33:40 -07:00
|
|
|
ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
|
|
|
|
|
|
|
|
// sanitize and filter packets that are no longer valid (could be too old, a duplicate of something
|
|
|
|
// already processed), then add to forwarding buffer.
|
2022-10-20 14:10:48 -07:00
|
|
|
let filter_forwarding_result = unprocessed_transaction_storage
|
|
|
|
.filter_forwardable_packets_and_add_batches(
|
|
|
|
current_bank,
|
|
|
|
&mut forward_packet_batches_by_accounts,
|
|
|
|
);
|
2022-09-29 14:33:40 -07:00
|
|
|
slot_metrics_tracker.increment_transactions_from_packets_us(
|
|
|
|
filter_forwarding_result.total_packet_conversion_us,
|
2022-06-02 11:14:58 -07:00
|
|
|
);
|
2022-09-29 14:33:40 -07:00
|
|
|
banking_stage_stats.packet_conversion_elapsed.fetch_add(
|
|
|
|
filter_forwarding_result.total_packet_conversion_us,
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
banking_stage_stats
|
|
|
|
.filter_pending_packets_elapsed
|
|
|
|
.fetch_add(
|
|
|
|
filter_forwarding_result.total_filter_packets_us,
|
|
|
|
Ordering::Relaxed,
|
|
|
|
);
|
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
forward_packet_batches_by_accounts
|
|
|
|
.iter_batches()
|
|
|
|
.filter(|&batch| !batch.is_empty())
|
|
|
|
.for_each(|forward_batch| {
|
|
|
|
slot_metrics_tracker.increment_forwardable_batches_count(1);
|
|
|
|
|
|
|
|
let batched_forwardable_packets_count = forward_batch.len();
|
|
|
|
let (_forward_result, sucessful_forwarded_packets_count, leader_pubkey) =
|
|
|
|
Self::forward_buffered_packets(
|
|
|
|
connection_cache,
|
2022-10-20 14:10:48 -07:00
|
|
|
&forward_option,
|
2022-07-05 21:24:58 -07:00
|
|
|
cluster_info,
|
|
|
|
poh_recorder,
|
|
|
|
socket,
|
|
|
|
forward_batch.get_forwardable_packets(),
|
|
|
|
data_budget,
|
|
|
|
banking_stage_stats,
|
|
|
|
);
|
2022-02-11 00:07:45 -08:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
if let Some(leader_pubkey) = leader_pubkey {
|
|
|
|
tracer_packet_stats.increment_total_forwardable_tracer_packets(
|
|
|
|
filter_forwarding_result.total_forwardable_tracer_packets,
|
|
|
|
leader_pubkey,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
let failed_forwarded_packets_count = batched_forwardable_packets_count
|
|
|
|
.saturating_sub(sucessful_forwarded_packets_count);
|
2022-02-11 00:07:45 -08:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
if failed_forwarded_packets_count > 0 {
|
|
|
|
slot_metrics_tracker.increment_failed_forwarded_packets_count(
|
|
|
|
failed_forwarded_packets_count as u64,
|
|
|
|
);
|
|
|
|
slot_metrics_tracker.increment_packet_batch_forward_failure_count(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if sucessful_forwarded_packets_count > 0 {
|
|
|
|
slot_metrics_tracker.increment_successful_forwarded_packets_count(
|
|
|
|
sucessful_forwarded_packets_count as u64,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
2022-02-11 00:07:45 -08:00
|
|
|
|
2022-10-07 09:50:57 -07:00
|
|
|
if !hold {
|
2022-07-05 21:24:58 -07:00
|
|
|
slot_metrics_tracker.increment_cleared_from_buffer_after_forward_count(
|
|
|
|
filter_forwarding_result.total_forwardable_packets as u64,
|
|
|
|
);
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats.increment_total_cleared_from_buffer_after_forward(
|
|
|
|
filter_forwarding_result.total_tracer_packets_in_buffer,
|
|
|
|
);
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage.clear_forwarded_packets();
|
2022-09-29 14:33:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-06-17 10:14:21 -07:00
|
|
|
fn process_loop(
|
2022-09-01 08:00:48 -07:00
|
|
|
packet_deserializer: &mut PacketDeserializer,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: &ClusterInfo,
|
2019-04-09 11:17:15 -07:00
|
|
|
recv_start: &mut Instant,
|
2019-05-20 09:15:00 -07:00
|
|
|
id: u32,
|
2019-11-20 15:43:10 -08:00
|
|
|
transaction_status_sender: Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: ReplayVoteSender,
|
2021-09-21 08:49:41 -07:00
|
|
|
data_budget: &DataBudget,
|
2021-12-22 13:39:59 -08:00
|
|
|
cost_model: Arc<RwLock<CostModel>>,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-06-08 04:57:12 -07:00
|
|
|
connection_cache: Arc<ConnectionCache>,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2022-10-20 14:10:48 -07:00
|
|
|
mut unprocessed_transaction_storage: UnprocessedTransactionStorage,
|
2019-03-03 16:44:06 -08:00
|
|
|
) {
|
2022-07-05 07:29:44 -07:00
|
|
|
let recorder = poh_recorder.read().unwrap().recorder();
|
2022-06-21 05:56:11 -07:00
|
|
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2022-01-19 00:13:07 -08:00
|
|
|
let mut banking_stage_stats = BankingStageStats::new(id);
|
2022-06-08 22:25:37 -07:00
|
|
|
let mut tracer_packet_stats = TracerPacketStats::new(id);
|
2021-12-22 13:39:59 -08:00
|
|
|
let qos_service = QosService::new(cost_model, id);
|
2022-05-18 13:37:47 -07:00
|
|
|
|
2022-02-11 00:07:45 -08:00
|
|
|
let mut slot_metrics_tracker = LeaderSlotMetricsTracker::new(id);
|
2022-05-18 13:37:47 -07:00
|
|
|
let mut last_metrics_update = Instant::now();
|
|
|
|
|
2019-03-03 16:44:06 -08:00
|
|
|
loop {
|
2021-06-17 13:51:06 -07:00
|
|
|
let my_pubkey = cluster_info.id();
|
2022-10-20 14:10:48 -07:00
|
|
|
if !unprocessed_transaction_storage.is_empty()
|
2022-06-13 15:03:34 -07:00
|
|
|
|| last_metrics_update.elapsed() >= SLOT_BOUNDARY_CHECK_PERIOD
|
|
|
|
{
|
2022-06-06 18:21:05 -07:00
|
|
|
let (_, process_buffered_packets_time) = measure!(
|
|
|
|
Self::process_buffered_packets(
|
|
|
|
&my_pubkey,
|
2022-06-21 05:56:11 -07:00
|
|
|
&socket,
|
2022-06-06 18:21:05 -07:00
|
|
|
poh_recorder,
|
|
|
|
cluster_info,
|
2022-10-20 14:10:48 -07:00
|
|
|
&mut unprocessed_transaction_storage,
|
|
|
|
&transaction_status_sender,
|
2022-06-06 18:21:05 -07:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&banking_stage_stats,
|
|
|
|
&recorder,
|
|
|
|
data_budget,
|
|
|
|
&qos_service,
|
|
|
|
&mut slot_metrics_tracker,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2022-06-08 22:25:37 -07:00
|
|
|
&mut tracer_packet_stats,
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"process_buffered_packets",
|
2020-01-02 19:50:43 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
slot_metrics_tracker
|
|
|
|
.increment_process_buffered_packets_us(process_buffered_packets_time.as_us());
|
2022-06-13 15:03:34 -07:00
|
|
|
last_metrics_update = Instant::now();
|
2019-03-08 16:48:15 -08:00
|
|
|
}
|
|
|
|
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats.report(1000);
|
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
// Gossip thread will almost always not wait because the transaction storage will most likely not be empty
|
|
|
|
let recv_timeout = if !unprocessed_transaction_storage.is_empty() {
|
2022-05-18 13:37:47 -07:00
|
|
|
// If there are buffered packets, run the equivalent of try_recv to try reading more
|
|
|
|
// packets. This prevents starving BankingStage::consume_buffered_packets due to
|
|
|
|
// buffered_packet_batches containing transactions that exceed the cost model for
|
|
|
|
// the current bank.
|
|
|
|
Duration::from_millis(0)
|
2019-04-14 12:34:07 -07:00
|
|
|
} else {
|
|
|
|
// Default wait time
|
|
|
|
Duration::from_millis(100)
|
|
|
|
};
|
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (res, receive_and_buffer_packets_time) = measure!(
|
|
|
|
Self::receive_and_buffer_packets(
|
2022-09-01 08:00:48 -07:00
|
|
|
packet_deserializer,
|
2022-06-06 18:21:05 -07:00
|
|
|
recv_start,
|
|
|
|
recv_timeout,
|
|
|
|
id,
|
2022-10-20 14:10:48 -07:00
|
|
|
&mut unprocessed_transaction_storage,
|
2022-06-06 18:21:05 -07:00
|
|
|
&mut banking_stage_stats,
|
2022-06-08 22:25:37 -07:00
|
|
|
&mut tracer_packet_stats,
|
2022-06-06 18:21:05 -07:00
|
|
|
&mut slot_metrics_tracker,
|
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"receive_and_buffer_packets",
|
|
|
|
);
|
|
|
|
slot_metrics_tracker
|
|
|
|
.increment_receive_and_buffer_packets_us(receive_and_buffer_packets_time.as_us());
|
|
|
|
|
|
|
|
match res {
|
2021-02-12 03:27:37 -08:00
|
|
|
Ok(()) | Err(RecvTimeoutError::Timeout) => (),
|
2020-01-02 19:50:43 -08:00
|
|
|
Err(RecvTimeoutError::Disconnected) => break,
|
2019-03-03 16:44:06 -08:00
|
|
|
}
|
2021-03-03 10:58:47 -08:00
|
|
|
banking_stage_stats.report(1000);
|
2019-03-03 16:44:06 -08:00
|
|
|
}
|
2018-05-14 16:31:13 -07:00
|
|
|
}
|
|
|
|
|
2018-12-21 13:55:45 -08:00
|
|
|
pub fn num_threads() -> u32 {
|
2019-06-28 01:55:24 -07:00
|
|
|
cmp::max(
|
|
|
|
env::var("SOLANA_BANKING_THREADS")
|
|
|
|
.map(|x| x.parse().unwrap_or(NUM_THREADS))
|
|
|
|
.unwrap_or(NUM_THREADS),
|
2022-03-02 07:08:08 -08:00
|
|
|
MIN_TOTAL_THREADS,
|
2019-06-28 01:55:24 -07:00
|
|
|
)
|
2018-12-21 13:55:45 -08:00
|
|
|
}
|
|
|
|
|
2019-06-26 22:39:50 -07:00
|
|
|
#[allow(clippy::match_wild_err_arm)]
|
2021-08-17 15:17:56 -07:00
|
|
|
fn record_transactions(
|
2019-11-02 00:38:30 -07:00
|
|
|
bank_slot: Slot,
|
2022-04-21 06:06:26 -07:00
|
|
|
transactions: Vec<VersionedTransaction>,
|
2021-03-23 07:10:04 -07:00
|
|
|
recorder: &TransactionRecorder,
|
2022-02-16 22:14:32 -08:00
|
|
|
) -> RecordTransactionsSummary {
|
|
|
|
let mut record_transactions_timings = RecordTransactionsTimings::default();
|
2022-06-23 12:37:38 -07:00
|
|
|
let mut starting_transaction_index = None;
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
if !transactions.is_empty() {
|
|
|
|
let num_to_record = transactions.len();
|
2021-03-02 17:28:15 -08:00
|
|
|
inc_new_counter_info!("banking_stage-record_count", 1);
|
2022-04-21 06:06:26 -07:00
|
|
|
inc_new_counter_info!("banking_stage-record_transactions", num_to_record);
|
2019-06-29 06:34:49 -07:00
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (hash, hash_time) = measure!(hash_transactions(&transactions), "hash");
|
2022-02-16 22:14:32 -08:00
|
|
|
record_transactions_timings.hash_us = hash_time.as_us();
|
2019-06-29 06:34:49 -07:00
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (res, poh_record_time) =
|
|
|
|
measure!(recorder.record(bank_slot, hash, transactions), "hash");
|
2022-02-16 22:14:32 -08:00
|
|
|
record_transactions_timings.poh_record_us = poh_record_time.as_us();
|
|
|
|
|
2019-06-26 22:39:50 -07:00
|
|
|
match res {
|
2022-06-23 12:37:38 -07:00
|
|
|
Ok(starting_index) => {
|
|
|
|
starting_transaction_index = starting_index;
|
|
|
|
}
|
2020-01-02 19:50:43 -08:00
|
|
|
Err(PohRecorderError::MaxHeightReached) => {
|
2021-03-02 17:28:15 -08:00
|
|
|
inc_new_counter_info!("banking_stage-max_height_reached", 1);
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"banking_stage-max_height_reached_num_to_commit",
|
2022-04-21 06:06:26 -07:00
|
|
|
num_to_record
|
2021-03-02 17:28:15 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
return RecordTransactionsSummary {
|
|
|
|
record_transactions_timings,
|
|
|
|
result: Err(PohRecorderError::MaxHeightReached),
|
2022-06-23 12:37:38 -07:00
|
|
|
starting_transaction_index: None,
|
2022-02-16 22:14:32 -08:00
|
|
|
};
|
2019-06-26 22:39:50 -07:00
|
|
|
}
|
2021-02-18 23:42:09 -08:00
|
|
|
Err(e) => panic!("Poh recorder returned unexpected error: {:?}", e),
|
2019-06-26 22:39:50 -07:00
|
|
|
}
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
2022-02-16 22:14:32 -08:00
|
|
|
|
|
|
|
RecordTransactionsSummary {
|
|
|
|
record_transactions_timings,
|
2022-04-21 06:06:26 -07:00
|
|
|
result: Ok(()),
|
2022-06-23 12:37:38 -07:00
|
|
|
starting_transaction_index,
|
2022-02-16 22:14:32 -08:00
|
|
|
}
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
|
|
|
|
2022-10-29 12:36:57 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
fn commit_transactions(
|
|
|
|
batch: &TransactionBatch,
|
|
|
|
loaded_transactions: &mut [TransactionLoadResult],
|
|
|
|
execution_results: Vec<TransactionExecutionResult>,
|
|
|
|
sanitized_txs: &[SanitizedTransaction],
|
|
|
|
starting_transaction_index: Option<usize>,
|
|
|
|
bank: &Arc<Bank>,
|
|
|
|
pre_balance_info: &mut PreBalanceInfo,
|
|
|
|
execute_and_commit_timings: &mut LeaderExecuteAndCommitTimings,
|
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
|
|
|
signature_count: u64,
|
|
|
|
executed_transactions_count: usize,
|
|
|
|
executed_with_successful_result_count: usize,
|
|
|
|
) -> (u64, Vec<CommitTransactionDetails>) {
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"banking_stage-record_transactions_num_to_commit",
|
|
|
|
executed_transactions_count
|
|
|
|
);
|
|
|
|
|
|
|
|
let (last_blockhash, lamports_per_signature) =
|
|
|
|
bank.last_blockhash_and_lamports_per_signature();
|
|
|
|
|
|
|
|
let (tx_results, commit_time) = measure!(
|
|
|
|
bank.commit_transactions(
|
|
|
|
sanitized_txs,
|
|
|
|
loaded_transactions,
|
|
|
|
execution_results,
|
|
|
|
last_blockhash,
|
|
|
|
lamports_per_signature,
|
|
|
|
CommitTransactionCounts {
|
|
|
|
committed_transactions_count: executed_transactions_count as u64,
|
|
|
|
committed_with_failure_result_count: executed_transactions_count
|
|
|
|
.saturating_sub(executed_with_successful_result_count)
|
|
|
|
as u64,
|
|
|
|
signature_count,
|
|
|
|
},
|
|
|
|
&mut execute_and_commit_timings.execute_timings,
|
|
|
|
),
|
|
|
|
"commit",
|
|
|
|
);
|
|
|
|
let commit_time_us = commit_time.as_us();
|
|
|
|
execute_and_commit_timings.commit_us = commit_time_us;
|
|
|
|
|
|
|
|
let commit_transaction_statuses = tx_results
|
|
|
|
.execution_results
|
|
|
|
.iter()
|
|
|
|
.map(|execution_result| match execution_result.details() {
|
|
|
|
Some(details) => CommitTransactionDetails::Committed {
|
|
|
|
compute_units: details.executed_units,
|
|
|
|
},
|
|
|
|
None => CommitTransactionDetails::NotCommitted,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let (_, find_and_send_votes_time) = measure!(
|
|
|
|
{
|
|
|
|
bank_utils::find_and_send_votes(
|
|
|
|
sanitized_txs,
|
|
|
|
&tx_results,
|
|
|
|
Some(gossip_vote_sender),
|
|
|
|
);
|
|
|
|
Self::collect_balances_and_send_status_batch(
|
|
|
|
transaction_status_sender,
|
|
|
|
tx_results,
|
|
|
|
bank,
|
|
|
|
batch,
|
|
|
|
pre_balance_info,
|
|
|
|
starting_transaction_index,
|
|
|
|
);
|
|
|
|
},
|
|
|
|
"find_and_send_votes",
|
|
|
|
);
|
|
|
|
execute_and_commit_timings.find_and_send_votes_us = find_and_send_votes_time.as_us();
|
|
|
|
(commit_time_us, commit_transaction_statuses)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_balances_and_send_status_batch(
|
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
|
|
|
tx_results: TransactionResults,
|
|
|
|
bank: &Arc<Bank>,
|
|
|
|
batch: &TransactionBatch,
|
|
|
|
pre_balance_info: &mut PreBalanceInfo,
|
|
|
|
starting_transaction_index: Option<usize>,
|
|
|
|
) {
|
|
|
|
if let Some(transaction_status_sender) = transaction_status_sender {
|
|
|
|
let txs = batch.sanitized_transactions().to_vec();
|
|
|
|
let post_balances = bank.collect_balances(batch);
|
|
|
|
let post_token_balances =
|
|
|
|
collect_token_balances(bank, batch, &mut pre_balance_info.mint_decimals);
|
|
|
|
let mut transaction_index = starting_transaction_index.unwrap_or_default();
|
|
|
|
let batch_transaction_indexes: Vec<_> = tx_results
|
|
|
|
.execution_results
|
|
|
|
.iter()
|
|
|
|
.map(|result| {
|
|
|
|
if result.was_executed() {
|
|
|
|
let this_transaction_index = transaction_index;
|
|
|
|
saturating_add_assign!(transaction_index, 1);
|
|
|
|
this_transaction_index
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
transaction_status_sender.send_transaction_status_batch(
|
|
|
|
bank.clone(),
|
|
|
|
txs,
|
|
|
|
tx_results.execution_results,
|
|
|
|
TransactionBalancesSet::new(
|
|
|
|
std::mem::take(&mut pre_balance_info.native),
|
|
|
|
post_balances,
|
|
|
|
),
|
|
|
|
TransactionTokenBalancesSet::new(
|
|
|
|
std::mem::take(&mut pre_balance_info.token),
|
|
|
|
post_token_balances,
|
|
|
|
),
|
|
|
|
tx_results.rent_debits,
|
|
|
|
batch_transaction_indexes,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
fn execute_and_commit_transactions_locked(
|
2019-11-20 15:43:10 -08:00
|
|
|
bank: &Arc<Bank>,
|
2021-03-23 07:10:04 -07:00
|
|
|
poh: &TransactionRecorder,
|
2019-09-19 10:06:08 -07:00
|
|
|
batch: &TransactionBatch,
|
2022-10-20 14:10:48 -07:00
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-02-03 00:56:36 -08:00
|
|
|
) -> ExecuteAndCommitTransactionsOutput {
|
2022-02-16 22:14:32 -08:00
|
|
|
let mut execute_and_commit_timings = LeaderExecuteAndCommitTimings::default();
|
2020-12-10 19:25:07 -08:00
|
|
|
|
2022-10-29 12:36:57 -07:00
|
|
|
let mut pre_balance_info = PreBalanceInfo::default();
|
|
|
|
let (_, collect_balances_time) = measure!(
|
2022-06-06 18:21:05 -07:00
|
|
|
{
|
2022-10-29 12:36:57 -07:00
|
|
|
// If the extra meta-data services are enabled for RPC, collect the
|
|
|
|
// pre-balances for native and token programs.
|
|
|
|
if transaction_status_sender.is_some() {
|
|
|
|
pre_balance_info.native = bank.collect_balances(batch);
|
|
|
|
pre_balance_info.token =
|
|
|
|
collect_token_balances(bank, batch, &mut pre_balance_info.mint_decimals)
|
|
|
|
}
|
2022-02-16 22:14:32 -08:00
|
|
|
},
|
|
|
|
"collect_balances",
|
2022-02-03 00:56:36 -08:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings.collect_balances_us = collect_balances_time.as_us();
|
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (load_and_execute_transactions_output, load_execute_time) = measure!(
|
|
|
|
bank.load_and_execute_transactions(
|
|
|
|
batch,
|
|
|
|
MAX_PROCESSING_AGE,
|
|
|
|
transaction_status_sender.is_some(),
|
|
|
|
transaction_status_sender.is_some(),
|
|
|
|
transaction_status_sender.is_some(),
|
|
|
|
&mut execute_and_commit_timings.execute_timings,
|
|
|
|
None, // account_overrides
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"load_execute",
|
|
|
|
);
|
|
|
|
execute_and_commit_timings.load_execute_us = load_execute_time.as_us();
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let LoadAndExecuteTransactionsOutput {
|
|
|
|
mut loaded_transactions,
|
|
|
|
execution_results,
|
|
|
|
mut retryable_transaction_indexes,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
signature_count,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
..
|
|
|
|
} = load_and_execute_transactions_output;
|
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
let transactions_attempted_execution_count = execution_results.len();
|
2022-06-06 18:21:05 -07:00
|
|
|
let (executed_transactions, execution_results_to_transactions_time): (Vec<_>, Measure) = measure!(
|
|
|
|
execution_results
|
|
|
|
.iter()
|
|
|
|
.zip(batch.sanitized_transactions())
|
|
|
|
.filter_map(|(execution_result, tx)| {
|
|
|
|
if execution_result.was_executed() {
|
|
|
|
Some(tx.to_versioned_transaction())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
"execution_results_to_transactions",
|
|
|
|
);
|
2022-04-10 15:45:24 -07:00
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (freeze_lock, freeze_lock_time) = measure!(bank.freeze_lock(), "freeze_lock");
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings.freeze_lock_us = freeze_lock_time.as_us();
|
|
|
|
|
2022-06-06 18:21:05 -07:00
|
|
|
let (record_transactions_summary, record_time) = measure!(
|
|
|
|
Self::record_transactions(bank.slot(), executed_transactions, poh),
|
2022-02-16 22:14:32 -08:00
|
|
|
"record_transactions",
|
|
|
|
);
|
|
|
|
execute_and_commit_timings.record_us = record_time.as_us();
|
|
|
|
|
|
|
|
let RecordTransactionsSummary {
|
2022-04-21 06:06:26 -07:00
|
|
|
result: record_transactions_result,
|
2022-02-16 22:14:32 -08:00
|
|
|
record_transactions_timings,
|
2022-06-23 12:37:38 -07:00
|
|
|
starting_transaction_index,
|
2022-02-16 22:14:32 -08:00
|
|
|
} = record_transactions_summary;
|
2022-04-21 06:06:26 -07:00
|
|
|
execute_and_commit_timings.record_transactions_timings = RecordTransactionsTimings {
|
|
|
|
execution_results_to_transactions_us: execution_results_to_transactions_time.as_us(),
|
|
|
|
..record_transactions_timings
|
|
|
|
};
|
2019-05-23 17:35:15 -07:00
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
if let Err(recorder_err) = record_transactions_result {
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"banking_stage-record_transactions_retryable_record_txs",
|
|
|
|
executed_transactions_count
|
|
|
|
);
|
|
|
|
|
|
|
|
retryable_transaction_indexes.extend(execution_results.iter().enumerate().filter_map(
|
2022-08-22 18:01:03 -07:00
|
|
|
|(index, execution_result)| execution_result.was_executed().then_some(index),
|
2022-04-21 06:06:26 -07:00
|
|
|
));
|
2022-04-11 14:00:09 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
return ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
retryable_transaction_indexes,
|
2022-04-21 06:06:26 -07:00
|
|
|
commit_transactions_result: Err(recorder_err),
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
};
|
2019-08-09 21:14:20 -07:00
|
|
|
}
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2021-07-15 20:51:27 -07:00
|
|
|
let sanitized_txs = batch.sanitized_transactions();
|
2022-04-21 06:06:26 -07:00
|
|
|
let (commit_time_us, commit_transaction_statuses) = if executed_transactions_count != 0 {
|
2022-10-29 12:36:57 -07:00
|
|
|
Self::commit_transactions(
|
|
|
|
batch,
|
|
|
|
&mut loaded_transactions,
|
|
|
|
execution_results,
|
|
|
|
sanitized_txs,
|
|
|
|
starting_transaction_index,
|
|
|
|
bank,
|
|
|
|
&mut pre_balance_info,
|
|
|
|
&mut execute_and_commit_timings,
|
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
|
|
|
signature_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
)
|
2022-02-16 22:14:32 -08:00
|
|
|
} else {
|
2022-04-21 06:06:26 -07:00
|
|
|
(
|
|
|
|
0,
|
|
|
|
vec![CommitTransactionDetails::NotCommitted; execution_results.len()],
|
|
|
|
)
|
2022-02-16 22:14:32 -08:00
|
|
|
};
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2019-05-23 17:35:15 -07:00
|
|
|
drop(freeze_lock);
|
2019-05-07 15:51:35 -07:00
|
|
|
|
2019-03-23 13:30:56 -07:00
|
|
|
debug!(
|
2019-08-09 21:14:20 -07:00
|
|
|
"bank: {} process_and_record_locked: {}us record: {}us commit: {}us txs_len: {}",
|
2019-03-23 13:30:56 -07:00
|
|
|
bank.slot(),
|
2019-06-29 06:34:49 -07:00
|
|
|
load_execute_time.as_us(),
|
|
|
|
record_time.as_us(),
|
2022-02-16 22:14:32 -08:00
|
|
|
commit_time_us,
|
2021-07-15 20:51:27 -07:00
|
|
|
sanitized_txs.len(),
|
2019-03-23 13:30:56 -07:00
|
|
|
);
|
|
|
|
|
2021-03-03 15:07:45 -08:00
|
|
|
debug!(
|
2022-02-03 00:56:36 -08:00
|
|
|
"execute_and_commit_transactions_locked: {:?}",
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings.execute_timings,
|
2021-03-03 15:07:45 -08:00
|
|
|
);
|
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
debug_assert_eq!(
|
|
|
|
commit_transaction_statuses.len(),
|
|
|
|
transactions_attempted_execution_count
|
|
|
|
);
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
retryable_transaction_indexes,
|
2022-04-21 06:06:26 -07:00
|
|
|
commit_transactions_result: Ok(commit_transaction_statuses),
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
}
|
2019-03-23 13:30:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_and_record_transactions(
|
2019-11-20 15:43:10 -08:00
|
|
|
bank: &Arc<Bank>,
|
2021-07-15 20:51:27 -07:00
|
|
|
txs: &[SanitizedTransaction],
|
2021-03-23 07:10:04 -07:00
|
|
|
poh: &TransactionRecorder,
|
2019-05-07 10:23:02 -07:00
|
|
|
chunk_offset: usize,
|
2022-10-20 14:10:48 -07:00
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
2021-12-22 13:39:59 -08:00
|
|
|
qos_service: &QosService,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-02-03 00:56:36 -08:00
|
|
|
) -> ProcessTransactionBatchOutput {
|
2022-04-08 10:34:11 -07:00
|
|
|
let mut cost_model_time = Measure::start("cost_model");
|
2022-02-16 22:14:32 -08:00
|
|
|
|
2022-04-08 10:34:11 -07:00
|
|
|
let transaction_costs = qos_service.compute_transaction_costs(txs.iter());
|
2022-02-16 22:14:32 -08:00
|
|
|
|
2022-04-08 10:34:11 -07:00
|
|
|
let (transactions_qos_results, num_included) =
|
|
|
|
qos_service.select_transactions_per_cost(txs.iter(), transaction_costs.iter(), bank);
|
2022-02-16 22:14:32 -08:00
|
|
|
|
2022-04-08 10:34:11 -07:00
|
|
|
let cost_model_throttled_transactions_count = txs.len().saturating_sub(num_included);
|
|
|
|
|
|
|
|
qos_service.accumulate_estimated_transaction_costs(
|
|
|
|
&Self::accumulate_batched_transaction_costs(
|
|
|
|
transaction_costs.iter(),
|
|
|
|
transactions_qos_results.iter(),
|
|
|
|
),
|
2022-04-08 05:22:31 -07:00
|
|
|
);
|
2022-04-08 10:34:11 -07:00
|
|
|
cost_model_time.stop();
|
2022-01-14 15:44:18 -08:00
|
|
|
|
2021-11-11 23:04:53 -08:00
|
|
|
// Only lock accounts for those transactions are selected for the block;
|
2019-03-23 13:30:56 -07:00
|
|
|
// Once accounts are locked, other threads cannot encode transactions that will modify the
|
|
|
|
// same account state
|
2021-11-11 23:04:53 -08:00
|
|
|
let mut lock_time = Measure::start("lock_time");
|
2022-04-07 13:42:39 -07:00
|
|
|
let batch = bank.prepare_sanitized_batch_with_results(txs, transactions_qos_results.iter());
|
2019-06-29 06:34:49 -07:00
|
|
|
lock_time.stop();
|
2019-03-23 13:30:56 -07:00
|
|
|
|
2021-12-12 12:57:18 -08:00
|
|
|
// retryable_txs includes AccountInUse, WouldExceedMaxBlockCostLimit
|
2022-01-12 21:27:19 -08:00
|
|
|
// WouldExceedMaxAccountCostLimit, WouldExceedMaxVoteCostLimit
|
|
|
|
// and WouldExceedMaxAccountDataCostLimit
|
2022-02-03 00:56:36 -08:00
|
|
|
let mut execute_and_commit_transactions_output =
|
|
|
|
Self::execute_and_commit_transactions_locked(
|
2022-01-14 15:44:18 -08:00
|
|
|
bank,
|
|
|
|
poh,
|
|
|
|
&batch,
|
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2022-01-14 15:44:18 -08:00
|
|
|
);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
2022-04-07 13:42:39 -07:00
|
|
|
let mut unlock_time = Measure::start("unlock_time");
|
|
|
|
// Once the accounts are new transactions can enter the pipeline to process them
|
|
|
|
drop(batch);
|
|
|
|
unlock_time.stop();
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
ref mut retryable_transaction_indexes,
|
2022-02-16 22:14:32 -08:00
|
|
|
ref execute_and_commit_timings,
|
2022-04-12 18:16:57 -07:00
|
|
|
ref commit_transactions_result,
|
2022-02-03 00:56:36 -08:00
|
|
|
..
|
|
|
|
} = execute_and_commit_transactions_output;
|
|
|
|
|
2022-04-08 05:22:31 -07:00
|
|
|
QosService::update_or_remove_transaction_costs(
|
|
|
|
transaction_costs.iter(),
|
2022-04-07 13:42:39 -07:00
|
|
|
transactions_qos_results.iter(),
|
2022-04-12 18:16:57 -07:00
|
|
|
commit_transactions_result.as_ref().ok(),
|
2022-04-07 13:42:39 -07:00
|
|
|
bank,
|
|
|
|
);
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
retryable_transaction_indexes
|
|
|
|
.iter_mut()
|
|
|
|
.for_each(|x| *x += chunk_offset);
|
2019-03-23 13:30:56 -07:00
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
let (cu, us) =
|
|
|
|
Self::accumulate_execute_units_and_time(&execute_and_commit_timings.execute_timings);
|
2022-01-14 15:44:18 -08:00
|
|
|
qos_service.accumulate_actual_execute_cu(cu);
|
|
|
|
qos_service.accumulate_actual_execute_time(us);
|
|
|
|
|
2021-12-22 13:39:59 -08:00
|
|
|
// reports qos service stats for this batch
|
|
|
|
qos_service.report_metrics(bank.clone());
|
|
|
|
|
2019-02-16 14:02:21 -08:00
|
|
|
debug!(
|
2019-03-23 13:30:56 -07:00
|
|
|
"bank: {} lock: {}us unlock: {}us txs_len: {}",
|
2019-03-03 16:44:06 -08:00
|
|
|
bank.slot(),
|
2019-06-29 06:34:49 -07:00
|
|
|
lock_time.as_us(),
|
|
|
|
unlock_time.as_us(),
|
2019-02-16 14:02:21 -08:00
|
|
|
txs.len(),
|
|
|
|
);
|
2019-03-23 13:30:56 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
ProcessTransactionBatchOutput {
|
|
|
|
cost_model_throttled_transactions_count,
|
2022-02-16 22:14:32 -08:00
|
|
|
cost_model_us: cost_model_time.as_us(),
|
2022-02-03 00:56:36 -08:00
|
|
|
execute_and_commit_transactions_output,
|
|
|
|
}
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
|
|
|
|
2022-01-14 15:44:18 -08:00
|
|
|
// rollup transaction cost details, eg signature_cost, write_lock_cost, data_bytes_cost and
|
|
|
|
// execution_cost from the batch of transactions selected for block.
|
|
|
|
fn accumulate_batched_transaction_costs<'a>(
|
|
|
|
transactions_costs: impl Iterator<Item = &'a TransactionCost>,
|
|
|
|
transaction_results: impl Iterator<Item = &'a transaction::Result<()>>,
|
2022-03-13 08:58:57 -07:00
|
|
|
) -> BatchedTransactionDetails {
|
|
|
|
let mut batched_transaction_details = BatchedTransactionDetails::default();
|
2022-01-14 15:44:18 -08:00
|
|
|
transactions_costs
|
|
|
|
.zip(transaction_results)
|
2022-03-13 08:58:57 -07:00
|
|
|
.for_each(|(cost, result)| match result {
|
|
|
|
Ok(_) => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details.costs.batched_signature_cost,
|
|
|
|
cost.signature_cost
|
|
|
|
);
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details.costs.batched_write_lock_cost,
|
|
|
|
cost.write_lock_cost
|
|
|
|
);
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details.costs.batched_data_bytes_cost,
|
|
|
|
cost.data_bytes_cost
|
|
|
|
);
|
|
|
|
saturating_add_assign!(
|
2022-04-19 11:25:47 -07:00
|
|
|
batched_transaction_details
|
|
|
|
.costs
|
|
|
|
.batched_builtins_execute_cost,
|
|
|
|
cost.builtins_execution_cost
|
|
|
|
);
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details.costs.batched_bpf_execute_cost,
|
|
|
|
cost.bpf_execution_cost
|
2022-03-13 08:58:57 -07:00
|
|
|
);
|
2022-01-14 15:44:18 -08:00
|
|
|
}
|
2022-03-13 08:58:57 -07:00
|
|
|
Err(transaction_error) => match transaction_error {
|
|
|
|
TransactionError::WouldExceedMaxBlockCostLimit => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details
|
|
|
|
.errors
|
|
|
|
.batched_retried_txs_per_block_limit_count,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
TransactionError::WouldExceedMaxVoteCostLimit => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details
|
|
|
|
.errors
|
|
|
|
.batched_retried_txs_per_vote_limit_count,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
TransactionError::WouldExceedMaxAccountCostLimit => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details
|
|
|
|
.errors
|
|
|
|
.batched_retried_txs_per_account_limit_count,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
TransactionError::WouldExceedAccountDataBlockLimit => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details
|
|
|
|
.errors
|
|
|
|
.batched_retried_txs_per_account_data_block_limit_count,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
TransactionError::WouldExceedAccountDataTotalLimit => {
|
|
|
|
saturating_add_assign!(
|
|
|
|
batched_transaction_details
|
|
|
|
.errors
|
|
|
|
.batched_dropped_txs_per_account_data_total_limit_count,
|
|
|
|
1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
},
|
2022-01-14 15:44:18 -08:00
|
|
|
});
|
2022-03-13 08:58:57 -07:00
|
|
|
batched_transaction_details
|
2022-01-14 15:44:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn accumulate_execute_units_and_time(execute_timings: &ExecuteTimings) -> (u64, u64) {
|
|
|
|
let (units, times): (Vec<_>, Vec<_>) = execute_timings
|
|
|
|
.details
|
|
|
|
.per_program_timings
|
2022-09-23 13:57:27 -07:00
|
|
|
.values()
|
|
|
|
.map(|program_timings| {
|
2022-01-14 15:44:18 -08:00
|
|
|
(
|
|
|
|
program_timings.accumulated_units,
|
|
|
|
program_timings.accumulated_us,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.unzip();
|
|
|
|
(units.iter().sum(), times.iter().sum())
|
|
|
|
}
|
|
|
|
|
2019-02-13 19:12:14 -08:00
|
|
|
/// Sends transactions to the bank.
|
|
|
|
///
|
|
|
|
/// Returns the number of transactions successfully processed by the bank, which may be less
|
|
|
|
/// than the total number if max PoH height was reached and the bank halted
|
2018-09-21 21:01:13 -07:00
|
|
|
fn process_transactions(
|
2019-11-20 15:43:10 -08:00
|
|
|
bank: &Arc<Bank>,
|
2021-03-15 17:11:15 -07:00
|
|
|
bank_creation_time: &Instant,
|
2021-07-15 20:51:27 -07:00
|
|
|
transactions: &[SanitizedTransaction],
|
2021-03-23 07:10:04 -07:00
|
|
|
poh: &TransactionRecorder,
|
2022-10-20 14:10:48 -07:00
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender: &ReplayVoteSender,
|
2021-12-22 13:39:59 -08:00
|
|
|
qos_service: &QosService,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-02-03 00:56:36 -08:00
|
|
|
) -> ProcessTransactionsSummary {
|
2018-09-21 21:01:13 -07:00
|
|
|
let mut chunk_start = 0;
|
2022-02-03 00:56:36 -08:00
|
|
|
let mut all_retryable_tx_indexes = vec![];
|
|
|
|
// All the transactions that attempted execution. See description of
|
|
|
|
// struct ProcessTransactionsSummary above for possible outcomes.
|
|
|
|
let mut total_transactions_attempted_execution_count: usize = 0;
|
|
|
|
// All transactions that were executed and committed
|
|
|
|
let mut total_committed_transactions_count: usize = 0;
|
|
|
|
// All transactions that were executed and committed with a successful result
|
|
|
|
let mut total_committed_transactions_with_successful_result_count: usize = 0;
|
|
|
|
// All transactions that were executed but then failed record because the
|
|
|
|
// slot ended
|
|
|
|
let mut total_failed_commit_count: usize = 0;
|
|
|
|
let mut total_cost_model_throttled_transactions_count: usize = 0;
|
2022-02-16 22:14:32 -08:00
|
|
|
let mut total_cost_model_us: u64 = 0;
|
|
|
|
let mut total_execute_and_commit_timings = LeaderExecuteAndCommitTimings::default();
|
2022-04-23 16:10:47 -07:00
|
|
|
let mut total_error_counters = TransactionErrorMetrics::default();
|
2022-02-03 00:56:36 -08:00
|
|
|
let mut reached_max_poh_height = false;
|
2018-09-21 21:01:13 -07:00
|
|
|
while chunk_start != transactions.len() {
|
2019-09-10 11:04:03 -07:00
|
|
|
let chunk_end = std::cmp::min(
|
|
|
|
transactions.len(),
|
|
|
|
chunk_start + MAX_NUM_TRANSACTIONS_PER_BATCH,
|
|
|
|
);
|
2022-02-03 00:56:36 -08:00
|
|
|
let process_transaction_batch_output = Self::process_and_record_transactions(
|
2019-02-16 14:02:21 -08:00
|
|
|
bank,
|
|
|
|
&transactions[chunk_start..chunk_end],
|
|
|
|
poh,
|
2019-05-07 10:23:02 -07:00
|
|
|
chunk_start,
|
2022-10-20 14:10:48 -07:00
|
|
|
transaction_status_sender,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-11-18 13:35:30 -08:00
|
|
|
qos_service,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2019-02-16 14:02:21 -08:00
|
|
|
);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
let ProcessTransactionBatchOutput {
|
|
|
|
cost_model_throttled_transactions_count: new_cost_model_throttled_transactions_count,
|
2022-02-16 22:14:32 -08:00
|
|
|
cost_model_us: new_cost_model_us,
|
2022-02-03 00:56:36 -08:00
|
|
|
execute_and_commit_transactions_output,
|
|
|
|
} = process_transaction_batch_output;
|
|
|
|
total_cost_model_throttled_transactions_count =
|
|
|
|
total_cost_model_throttled_transactions_count
|
|
|
|
.saturating_add(new_cost_model_throttled_transactions_count);
|
2022-02-16 22:14:32 -08:00
|
|
|
total_cost_model_us = total_cost_model_us.saturating_add(new_cost_model_us);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count: new_transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count: new_executed_transactions_count,
|
|
|
|
executed_with_successful_result_count: new_executed_with_successful_result_count,
|
|
|
|
retryable_transaction_indexes: new_retryable_transaction_indexes,
|
|
|
|
commit_transactions_result: new_commit_transactions_result,
|
2022-02-16 22:14:32 -08:00
|
|
|
execute_and_commit_timings: new_execute_and_commit_timings,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters: new_error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
..
|
|
|
|
} = execute_and_commit_transactions_output;
|
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
total_execute_and_commit_timings.accumulate(&new_execute_and_commit_timings);
|
2022-04-23 16:10:47 -07:00
|
|
|
total_error_counters.accumulate(&new_error_counters);
|
2022-02-03 00:56:36 -08:00
|
|
|
total_transactions_attempted_execution_count =
|
|
|
|
total_transactions_attempted_execution_count
|
|
|
|
.saturating_add(new_transactions_attempted_execution_count);
|
|
|
|
|
|
|
|
trace!(
|
|
|
|
"process_transactions result: {:?}",
|
|
|
|
new_commit_transactions_result
|
|
|
|
);
|
|
|
|
|
|
|
|
if new_commit_transactions_result.is_ok() {
|
|
|
|
total_committed_transactions_count = total_committed_transactions_count
|
|
|
|
.saturating_add(new_executed_transactions_count);
|
|
|
|
total_committed_transactions_with_successful_result_count =
|
|
|
|
total_committed_transactions_with_successful_result_count
|
|
|
|
.saturating_add(new_executed_with_successful_result_count);
|
|
|
|
} else {
|
|
|
|
total_failed_commit_count =
|
|
|
|
total_failed_commit_count.saturating_add(new_executed_transactions_count);
|
|
|
|
}
|
2019-06-26 22:39:50 -07:00
|
|
|
|
|
|
|
// Add the retryable txs (transactions that errored in a way that warrants a retry)
|
|
|
|
// to the list of unprocessed txs.
|
2022-02-03 00:56:36 -08:00
|
|
|
all_retryable_tx_indexes.extend_from_slice(&new_retryable_transaction_indexes);
|
2021-03-15 17:11:15 -07:00
|
|
|
|
|
|
|
// If `bank_creation_time` is None, it's a test so ignore the option so
|
|
|
|
// allow processing
|
|
|
|
let should_bank_still_be_processing_txs =
|
|
|
|
Bank::should_bank_still_be_processing_txs(bank_creation_time, bank.ns_per_slot);
|
2022-02-03 00:56:36 -08:00
|
|
|
match (
|
|
|
|
new_commit_transactions_result,
|
|
|
|
should_bank_still_be_processing_txs,
|
|
|
|
) {
|
2021-03-15 17:11:15 -07:00
|
|
|
(Err(PohRecorderError::MaxHeightReached), _) | (_, false) => {
|
|
|
|
info!(
|
|
|
|
"process transactions: max height reached slot: {} height: {}",
|
|
|
|
bank.slot(),
|
|
|
|
bank.tick_height()
|
|
|
|
);
|
|
|
|
// process_and_record_transactions has returned all retryable errors in
|
|
|
|
// transactions[chunk_start..chunk_end], so we just need to push the remaining
|
|
|
|
// transactions into the unprocessed queue.
|
2022-02-03 00:56:36 -08:00
|
|
|
all_retryable_tx_indexes.extend(chunk_end..transactions.len());
|
|
|
|
reached_max_poh_height = true;
|
2021-03-15 17:11:15 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
_ => (),
|
2019-02-13 19:12:14 -08:00
|
|
|
}
|
2019-06-26 22:39:50 -07:00
|
|
|
// Don't exit early on any other type of error, continue processing...
|
2019-05-07 10:23:02 -07:00
|
|
|
chunk_start = chunk_end;
|
2018-09-21 21:01:13 -07:00
|
|
|
}
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
ProcessTransactionsSummary {
|
|
|
|
reached_max_poh_height,
|
|
|
|
transactions_attempted_execution_count: total_transactions_attempted_execution_count,
|
|
|
|
committed_transactions_count: total_committed_transactions_count,
|
|
|
|
committed_transactions_with_successful_result_count:
|
|
|
|
total_committed_transactions_with_successful_result_count,
|
|
|
|
failed_commit_count: total_failed_commit_count,
|
|
|
|
retryable_transaction_indexes: all_retryable_tx_indexes,
|
|
|
|
cost_model_throttled_transactions_count: total_cost_model_throttled_transactions_count,
|
2022-02-16 22:14:32 -08:00
|
|
|
cost_model_us: total_cost_model_us,
|
|
|
|
execute_and_commit_timings: total_execute_and_commit_timings,
|
2022-04-23 16:10:47 -07:00
|
|
|
error_counters: total_error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
}
|
2018-09-21 21:01:13 -07:00
|
|
|
}
|
|
|
|
|
2022-09-29 14:33:40 -07:00
|
|
|
/// This function creates a filter of transaction results with Ok() for every pending
|
|
|
|
/// transaction. The non-pending transactions are marked with TransactionError
|
2019-05-08 10:32:25 -07:00
|
|
|
fn prepare_filter_for_pending_transactions(
|
2021-04-12 23:28:08 -07:00
|
|
|
transactions_len: usize,
|
2019-05-08 10:32:25 -07:00
|
|
|
pending_tx_indexes: &[usize],
|
2021-12-29 23:42:32 -08:00
|
|
|
) -> Vec<transaction::Result<()>> {
|
2021-04-12 23:28:08 -07:00
|
|
|
let mut mask = vec![Err(TransactionError::BlockhashNotFound); transactions_len];
|
2021-12-29 23:42:32 -08:00
|
|
|
pending_tx_indexes.iter().for_each(|x| mask[*x] = Ok(()));
|
2019-05-08 10:32:25 -07:00
|
|
|
mask
|
|
|
|
}
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2022-09-29 14:33:40 -07:00
|
|
|
/// This function returns a vector containing index of all valid transactions. A valid
|
|
|
|
/// transaction has result Ok() as the value
|
2019-05-08 10:32:25 -07:00
|
|
|
fn filter_valid_transaction_indexes(
|
2020-11-29 11:21:55 -08:00
|
|
|
valid_txs: &[TransactionCheckResult],
|
2019-05-08 10:32:25 -07:00
|
|
|
transaction_indexes: &[usize],
|
|
|
|
) -> Vec<usize> {
|
2021-09-08 09:32:38 -07:00
|
|
|
valid_txs
|
2019-05-07 10:23:02 -07:00
|
|
|
.iter()
|
2019-05-08 10:32:25 -07:00
|
|
|
.enumerate()
|
2019-12-07 11:54:10 -08:00
|
|
|
.filter_map(|(index, (x, _h))| if x.is_ok() { Some(index) } else { None })
|
2021-09-08 09:32:38 -07:00
|
|
|
.map(|x| transaction_indexes[x])
|
|
|
|
.collect_vec()
|
2019-05-02 19:05:53 -07:00
|
|
|
}
|
|
|
|
|
2022-09-29 14:33:40 -07:00
|
|
|
/// This function filters pending packets that are still valid
|
|
|
|
/// # Arguments
|
|
|
|
/// * `transactions` - a batch of transactions deserialized from packets
|
|
|
|
/// * `transaction_to_packet_indexes` - maps each transaction to a packet index
|
|
|
|
/// * `pending_indexes` - identifies which indexes in the `transactions` list are still pending
|
|
|
|
fn filter_pending_packets_from_pending_txs(
|
|
|
|
bank: &Arc<Bank>,
|
|
|
|
transactions: &[SanitizedTransaction],
|
|
|
|
transaction_to_packet_indexes: &[usize],
|
|
|
|
pending_indexes: &[usize],
|
|
|
|
) -> Vec<usize> {
|
|
|
|
let filter =
|
|
|
|
Self::prepare_filter_for_pending_transactions(transactions.len(), pending_indexes);
|
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let results = bank.check_transactions_with_forwarding_delay(
|
|
|
|
transactions,
|
|
|
|
&filter,
|
|
|
|
FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET,
|
|
|
|
);
|
2019-05-08 10:32:25 -07:00
|
|
|
|
2021-04-12 23:28:08 -07:00
|
|
|
Self::filter_valid_transaction_indexes(&results, transaction_to_packet_indexes)
|
2019-05-13 14:40:05 -07:00
|
|
|
}
|
2019-05-08 10:32:25 -07:00
|
|
|
|
2021-06-01 07:16:17 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2022-05-04 19:50:56 -07:00
|
|
|
fn process_packets_transactions<'a>(
|
|
|
|
bank: &'a Arc<Bank>,
|
2021-03-15 17:11:15 -07:00
|
|
|
bank_creation_time: &Instant,
|
2022-05-04 19:50:56 -07:00
|
|
|
poh: &'a TransactionRecorder,
|
|
|
|
deserialized_packets: impl Iterator<Item = &'a ImmutableDeserializedPacket>,
|
2022-10-20 14:10:48 -07:00
|
|
|
transaction_status_sender: &Option<TransactionStatusSender>,
|
2022-05-04 19:50:56 -07:00
|
|
|
gossip_vote_sender: &'a ReplayVoteSender,
|
|
|
|
banking_stage_stats: &'a BankingStageStats,
|
|
|
|
qos_service: &'a QosService,
|
|
|
|
slot_metrics_tracker: &'a mut LeaderSlotMetricsTracker,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit: Option<usize>,
|
2022-02-03 00:56:36 -08:00
|
|
|
) -> ProcessTransactionsSummary {
|
2022-02-16 22:14:32 -08:00
|
|
|
// Convert packets to transactions
|
2022-05-04 19:50:56 -07:00
|
|
|
let ((transactions, transaction_to_packet_indexes), packet_conversion_time): (
|
|
|
|
(Vec<SanitizedTransaction>, Vec<usize>),
|
|
|
|
_,
|
2022-06-06 18:21:05 -07:00
|
|
|
) = measure!(
|
|
|
|
deserialized_packets
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(i, deserialized_packet)| {
|
2022-10-20 14:10:48 -07:00
|
|
|
deserialized_packet
|
|
|
|
.build_sanitized_transaction(
|
|
|
|
&bank.feature_set,
|
|
|
|
bank.vote_only_bank(),
|
|
|
|
bank.as_ref(),
|
|
|
|
)
|
|
|
|
.map(|transaction| (transaction, i))
|
2022-06-06 18:21:05 -07:00
|
|
|
})
|
|
|
|
.unzip(),
|
2022-02-16 22:14:32 -08:00
|
|
|
"packet_conversion",
|
2021-11-11 23:04:53 -08:00
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
let packet_conversion_us = packet_conversion_time.as_us();
|
|
|
|
slot_metrics_tracker.increment_transactions_from_packets_us(packet_conversion_us);
|
|
|
|
banking_stage_stats
|
|
|
|
.packet_conversion_elapsed
|
|
|
|
.fetch_add(packet_conversion_us, Ordering::Relaxed);
|
2021-06-28 19:34:04 -07:00
|
|
|
inc_new_counter_info!("banking_stage-packet_conversion", 1);
|
2021-04-12 23:28:08 -07:00
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
// Process transactions
|
2022-06-06 18:21:05 -07:00
|
|
|
let (mut process_transactions_summary, process_transactions_time) = measure!(
|
|
|
|
Self::process_transactions(
|
|
|
|
bank,
|
|
|
|
bank_creation_time,
|
|
|
|
&transactions,
|
|
|
|
poh,
|
|
|
|
transaction_status_sender,
|
|
|
|
gossip_vote_sender,
|
|
|
|
qos_service,
|
2022-07-11 08:53:18 -07:00
|
|
|
log_messages_bytes_limit,
|
2022-06-06 18:21:05 -07:00
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"process_transaction_time",
|
2020-08-07 11:21:35 -07:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
let process_transactions_us = process_transactions_time.as_us();
|
|
|
|
slot_metrics_tracker.increment_process_transactions_us(process_transactions_us);
|
|
|
|
banking_stage_stats
|
|
|
|
.transaction_processing_elapsed
|
|
|
|
.fetch_add(process_transactions_us, Ordering::Relaxed);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
let ProcessTransactionsSummary {
|
|
|
|
ref retryable_transaction_indexes,
|
2022-04-23 16:10:47 -07:00
|
|
|
ref error_counters,
|
2022-02-03 00:56:36 -08:00
|
|
|
..
|
|
|
|
} = process_transactions_summary;
|
2019-05-08 10:32:25 -07:00
|
|
|
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker.accumulate_process_transactions_summary(&process_transactions_summary);
|
2022-04-23 16:10:47 -07:00
|
|
|
slot_metrics_tracker.accumulate_transaction_errors(error_counters);
|
2022-02-11 00:07:45 -08:00
|
|
|
|
|
|
|
let retryable_tx_count = retryable_transaction_indexes.len();
|
|
|
|
inc_new_counter_info!("banking_stage-unprocessed_transactions", retryable_tx_count);
|
|
|
|
|
2022-05-04 19:50:56 -07:00
|
|
|
// Filter out the retryable transactions that are too old
|
2022-06-06 18:21:05 -07:00
|
|
|
let (filtered_retryable_transaction_indexes, filter_retryable_packets_time) = measure!(
|
|
|
|
Self::filter_pending_packets_from_pending_txs(
|
|
|
|
bank,
|
|
|
|
&transactions,
|
|
|
|
&transaction_to_packet_indexes,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
),
|
2022-02-16 22:14:32 -08:00
|
|
|
"filter_pending_packets_time",
|
2019-05-13 14:40:05 -07:00
|
|
|
);
|
2022-02-16 22:14:32 -08:00
|
|
|
let filter_retryable_packets_us = filter_retryable_packets_time.as_us();
|
2022-11-09 11:39:38 -08:00
|
|
|
slot_metrics_tracker.increment_filter_retryable_packets_us(filter_retryable_packets_us);
|
2022-02-16 22:14:32 -08:00
|
|
|
banking_stage_stats
|
|
|
|
.filter_pending_packets_elapsed
|
|
|
|
.fetch_add(filter_retryable_packets_us, Ordering::Relaxed);
|
2021-04-12 23:28:08 -07:00
|
|
|
|
2022-02-11 00:07:45 -08:00
|
|
|
let retryable_packets_filtered_count = retryable_transaction_indexes
|
|
|
|
.len()
|
2022-02-16 22:14:32 -08:00
|
|
|
.saturating_sub(filtered_retryable_transaction_indexes.len());
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker
|
|
|
|
.increment_retryable_packets_filtered_count(retryable_packets_filtered_count as u64);
|
|
|
|
|
2019-05-13 14:40:05 -07:00
|
|
|
inc_new_counter_info!(
|
|
|
|
"banking_stage-dropped_tx_before_forwarding",
|
2022-02-03 00:56:36 -08:00
|
|
|
retryable_transaction_indexes
|
|
|
|
.len()
|
2022-02-16 22:14:32 -08:00
|
|
|
.saturating_sub(filtered_retryable_transaction_indexes.len())
|
2019-05-08 10:32:25 -07:00
|
|
|
);
|
|
|
|
|
2022-02-16 22:14:32 -08:00
|
|
|
process_transactions_summary.retryable_transaction_indexes =
|
|
|
|
filtered_retryable_transaction_indexes;
|
2022-02-03 00:56:36 -08:00
|
|
|
process_transactions_summary
|
2019-05-13 14:40:05 -07:00
|
|
|
}
|
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-12-16 09:44:10 -08:00
|
|
|
/// Receive incoming packets, push into unprocessed buffer with packet indexes
|
|
|
|
fn receive_and_buffer_packets(
|
2022-09-01 08:00:48 -07:00
|
|
|
packet_deserializer: &mut PacketDeserializer,
|
2019-04-09 11:17:15 -07:00
|
|
|
recv_start: &mut Instant,
|
2019-04-14 12:34:07 -07:00
|
|
|
recv_timeout: Duration,
|
2019-05-20 09:15:00 -07:00
|
|
|
id: u32,
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
|
2022-01-19 00:13:07 -08:00
|
|
|
banking_stage_stats: &mut BankingStageStats,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats: &mut TracerPacketStats,
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
2021-02-12 03:27:37 -08:00
|
|
|
) -> Result<(), RecvTimeoutError> {
|
2021-12-16 09:44:10 -08:00
|
|
|
let mut recv_time = Measure::start("receive_and_buffer_packets_recv");
|
2022-09-01 08:00:48 -07:00
|
|
|
let ReceivePacketResults {
|
|
|
|
deserialized_packets,
|
|
|
|
new_tracer_stats_option,
|
|
|
|
passed_sigverify_count,
|
|
|
|
failed_sigverify_count,
|
|
|
|
} = packet_deserializer.handle_received_packets(
|
2022-05-08 10:47:55 -07:00
|
|
|
recv_timeout,
|
2022-10-26 08:03:47 -07:00
|
|
|
unprocessed_transaction_storage.max_receive_size(),
|
2022-05-08 10:47:55 -07:00
|
|
|
)?;
|
2022-09-01 08:00:48 -07:00
|
|
|
let packet_count = deserialized_packets.len();
|
2019-03-28 11:45:34 -07:00
|
|
|
debug!(
|
2019-05-20 09:15:00 -07:00
|
|
|
"@{:?} process start stalled for: {:?}ms txs: {} id: {}",
|
2019-09-06 14:30:56 -07:00
|
|
|
timestamp(),
|
|
|
|
duration_as_ms(&recv_start.elapsed()),
|
2021-12-11 06:44:15 -08:00
|
|
|
packet_count,
|
2019-05-20 09:15:00 -07:00
|
|
|
id,
|
2018-05-14 16:31:13 -07:00
|
|
|
);
|
2019-05-20 09:15:00 -07:00
|
|
|
|
2022-09-01 08:00:48 -07:00
|
|
|
if let Some(new_sigverify_stats) = &new_tracer_stats_option {
|
|
|
|
tracer_packet_stats.aggregate_sigverify_tracer_packet_stats(new_sigverify_stats);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Track all the packets incoming from sigverify, both valid and invalid
|
|
|
|
slot_metrics_tracker.increment_total_new_valid_packets(passed_sigverify_count);
|
|
|
|
slot_metrics_tracker.increment_newly_failed_sigverify_count(failed_sigverify_count);
|
|
|
|
|
2021-09-15 13:53:55 -07:00
|
|
|
let mut dropped_packets_count = 0;
|
2021-02-12 03:27:37 -08:00
|
|
|
let mut newly_buffered_packets_count = 0;
|
2022-09-01 08:00:48 -07:00
|
|
|
Self::push_unprocessed(
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage,
|
2022-09-01 08:00:48 -07:00
|
|
|
deserialized_packets,
|
|
|
|
&mut dropped_packets_count,
|
|
|
|
&mut newly_buffered_packets_count,
|
|
|
|
banking_stage_stats,
|
|
|
|
slot_metrics_tracker,
|
|
|
|
tracer_packet_stats,
|
|
|
|
);
|
2022-06-08 22:25:37 -07:00
|
|
|
recv_time.stop();
|
2019-06-29 06:34:49 -07:00
|
|
|
|
2021-04-12 23:28:08 -07:00
|
|
|
banking_stage_stats
|
2021-12-16 09:44:10 -08:00
|
|
|
.receive_and_buffer_packets_elapsed
|
2022-06-08 22:25:37 -07:00
|
|
|
.fetch_add(recv_time.as_us(), Ordering::Relaxed);
|
2021-02-12 03:27:37 -08:00
|
|
|
banking_stage_stats
|
2021-12-16 09:44:10 -08:00
|
|
|
.receive_and_buffer_packets_count
|
2021-12-11 06:44:15 -08:00
|
|
|
.fetch_add(packet_count, Ordering::Relaxed);
|
2021-10-20 19:56:48 -07:00
|
|
|
banking_stage_stats
|
|
|
|
.dropped_packets_count
|
|
|
|
.fetch_add(dropped_packets_count, Ordering::Relaxed);
|
2021-02-12 03:27:37 -08:00
|
|
|
banking_stage_stats
|
|
|
|
.newly_buffered_packets_count
|
|
|
|
.fetch_add(newly_buffered_packets_count, Ordering::Relaxed);
|
2022-05-04 19:50:56 -07:00
|
|
|
banking_stage_stats
|
|
|
|
.current_buffered_packets_count
|
2022-10-20 14:10:48 -07:00
|
|
|
.swap(unprocessed_transaction_storage.len(), Ordering::Relaxed);
|
2019-04-09 11:17:15 -07:00
|
|
|
*recv_start = Instant::now();
|
2021-02-12 03:27:37 -08:00
|
|
|
Ok(())
|
2019-02-13 19:12:14 -08:00
|
|
|
}
|
2019-05-20 09:15:00 -07:00
|
|
|
|
|
|
|
fn push_unprocessed(
|
2022-10-20 14:10:48 -07:00
|
|
|
unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
|
2022-09-01 08:00:48 -07:00
|
|
|
deserialized_packets: Vec<ImmutableDeserializedPacket>,
|
2021-09-15 13:53:55 -07:00
|
|
|
dropped_packets_count: &mut usize,
|
2021-02-12 03:27:37 -08:00
|
|
|
newly_buffered_packets_count: &mut usize,
|
2022-01-19 00:13:07 -08:00
|
|
|
banking_stage_stats: &mut BankingStageStats,
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
|
2022-06-08 22:25:37 -07:00
|
|
|
tracer_packet_stats: &mut TracerPacketStats,
|
2019-05-20 09:15:00 -07:00
|
|
|
) {
|
2022-09-01 08:00:48 -07:00
|
|
|
if !deserialized_packets.is_empty() {
|
2022-01-19 00:13:07 -08:00
|
|
|
let _ = banking_stage_stats
|
|
|
|
.batch_packet_indexes_len
|
2022-09-01 08:00:48 -07:00
|
|
|
.increment(deserialized_packets.len() as u64);
|
2022-01-19 00:13:07 -08:00
|
|
|
|
2022-09-01 08:00:48 -07:00
|
|
|
*newly_buffered_packets_count += deserialized_packets.len();
|
2022-02-11 00:07:45 -08:00
|
|
|
slot_metrics_tracker
|
2022-09-01 08:00:48 -07:00
|
|
|
.increment_newly_buffered_packets_count(deserialized_packets.len() as u64);
|
2022-03-10 10:47:46 -08:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let insert_packet_batches_summary =
|
|
|
|
unprocessed_transaction_storage.insert_batch(deserialized_packets);
|
|
|
|
slot_metrics_tracker
|
|
|
|
.accumulate_insert_packet_batches_summary(&insert_packet_batches_summary);
|
|
|
|
saturating_add_assign!(
|
|
|
|
*dropped_packets_count,
|
|
|
|
insert_packet_batches_summary.total_dropped_packets()
|
|
|
|
);
|
|
|
|
tracer_packet_stats.increment_total_exceeded_banking_stage_buffer(
|
|
|
|
insert_packet_batches_summary.dropped_tracer_packets(),
|
2022-05-04 19:50:56 -07:00
|
|
|
);
|
2019-05-20 09:15:00 -07:00
|
|
|
}
|
|
|
|
}
|
2018-10-18 22:57:48 -07:00
|
|
|
|
2019-11-13 10:12:09 -08:00
|
|
|
pub fn join(self) -> thread::Result<()> {
|
2018-10-18 22:57:48 -07:00
|
|
|
for bank_thread_hdl in self.bank_thread_hdls {
|
2019-02-13 19:12:14 -08:00
|
|
|
bank_thread_hdl.join()?;
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
2019-02-13 19:12:14 -08:00
|
|
|
Ok(())
|
2018-07-03 21:14:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:22:00 -07:00
|
|
|
pub(crate) fn next_leader_tpu(
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &RwLock<PohRecorder>,
|
2022-06-08 22:25:37 -07:00
|
|
|
) -> Option<(Pubkey, std::net::SocketAddr)> {
|
2021-10-07 02:38:23 -07:00
|
|
|
next_leader_x(cluster_info, poh_recorder, |leader| leader.tpu)
|
2021-04-17 10:22:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn next_leader_tpu_forwards(
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &RwLock<PohRecorder>,
|
2022-06-08 22:25:37 -07:00
|
|
|
) -> Option<(Pubkey, std::net::SocketAddr)> {
|
2021-10-07 02:38:23 -07:00
|
|
|
next_leader_x(cluster_info, poh_recorder, |leader| leader.tpu_forwards)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn next_leader_tpu_vote(
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &RwLock<PohRecorder>,
|
2022-06-08 22:25:37 -07:00
|
|
|
) -> Option<(Pubkey, std::net::SocketAddr)> {
|
2021-10-07 02:38:23 -07:00
|
|
|
next_leader_x(cluster_info, poh_recorder, |leader| leader.tpu_vote)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn next_leader_x<F>(
|
|
|
|
cluster_info: &ClusterInfo,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &RwLock<PohRecorder>,
|
2021-10-07 02:38:23 -07:00
|
|
|
port_selector: F,
|
2022-06-08 22:25:37 -07:00
|
|
|
) -> Option<(Pubkey, std::net::SocketAddr)>
|
2021-10-07 02:38:23 -07:00
|
|
|
where
|
|
|
|
F: FnOnce(&ContactInfo) -> SocketAddr,
|
|
|
|
{
|
2022-04-29 01:32:46 -07:00
|
|
|
let leader_pubkey = poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-17 10:22:00 -07:00
|
|
|
.unwrap()
|
2022-04-29 01:32:46 -07:00
|
|
|
.leader_after_n_slots(FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET);
|
|
|
|
if let Some(leader_pubkey) = leader_pubkey {
|
2022-06-08 22:25:37 -07:00
|
|
|
cluster_info
|
|
|
|
.lookup_contact_info(&leader_pubkey, port_selector)
|
|
|
|
.map(|addr| (leader_pubkey, addr))
|
2021-04-17 10:22:00 -07:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-25 15:01:51 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
2022-10-20 14:10:48 -07:00
|
|
|
crate::unprocessed_packet_batches,
|
2022-01-11 02:44:46 -08:00
|
|
|
crossbeam_channel::{unbounded, Receiver},
|
2022-01-13 23:24:41 -08:00
|
|
|
solana_address_lookup_table_program::state::{AddressLookupTable, LookupTableMeta},
|
|
|
|
solana_entry::entry::{next_entry, next_versioned_entry, Entry, EntrySlice},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_gossip::{cluster_info::Node, contact_info::ContactInfo},
|
|
|
|
solana_ledger::{
|
|
|
|
blockstore::{entries_to_test_shreds, Blockstore},
|
|
|
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
2022-02-03 00:56:36 -08:00
|
|
|
get_tmp_ledger_path_auto_delete,
|
2021-12-03 09:00:31 -08:00
|
|
|
leader_schedule_cache::LeaderScheduleCache,
|
|
|
|
},
|
2022-05-23 20:15:20 -07:00
|
|
|
solana_perf::packet::{to_packet_batches, PacketFlags},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_poh::{
|
|
|
|
poh_recorder::{create_test_recorder, Record, WorkingBankEntry},
|
|
|
|
poh_service::PohService,
|
|
|
|
},
|
2022-01-14 15:44:18 -08:00
|
|
|
solana_program_runtime::timings::ProgramTiming,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_rpc::transaction_status_service::TransactionStatusService,
|
2022-10-20 14:10:48 -07:00
|
|
|
solana_runtime::{bank_forks::BankForks, genesis_utils::activate_feature},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_sdk::{
|
2022-01-13 23:24:41 -08:00
|
|
|
account::AccountSharedData,
|
2021-12-03 09:00:31 -08:00
|
|
|
hash::Hash,
|
|
|
|
instruction::InstructionError,
|
2022-02-03 03:00:12 -08:00
|
|
|
message::{
|
|
|
|
v0::{self, MessageAddressTableLookup},
|
|
|
|
MessageHeader, VersionedMessage,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
poh_config::PohConfig,
|
|
|
|
signature::{Keypair, Signer},
|
|
|
|
system_transaction,
|
2022-07-05 21:24:58 -07:00
|
|
|
transaction::{MessageHash, Transaction, TransactionError, VersionedTransaction},
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
2021-12-29 10:34:31 -08:00
|
|
|
solana_streamer::{recvmmsg::recv_mmsg, socket::SocketAddrSpace},
|
2022-01-13 23:24:41 -08:00
|
|
|
solana_transaction_status::{TransactionStatusMeta, VersionedTransactionWithStatusMeta},
|
2022-10-20 14:10:48 -07:00
|
|
|
solana_vote_program::{
|
|
|
|
vote_state::VoteStateUpdate, vote_transaction::new_vote_state_update_transaction,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
std::{
|
2022-01-13 23:24:41 -08:00
|
|
|
borrow::Cow,
|
2022-05-04 19:50:56 -07:00
|
|
|
collections::HashSet,
|
2021-12-03 09:00:31 -08:00
|
|
|
path::Path,
|
2022-01-11 02:44:46 -08:00
|
|
|
sync::atomic::{AtomicBool, Ordering},
|
2021-12-03 09:00:31 -08:00
|
|
|
thread::sleep,
|
2021-06-04 08:23:06 -07:00
|
|
|
},
|
2021-03-23 07:10:04 -07:00
|
|
|
};
|
2018-09-25 15:01:51 -07:00
|
|
|
|
2021-07-23 08:25:03 -07:00
|
|
|
fn new_test_cluster_info(contact_info: ContactInfo) -> ClusterInfo {
|
|
|
|
ClusterInfo::new(
|
|
|
|
contact_info,
|
|
|
|
Arc::new(Keypair::new()),
|
|
|
|
SocketAddrSpace::Unspecified,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-09-25 15:01:51 -07:00
|
|
|
#[test]
|
2018-09-26 05:52:13 -07:00
|
|
|
fn test_banking_stage_shutdown1() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let genesis_config = create_genesis_config(2).genesis_config;
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2019-06-26 18:42:27 -07:00
|
|
|
let (verified_sender, verified_receiver) = unbounded();
|
2021-10-07 02:38:23 -07:00
|
|
|
let (gossip_verified_vote_sender, gossip_verified_vote_receiver) = unbounded();
|
|
|
|
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
let (exit, poh_recorder, poh_service, _entry_receiever) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, None, None);
|
2021-07-23 08:25:03 -07:00
|
|
|
let cluster_info = new_test_cluster_info(Node::new_localhost().info);
|
2020-04-21 12:54:45 -07:00
|
|
|
let cluster_info = Arc::new(cluster_info);
|
2021-10-07 02:38:23 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2019-04-17 21:07:45 -07:00
|
|
|
let banking_stage = BankingStage::new(
|
|
|
|
&cluster_info,
|
|
|
|
&poh_recorder,
|
|
|
|
verified_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
tpu_vote_receiver,
|
|
|
|
gossip_verified_vote_receiver,
|
2019-11-20 15:43:10 -08:00
|
|
|
None,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-10-19 12:37:33 -07:00
|
|
|
Arc::new(RwLock::new(CostModel::default())),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-06-08 04:57:12 -07:00
|
|
|
Arc::new(ConnectionCache::default()),
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2019-04-17 21:07:45 -07:00
|
|
|
);
|
2019-03-29 20:00:36 -07:00
|
|
|
drop(verified_sender);
|
2021-10-07 02:38:23 -07:00
|
|
|
drop(gossip_verified_vote_sender);
|
|
|
|
drop(tpu_vote_sender);
|
2019-03-29 20:00:36 -07:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
banking_stage.join().unwrap();
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
2018-09-25 15:01:51 -07:00
|
|
|
#[test]
|
|
|
|
fn test_banking_stage_tick() {
|
2019-03-03 16:44:06 -08:00
|
|
|
solana_logger::setup();
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
mut genesis_config, ..
|
|
|
|
} = create_genesis_config(2);
|
|
|
|
genesis_config.ticks_per_slot = 4;
|
2019-10-16 12:37:27 -07:00
|
|
|
let num_extra_ticks = 2;
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2019-03-02 10:25:16 -08:00
|
|
|
let start_hash = bank.last_blockhash();
|
2019-06-26 18:42:27 -07:00
|
|
|
let (verified_sender, verified_receiver) = unbounded();
|
2021-10-07 02:38:23 -07:00
|
|
|
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2020-12-13 17:26:34 -08:00
|
|
|
let poh_config = PohConfig {
|
|
|
|
target_tick_count: Some(bank.max_tick_height() + num_extra_ticks),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
2019-03-29 20:00:36 -07:00
|
|
|
let (exit, poh_recorder, poh_service, entry_receiver) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
2021-07-23 08:25:03 -07:00
|
|
|
let cluster_info = new_test_cluster_info(Node::new_localhost().info);
|
2020-04-21 12:54:45 -07:00
|
|
|
let cluster_info = Arc::new(cluster_info);
|
2021-10-07 02:38:23 -07:00
|
|
|
let (verified_gossip_vote_sender, verified_gossip_vote_receiver) = unbounded();
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2019-04-17 21:07:45 -07:00
|
|
|
let banking_stage = BankingStage::new(
|
|
|
|
&cluster_info,
|
|
|
|
&poh_recorder,
|
|
|
|
verified_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
tpu_vote_receiver,
|
|
|
|
verified_gossip_vote_receiver,
|
2019-11-20 15:43:10 -08:00
|
|
|
None,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-10-19 12:37:33 -07:00
|
|
|
Arc::new(RwLock::new(CostModel::default())),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-06-08 04:57:12 -07:00
|
|
|
Arc::new(ConnectionCache::default()),
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2019-04-17 21:07:45 -07:00
|
|
|
);
|
2019-03-29 20:00:36 -07:00
|
|
|
trace!("sending bank");
|
|
|
|
drop(verified_sender);
|
2021-10-07 02:38:23 -07:00
|
|
|
drop(verified_gossip_vote_sender);
|
|
|
|
drop(tpu_vote_sender);
|
2019-03-29 20:00:36 -07:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
drop(poh_recorder);
|
|
|
|
|
|
|
|
trace!("getting entries");
|
|
|
|
let entries: Vec<_> = entry_receiver
|
|
|
|
.iter()
|
2019-09-18 12:16:22 -07:00
|
|
|
.map(|(_bank, (entry, _tick_height))| entry)
|
2019-03-29 20:00:36 -07:00
|
|
|
.collect();
|
|
|
|
trace!("done");
|
2019-11-08 20:56:57 -08:00
|
|
|
assert_eq!(entries.len(), genesis_config.ticks_per_slot as usize);
|
2021-05-19 07:31:47 -07:00
|
|
|
assert!(entries.verify(&start_hash));
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(entries[entries.len() - 1].hash, bank.last_blockhash());
|
|
|
|
banking_stage.join().unwrap();
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2018-09-25 15:01:51 -07:00
|
|
|
}
|
|
|
|
|
2021-12-11 06:44:15 -08:00
|
|
|
pub fn convert_from_old_verified(
|
|
|
|
mut with_vers: Vec<(PacketBatch, Vec<u8>)>,
|
|
|
|
) -> Vec<PacketBatch> {
|
2019-11-01 14:23:03 -07:00
|
|
|
with_vers.iter_mut().for_each(|(b, v)| {
|
2022-05-23 13:30:15 -07:00
|
|
|
b.iter_mut()
|
2019-11-01 14:23:03 -07:00
|
|
|
.zip(v)
|
2022-01-02 09:10:32 -08:00
|
|
|
.for_each(|(p, f)| p.meta.set_discard(*f == 0))
|
2019-11-01 14:23:03 -07:00
|
|
|
});
|
|
|
|
with_vers.into_iter().map(|(b, _)| b).collect()
|
|
|
|
}
|
|
|
|
|
2018-09-25 15:01:51 -07:00
|
|
|
#[test]
|
2018-09-26 13:31:39 -07:00
|
|
|
fn test_banking_stage_entries_only() {
|
2019-03-12 21:07:06 -07:00
|
|
|
solana_logger::setup();
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2021-03-24 14:05:43 -07:00
|
|
|
} = create_slow_genesis_config(10);
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2019-03-02 10:25:16 -08:00
|
|
|
let start_hash = bank.last_blockhash();
|
2019-06-26 18:42:27 -07:00
|
|
|
let (verified_sender, verified_receiver) = unbounded();
|
2021-10-07 02:38:23 -07:00
|
|
|
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
|
|
|
let (gossip_verified_vote_sender, gossip_verified_vote_receiver) = unbounded();
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2020-12-13 17:26:34 -08:00
|
|
|
let poh_config = PohConfig {
|
|
|
|
// limit tick count to avoid clearing working_bank at PohRecord then
|
|
|
|
// PohRecorderError(MaxHeightReached) at BankingStage
|
|
|
|
target_tick_count: Some(bank.max_tick_height() - 1),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
2019-03-29 20:00:36 -07:00
|
|
|
let (exit, poh_recorder, poh_service, entry_receiver) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
2021-07-23 08:25:03 -07:00
|
|
|
let cluster_info = new_test_cluster_info(Node::new_localhost().info);
|
2020-04-21 12:54:45 -07:00
|
|
|
let cluster_info = Arc::new(cluster_info);
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2019-04-17 21:07:45 -07:00
|
|
|
let banking_stage = BankingStage::new(
|
|
|
|
&cluster_info,
|
|
|
|
&poh_recorder,
|
|
|
|
verified_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
tpu_vote_receiver,
|
|
|
|
gossip_verified_vote_receiver,
|
2019-11-20 15:43:10 -08:00
|
|
|
None,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-10-19 12:37:33 -07:00
|
|
|
Arc::new(RwLock::new(CostModel::default())),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-06-08 04:57:12 -07:00
|
|
|
Arc::new(ConnectionCache::default()),
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2019-04-17 21:07:45 -07:00
|
|
|
);
|
2018-09-25 15:01:51 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// fund another account so we can send 2 good transactions in a single batch.
|
|
|
|
let keypair = Keypair::new();
|
2019-10-19 18:23:27 -07:00
|
|
|
let fund_tx =
|
2019-10-23 22:01:22 -07:00
|
|
|
system_transaction::transfer(&mint_keypair, &keypair.pubkey(), 2, start_hash);
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.process_transaction(&fund_tx).unwrap();
|
2019-03-12 21:07:06 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// good tx
|
2020-10-19 12:12:08 -07:00
|
|
|
let to = solana_sdk::pubkey::new_rand();
|
2019-10-23 22:01:22 -07:00
|
|
|
let tx = system_transaction::transfer(&mint_keypair, &to, 1, start_hash);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// good tx, but no verify
|
2020-10-19 12:12:08 -07:00
|
|
|
let to2 = solana_sdk::pubkey::new_rand();
|
2019-10-23 22:01:22 -07:00
|
|
|
let tx_no_ver = system_transaction::transfer(&keypair, &to2, 2, start_hash);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// bad tx, AccountNotFound
|
|
|
|
let keypair = Keypair::new();
|
2020-10-19 12:12:08 -07:00
|
|
|
let to3 = solana_sdk::pubkey::new_rand();
|
2019-10-23 22:01:22 -07:00
|
|
|
let tx_anf = system_transaction::transfer(&keypair, &to3, 1, start_hash);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// send 'em over
|
2021-12-11 06:44:15 -08:00
|
|
|
let packet_batches = to_packet_batches(&[tx_no_ver, tx_anf, tx], 3);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// glad they all fit
|
2021-12-11 06:44:15 -08:00
|
|
|
assert_eq!(packet_batches.len(), 1);
|
2019-05-20 09:15:00 -07:00
|
|
|
|
2021-12-11 06:44:15 -08:00
|
|
|
let packet_batches = packet_batches
|
2019-05-20 09:15:00 -07:00
|
|
|
.into_iter()
|
2021-12-11 06:44:15 -08:00
|
|
|
.map(|batch| (batch, vec![0u8, 1u8, 1u8]))
|
2019-05-20 09:15:00 -07:00
|
|
|
.collect();
|
2021-12-11 06:44:15 -08:00
|
|
|
let packet_batches = convert_from_old_verified(packet_batches);
|
2019-03-29 20:00:36 -07:00
|
|
|
verified_sender // no_ver, anf, tx
|
2022-05-24 14:01:41 -07:00
|
|
|
.send((packet_batches, None))
|
2019-03-29 20:00:36 -07:00
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
drop(verified_sender);
|
2021-10-07 02:38:23 -07:00
|
|
|
drop(tpu_vote_sender);
|
|
|
|
drop(gossip_verified_vote_sender);
|
2019-10-16 12:37:27 -07:00
|
|
|
// wait until banking_stage to finish up all packets
|
|
|
|
banking_stage.join().unwrap();
|
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
drop(poh_recorder);
|
|
|
|
|
|
|
|
let mut blockhash = start_hash;
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.process_transaction(&fund_tx).unwrap();
|
|
|
|
//receive entries + ticks
|
2019-10-16 12:37:27 -07:00
|
|
|
loop {
|
2019-09-18 12:16:22 -07:00
|
|
|
let entries: Vec<Entry> = entry_receiver
|
2019-03-29 20:00:36 -07:00
|
|
|
.iter()
|
2019-09-18 12:16:22 -07:00
|
|
|
.map(|(_bank, (entry, _tick_height))| entry)
|
2019-03-29 20:00:36 -07:00
|
|
|
.collect();
|
|
|
|
|
2021-05-19 07:31:47 -07:00
|
|
|
assert!(entries.verify(&blockhash));
|
2019-10-16 12:37:27 -07:00
|
|
|
if !entries.is_empty() {
|
|
|
|
blockhash = entries.last().unwrap().hash;
|
|
|
|
for entry in entries {
|
2021-08-17 15:17:56 -07:00
|
|
|
bank.process_entry_transactions(entry.transactions)
|
2019-10-16 12:37:27 -07:00
|
|
|
.iter()
|
|
|
|
.for_each(|x| assert_eq!(*x, Ok(())));
|
|
|
|
}
|
2019-03-12 21:07:06 -07:00
|
|
|
}
|
2019-02-25 13:50:31 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
if bank.get_balance(&to) == 1 {
|
|
|
|
break;
|
|
|
|
}
|
2019-03-12 21:07:06 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
sleep(Duration::from_millis(200));
|
|
|
|
}
|
2019-03-12 21:07:06 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(bank.get_balance(&to), 1);
|
|
|
|
assert_eq!(bank.get_balance(&to2), 0);
|
2018-09-26 05:52:13 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
drop(entry_receiver);
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2018-09-26 13:31:39 -07:00
|
|
|
}
|
2019-03-03 16:44:06 -08:00
|
|
|
|
2018-09-25 15:01:51 -07:00
|
|
|
#[test]
|
|
|
|
fn test_banking_stage_entryfication() {
|
2019-03-18 22:08:21 -07:00
|
|
|
solana_logger::setup();
|
2018-09-25 15:01:51 -07:00
|
|
|
// In this attack we'll demonstrate that a verifier can interpret the ledger
|
|
|
|
// differently if either the server doesn't signal the ledger to add an
|
|
|
|
// Entry OR if the verifier tries to parallelize across multiple Entries.
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2021-03-24 14:05:43 -07:00
|
|
|
} = create_slow_genesis_config(2);
|
2019-06-26 18:42:27 -07:00
|
|
|
let (verified_sender, verified_receiver) = unbounded();
|
2018-09-25 15:01:51 -07:00
|
|
|
|
2022-05-12 08:36:19 -07:00
|
|
|
// Process a batch that includes a transaction that receives two lamports.
|
2018-09-25 15:01:51 -07:00
|
|
|
let alice = Keypair::new();
|
2022-05-12 08:36:19 -07:00
|
|
|
let tx =
|
|
|
|
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 2, genesis_config.hash());
|
|
|
|
|
|
|
|
let packet_batches = to_packet_batches(&[tx], 1);
|
|
|
|
let packet_batches = packet_batches
|
|
|
|
.into_iter()
|
|
|
|
.map(|batch| (batch, vec![1u8]))
|
|
|
|
.collect();
|
|
|
|
let packet_batches = convert_from_old_verified(packet_batches);
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_sender.send((packet_batches, None)).unwrap();
|
2022-05-12 08:36:19 -07:00
|
|
|
|
|
|
|
// Process a second batch that uses the same from account, so conflicts with above TX
|
|
|
|
let tx =
|
|
|
|
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, genesis_config.hash());
|
|
|
|
let packet_batches = to_packet_batches(&[tx], 1);
|
|
|
|
let packet_batches = packet_batches
|
|
|
|
.into_iter()
|
|
|
|
.map(|batch| (batch, vec![1u8]))
|
|
|
|
.collect();
|
|
|
|
let packet_batches = convert_from_old_verified(packet_batches);
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_sender.send((packet_batches, None)).unwrap();
|
2019-03-03 16:44:06 -08:00
|
|
|
|
2019-06-26 18:42:27 -07:00
|
|
|
let (vote_sender, vote_receiver) = unbounded();
|
2021-10-07 02:38:23 -07:00
|
|
|
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let entry_receiver = {
|
|
|
|
// start a banking_stage to eat verified receiver
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2019-03-29 20:00:36 -07:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
|
|
|
);
|
2020-12-13 17:26:34 -08:00
|
|
|
let poh_config = PohConfig {
|
|
|
|
// limit tick count to avoid clearing working_bank at
|
|
|
|
// PohRecord then PohRecorderError(MaxHeightReached) at BankingStage
|
|
|
|
target_tick_count: Some(bank.max_tick_height() - 1),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
2019-03-29 20:00:36 -07:00
|
|
|
let (exit, poh_recorder, poh_service, entry_receiver) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
2021-07-23 08:25:03 -07:00
|
|
|
let cluster_info = new_test_cluster_info(Node::new_localhost().info);
|
2020-04-21 12:54:45 -07:00
|
|
|
let cluster_info = Arc::new(cluster_info);
|
2019-03-29 20:00:36 -07:00
|
|
|
let _banking_stage = BankingStage::new_num_threads(
|
|
|
|
&cluster_info,
|
|
|
|
&poh_recorder,
|
|
|
|
verified_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
tpu_vote_receiver,
|
2019-04-17 21:07:45 -07:00
|
|
|
vote_receiver,
|
2021-10-07 02:38:23 -07:00
|
|
|
3,
|
2019-11-20 15:43:10 -08:00
|
|
|
None,
|
2020-08-07 11:21:35 -07:00
|
|
|
gossip_vote_sender,
|
2021-10-19 12:37:33 -07:00
|
|
|
Arc::new(RwLock::new(CostModel::default())),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-06-08 04:57:12 -07:00
|
|
|
Arc::new(ConnectionCache::default()),
|
2022-07-05 21:24:58 -07:00
|
|
|
bank_forks,
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-03-18 22:08:21 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// wait for banking_stage to eat the packets
|
2022-05-12 08:36:19 -07:00
|
|
|
while bank.get_balance(&alice.pubkey()) < 1 {
|
|
|
|
sleep(Duration::from_millis(10));
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
entry_receiver
|
|
|
|
};
|
|
|
|
drop(verified_sender);
|
2019-04-17 21:07:45 -07:00
|
|
|
drop(vote_sender);
|
2021-10-07 02:38:23 -07:00
|
|
|
drop(tpu_vote_sender);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// consume the entire entry_receiver, feed it into a new bank
|
|
|
|
// check that the balance is what we expect.
|
|
|
|
let entries: Vec<_> = entry_receiver
|
|
|
|
.iter()
|
2019-09-18 12:16:22 -07:00
|
|
|
.map(|(_bank, (entry, _tick_height))| entry)
|
2019-03-29 20:00:36 -07:00
|
|
|
.collect();
|
2018-09-25 15:01:51 -07:00
|
|
|
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
2021-08-17 15:17:56 -07:00
|
|
|
for entry in entries {
|
|
|
|
bank.process_entry_transactions(entry.transactions)
|
2019-03-29 20:00:36 -07:00
|
|
|
.iter()
|
|
|
|
.for_each(|x| assert_eq!(*x, Ok(())));
|
|
|
|
}
|
2019-03-18 22:08:21 -07:00
|
|
|
|
2022-05-12 08:36:19 -07:00
|
|
|
// Assert the user doesn't hold three lamports. If the stage only outputs one
|
|
|
|
// entry, then one of the transactions will be rejected, because it drives
|
2019-03-29 20:00:36 -07:00
|
|
|
// the account balance below zero before the credit is added.
|
2022-05-12 08:36:19 -07:00
|
|
|
assert!(bank.get_balance(&alice.pubkey()) != 3);
|
2019-03-11 12:45:45 -07:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2018-10-18 22:57:48 -07:00
|
|
|
}
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2021-08-17 15:17:56 -07:00
|
|
|
fn sanitize_transactions(txs: Vec<Transaction>) -> Vec<SanitizedTransaction> {
|
|
|
|
txs.into_iter()
|
2021-10-27 10:09:16 -07:00
|
|
|
.map(SanitizedTransaction::from_transaction_for_tests)
|
2021-08-17 15:17:56 -07:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2019-02-16 14:02:21 -08:00
|
|
|
#[test]
|
|
|
|
fn test_bank_record_transactions() {
|
2021-03-23 07:10:04 -07:00
|
|
|
solana_logger::setup();
|
|
|
|
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new(
|
|
|
|
// TODO use record_receiver
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2019-03-29 20:00:36 -07:00
|
|
|
None,
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
Arc::new(AtomicBool::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2021-03-23 07:10:04 -07:00
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2019-03-29 20:00:36 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2019-05-07 15:51:35 -07:00
|
|
|
let keypair2 = Keypair::new();
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey2 = solana_sdk::pubkey::new_rand();
|
2019-03-29 20:00:36 -07:00
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
let txs = vec![
|
|
|
|
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash())
|
|
|
|
.into(),
|
|
|
|
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()).into(),
|
|
|
|
];
|
2019-03-29 20:00:36 -07:00
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
let _ = BankingStage::record_transactions(bank.slot(), txs.clone(), &recorder);
|
2019-09-18 12:16:22 -07:00
|
|
|
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
|
2022-04-21 06:06:26 -07:00
|
|
|
assert_eq!(entry.transactions, txs);
|
2019-06-26 22:39:50 -07:00
|
|
|
|
|
|
|
// Once bank is set to a new bank (setting bank.slot() + 1 in record_transactions),
|
2022-04-21 06:06:26 -07:00
|
|
|
// record_transactions should throw MaxHeightReached
|
2021-09-13 16:55:35 -07:00
|
|
|
let next_slot = bank.slot() + 1;
|
2022-04-21 06:06:26 -07:00
|
|
|
let RecordTransactionsSummary { result, .. } =
|
|
|
|
BankingStage::record_transactions(next_slot, txs, &recorder);
|
2022-02-16 22:14:32 -08:00
|
|
|
assert_matches!(result, Err(PohRecorderError::MaxHeightReached));
|
2019-06-26 22:39:50 -07:00
|
|
|
// Should receive nothing from PohRecorder b/c record failed
|
|
|
|
assert!(entry_receiver.try_recv().is_err());
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
|
|
|
|
2019-05-08 10:32:25 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_prepare_filter_for_pending_transaction() {
|
|
|
|
assert_eq!(
|
2021-04-12 23:28:08 -07:00
|
|
|
BankingStage::prepare_filter_for_pending_transactions(6, &[2, 4, 5]),
|
2019-05-08 10:32:25 -07:00
|
|
|
vec![
|
|
|
|
Err(TransactionError::BlockhashNotFound),
|
|
|
|
Err(TransactionError::BlockhashNotFound),
|
2021-12-29 23:42:32 -08:00
|
|
|
Ok(()),
|
2019-05-08 10:32:25 -07:00
|
|
|
Err(TransactionError::BlockhashNotFound),
|
2021-12-29 23:42:32 -08:00
|
|
|
Ok(()),
|
|
|
|
Ok(())
|
2019-05-08 10:32:25 -07:00
|
|
|
]
|
|
|
|
);
|
2019-05-02 19:05:53 -07:00
|
|
|
|
2019-05-08 10:32:25 -07:00
|
|
|
assert_eq!(
|
2021-04-12 23:28:08 -07:00
|
|
|
BankingStage::prepare_filter_for_pending_transactions(6, &[0, 2, 3]),
|
2019-05-08 10:32:25 -07:00
|
|
|
vec![
|
2021-12-29 23:42:32 -08:00
|
|
|
Ok(()),
|
2019-05-08 10:32:25 -07:00
|
|
|
Err(TransactionError::BlockhashNotFound),
|
2021-12-29 23:42:32 -08:00
|
|
|
Ok(()),
|
|
|
|
Ok(()),
|
2019-05-08 10:32:25 -07:00
|
|
|
Err(TransactionError::BlockhashNotFound),
|
|
|
|
Err(TransactionError::BlockhashNotFound),
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
2019-05-02 19:05:53 -07:00
|
|
|
|
2019-05-08 10:32:25 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_filter_valid_transaction_indexes() {
|
|
|
|
assert_eq!(
|
|
|
|
BankingStage::filter_valid_transaction_indexes(
|
2020-05-15 09:35:43 -07:00
|
|
|
&[
|
2019-12-07 11:54:10 -08:00
|
|
|
(Err(TransactionError::BlockhashNotFound), None),
|
|
|
|
(Err(TransactionError::BlockhashNotFound), None),
|
2021-12-29 23:42:32 -08:00
|
|
|
(Ok(()), None),
|
2019-12-07 11:54:10 -08:00
|
|
|
(Err(TransactionError::BlockhashNotFound), None),
|
2021-12-29 23:42:32 -08:00
|
|
|
(Ok(()), None),
|
|
|
|
(Ok(()), None),
|
2019-05-08 10:32:25 -07:00
|
|
|
],
|
2020-05-15 09:35:43 -07:00
|
|
|
&[2, 4, 5, 9, 11, 13]
|
2019-05-08 10:32:25 -07:00
|
|
|
),
|
2020-05-15 09:35:43 -07:00
|
|
|
[5, 11, 13]
|
2019-05-08 10:32:25 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
BankingStage::filter_valid_transaction_indexes(
|
2020-05-15 09:35:43 -07:00
|
|
|
&[
|
2021-12-29 23:42:32 -08:00
|
|
|
(Ok(()), None),
|
2019-12-07 11:54:10 -08:00
|
|
|
(Err(TransactionError::BlockhashNotFound), None),
|
|
|
|
(Err(TransactionError::BlockhashNotFound), None),
|
2021-12-29 23:42:32 -08:00
|
|
|
(Ok(()), None),
|
|
|
|
(Ok(()), None),
|
|
|
|
(Ok(()), None),
|
2019-05-08 10:32:25 -07:00
|
|
|
],
|
2020-05-15 09:35:43 -07:00
|
|
|
&[1, 6, 7, 9, 31, 43]
|
2019-05-08 10:32:25 -07:00
|
|
|
),
|
2020-05-15 09:35:43 -07:00
|
|
|
[1, 9, 31, 43]
|
2019-05-08 10:32:25 -07:00
|
|
|
);
|
2019-05-02 19:05:53 -07:00
|
|
|
}
|
|
|
|
|
2019-04-13 23:19:54 -07:00
|
|
|
#[test]
|
|
|
|
fn test_should_process_or_forward_packets() {
|
2020-10-19 12:12:08 -07:00
|
|
|
let my_pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
let my_pubkey1 = solana_sdk::pubkey::new_rand();
|
2021-08-05 09:53:29 -07:00
|
|
|
let bank = Arc::new(Bank::default_for_tests());
|
2022-02-03 13:29:41 -08:00
|
|
|
// having active bank allows to consume immediately
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
|
|
|
BankingStage::consume_or_forward_packets(&my_pubkey, None, Some(&bank), false, false),
|
2022-02-03 13:29:41 -08:00
|
|
|
BufferedPacketsDecision::Consume(_)
|
2019-04-13 23:19:54 -07:00
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
|
|
|
BankingStage::consume_or_forward_packets(&my_pubkey, None, None, false, false),
|
2019-04-13 23:19:54 -07:00
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
|
|
|
BankingStage::consume_or_forward_packets(&my_pubkey1, None, None, false, false),
|
2019-04-13 23:19:54 -07:00
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
);
|
|
|
|
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
None,
|
2021-03-03 10:23:05 -08:00
|
|
|
false,
|
|
|
|
false
|
|
|
|
),
|
2019-04-13 23:19:54 -07:00
|
|
|
BufferedPacketsDecision::Forward
|
|
|
|
);
|
2021-03-03 10:23:05 -08:00
|
|
|
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
None,
|
2021-03-03 10:23:05 -08:00
|
|
|
true,
|
|
|
|
true
|
|
|
|
),
|
2019-04-23 11:56:30 -07:00
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
None,
|
2021-03-03 10:23:05 -08:00
|
|
|
true,
|
|
|
|
false
|
|
|
|
),
|
|
|
|
BufferedPacketsDecision::ForwardAndHold
|
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
Some(&bank),
|
2021-03-03 10:23:05 -08:00
|
|
|
false,
|
|
|
|
false
|
|
|
|
),
|
2021-03-15 17:11:15 -07:00
|
|
|
BufferedPacketsDecision::Consume(_)
|
2019-04-13 23:19:54 -07:00
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey1,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
None,
|
2021-03-03 10:23:05 -08:00
|
|
|
false,
|
|
|
|
false
|
|
|
|
),
|
2019-04-13 23:19:54 -07:00
|
|
|
BufferedPacketsDecision::Hold
|
|
|
|
);
|
2021-03-15 17:11:15 -07:00
|
|
|
assert_matches!(
|
2021-03-03 10:23:05 -08:00
|
|
|
BankingStage::consume_or_forward_packets(
|
|
|
|
&my_pubkey1,
|
|
|
|
Some(my_pubkey1),
|
2021-03-15 17:11:15 -07:00
|
|
|
Some(&bank),
|
2021-03-03 10:23:05 -08:00
|
|
|
false,
|
|
|
|
false
|
|
|
|
),
|
2021-03-15 17:11:15 -07:00
|
|
|
BufferedPacketsDecision::Consume(_)
|
2019-04-13 23:19:54 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-24 14:05:43 -07:00
|
|
|
fn create_slow_genesis_config(lamports: u64) -> GenesisConfigInfo {
|
|
|
|
let mut config_info = create_genesis_config(lamports);
|
|
|
|
// For these tests there's only 1 slot, don't want to run out of ticks
|
|
|
|
config_info.genesis_config.ticks_per_slot *= 8;
|
|
|
|
config_info
|
|
|
|
}
|
|
|
|
|
2019-02-16 14:02:21 -08:00
|
|
|
#[test]
|
|
|
|
fn test_bank_process_and_record_transactions() {
|
2019-02-26 10:48:18 -08:00
|
|
|
solana_logger::setup();
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2021-03-24 14:05:43 -07:00
|
|
|
} = create_slow_genesis_config(10_000);
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2021-10-27 10:09:16 -07:00
|
|
|
let transactions = sanitize_transactions(vec![system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&pubkey,
|
|
|
|
1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
)]);
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-03-29 20:00:36 -07:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new(
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
Arc::new(AtomicBool::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2021-03-23 07:10:04 -07:00
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2019-03-29 20:00:36 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
2019-03-29 20:00:36 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
2019-11-20 15:43:10 -08:00
|
|
|
&bank,
|
|
|
|
&transactions,
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2019-11-20 15:43:10 -08:00
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2020-08-07 11:21:35 -07:00
|
|
|
&gossip_vote_sender,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-02-03 00:56:36 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
commit_transactions_result,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
|
|
|
|
assert_eq!(transactions_attempted_execution_count, 1);
|
|
|
|
assert_eq!(executed_transactions_count, 1);
|
|
|
|
assert_eq!(executed_with_successful_result_count, 1);
|
|
|
|
assert!(commit_transactions_result.is_ok());
|
2021-09-13 16:55:35 -07:00
|
|
|
|
|
|
|
// Tick up to max tick height
|
2022-07-05 07:29:44 -07:00
|
|
|
while poh_recorder.read().unwrap().tick_height() != bank.max_tick_height() {
|
|
|
|
poh_recorder.write().unwrap().tick();
|
2021-09-13 16:55:35 -07:00
|
|
|
}
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let mut done = false;
|
|
|
|
// read entries until I find mine, might be ticks...
|
2019-09-18 12:16:22 -07:00
|
|
|
while let Ok((_bank, (entry, _tick_height))) = entry_receiver.recv() {
|
|
|
|
if !entry.is_tick() {
|
|
|
|
trace!("got entry");
|
|
|
|
assert_eq!(entry.transactions.len(), transactions.len());
|
|
|
|
assert_eq!(bank.get_balance(&pubkey), 1);
|
|
|
|
done = true;
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
|
|
|
if done {
|
|
|
|
break;
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
|
|
|
}
|
2019-03-29 20:00:36 -07:00
|
|
|
trace!("done ticking");
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2021-05-19 07:31:47 -07:00
|
|
|
assert!(done);
|
2019-02-26 10:48:18 -08:00
|
|
|
|
2021-10-27 10:09:16 -07:00
|
|
|
let transactions = sanitize_transactions(vec![system_transaction::transfer(
|
2019-03-29 20:00:36 -07:00
|
|
|
&mint_keypair,
|
|
|
|
&pubkey,
|
|
|
|
2,
|
2019-11-08 20:56:57 -08:00
|
|
|
genesis_config.hash(),
|
2021-10-27 10:09:16 -07:00
|
|
|
)]);
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-02-03 00:56:36 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-02-03 00:56:36 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
commit_transactions_result,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
assert_eq!(transactions_attempted_execution_count, 1);
|
|
|
|
// Transactions was still executed, just wasn't committed, so should be counted here.
|
|
|
|
assert_eq!(executed_transactions_count, 1);
|
|
|
|
assert_eq!(executed_with_successful_result_count, 1);
|
|
|
|
assert_eq!(retryable_transaction_indexes, vec![0]);
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_matches!(
|
2022-02-03 00:56:36 -08:00
|
|
|
commit_transactions_result,
|
2020-01-02 19:50:43 -08:00
|
|
|
Err(PohRecorderError::MaxHeightReached)
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-16 14:02:21 -08:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(bank.get_balance(&pubkey), 1);
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2019-02-16 14:02:21 -08:00
|
|
|
}
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2022-04-21 06:06:26 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_process_and_record_transactions_all_unexecuted() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(10_000);
|
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
|
|
|
|
let transactions = {
|
|
|
|
let mut tx =
|
|
|
|
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash());
|
|
|
|
// Add duplicate account key
|
|
|
|
tx.message.account_keys.push(pubkey);
|
|
|
|
sanitize_transactions(vec![tx])
|
|
|
|
};
|
|
|
|
|
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
|
|
|
{
|
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
|
|
|
bank.clone(),
|
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&pubkey,
|
|
|
|
&Arc::new(blockstore),
|
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
Arc::new(AtomicBool::default()),
|
|
|
|
);
|
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2022-04-21 06:06:26 -07:00
|
|
|
|
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2022-04-21 06:06:26 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-04-21 06:06:26 -07:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-04-21 06:06:26 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
commit_transactions_result,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
|
|
|
|
assert_eq!(transactions_attempted_execution_count, 1);
|
|
|
|
assert_eq!(executed_transactions_count, 0);
|
|
|
|
assert_eq!(executed_with_successful_result_count, 0);
|
|
|
|
assert!(retryable_transaction_indexes.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
commit_transactions_result.ok(),
|
|
|
|
Some(vec![CommitTransactionDetails::NotCommitted; 1])
|
|
|
|
);
|
|
|
|
|
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2022-04-21 06:06:26 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
|
|
|
let _ = poh_simulator.join();
|
|
|
|
}
|
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
|
|
|
}
|
|
|
|
|
2022-04-08 06:35:16 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_process_and_record_transactions_cost_tracker() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(10_000);
|
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
|
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
|
|
|
{
|
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
|
|
|
bank.clone(),
|
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&pubkey,
|
|
|
|
&Arc::new(blockstore),
|
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
Arc::new(AtomicBool::default()),
|
|
|
|
);
|
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2022-04-08 06:35:16 -07:00
|
|
|
|
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2022-04-08 06:35:16 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
let qos_service = QosService::new(Arc::new(RwLock::new(CostModel::default())), 1);
|
|
|
|
|
|
|
|
let get_block_cost = || bank.read_cost_tracker().unwrap().block_cost();
|
|
|
|
let get_tx_count = || bank.read_cost_tracker().unwrap().transaction_count();
|
|
|
|
assert_eq!(get_block_cost(), 0);
|
|
|
|
assert_eq!(get_tx_count(), 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// TEST: cost tracker's block cost increases when successfully processing a tx
|
|
|
|
//
|
|
|
|
|
|
|
|
let transactions = sanitize_transactions(vec![system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&pubkey,
|
|
|
|
1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-04-08 06:35:16 -07:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&qos_service,
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-04-08 06:35:16 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
commit_transactions_result,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
assert_eq!(executed_with_successful_result_count, 1);
|
|
|
|
assert!(commit_transactions_result.is_ok());
|
|
|
|
|
|
|
|
let single_transfer_cost = get_block_cost();
|
|
|
|
assert_ne!(single_transfer_cost, 0);
|
|
|
|
assert_eq!(get_tx_count(), 1);
|
|
|
|
|
|
|
|
//
|
|
|
|
// TEST: When a tx in a batch can't be executed (here because of account
|
|
|
|
// locks), then its cost does not affect the cost tracker.
|
|
|
|
//
|
|
|
|
|
|
|
|
let allocate_keypair = Keypair::new();
|
|
|
|
let transactions = sanitize_transactions(vec![
|
|
|
|
system_transaction::transfer(&mint_keypair, &pubkey, 2, genesis_config.hash()),
|
|
|
|
// intentionally use a tx that has a different cost
|
|
|
|
system_transaction::allocate(
|
|
|
|
&mint_keypair,
|
|
|
|
&allocate_keypair,
|
|
|
|
genesis_config.hash(),
|
|
|
|
1,
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-04-08 06:35:16 -07:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&qos_service,
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-04-08 06:35:16 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
executed_with_successful_result_count,
|
|
|
|
commit_transactions_result,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
assert_eq!(executed_with_successful_result_count, 1);
|
|
|
|
assert!(commit_transactions_result.is_ok());
|
|
|
|
assert_eq!(retryable_transaction_indexes, vec![1]);
|
|
|
|
|
|
|
|
assert_eq!(get_block_cost(), 2 * single_transfer_cost);
|
|
|
|
assert_eq!(get_tx_count(), 2);
|
|
|
|
|
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2022-04-08 06:35:16 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
|
|
|
let _ = poh_simulator.join();
|
|
|
|
}
|
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
|
|
|
}
|
|
|
|
|
2021-03-23 07:10:04 -07:00
|
|
|
fn simulate_poh(
|
2021-04-14 10:07:21 -07:00
|
|
|
record_receiver: CrossbeamReceiver<Record>,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: &Arc<RwLock<PohRecorder>>,
|
2021-04-14 10:07:21 -07:00
|
|
|
) -> JoinHandle<()> {
|
2021-03-23 07:10:04 -07:00
|
|
|
let poh_recorder = poh_recorder.clone();
|
2022-07-05 07:29:44 -07:00
|
|
|
let is_exited = poh_recorder.read().unwrap().is_exited.clone();
|
2021-03-23 07:10:04 -07:00
|
|
|
let tick_producer = Builder::new()
|
|
|
|
.name("solana-simulate_poh".to_string())
|
|
|
|
.spawn(move || loop {
|
|
|
|
PohService::read_record_receiver_and_process(
|
|
|
|
&poh_recorder,
|
|
|
|
&record_receiver,
|
|
|
|
Duration::from_millis(10),
|
|
|
|
);
|
2021-04-14 10:07:21 -07:00
|
|
|
if is_exited.load(Ordering::Relaxed) {
|
2021-03-23 07:10:04 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2021-04-14 10:07:21 -07:00
|
|
|
tick_producer.unwrap()
|
2021-03-23 07:10:04 -07:00
|
|
|
}
|
|
|
|
|
2019-05-07 10:23:02 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_process_and_record_transactions_account_in_use() {
|
|
|
|
solana_logger::setup();
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2021-03-24 14:05:43 -07:00
|
|
|
} = create_slow_genesis_config(10_000);
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
let pubkey1 = solana_sdk::pubkey::new_rand();
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2021-10-27 10:09:16 -07:00
|
|
|
let transactions = sanitize_transactions(vec![
|
|
|
|
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash()),
|
|
|
|
system_transaction::transfer(&mint_keypair, &pubkey1, 1, genesis_config.hash()),
|
|
|
|
]);
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-05-07 10:23:02 -07:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
2019-05-07 10:23:02 -07:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-05-07 10:23:02 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-05-07 10:23:02 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
Arc::new(AtomicBool::default()),
|
2019-05-07 10:23:02 -07:00
|
|
|
);
|
2021-03-23 07:10:04 -07:00
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2019-05-07 10:23:02 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let process_transactions_batch_output = BankingStage::process_and_record_transactions(
|
2019-05-07 10:23:02 -07:00
|
|
|
&bank,
|
|
|
|
&transactions,
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2019-05-07 10:23:02 -07:00
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2020-08-07 11:21:35 -07:00
|
|
|
&gossip_vote_sender,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2019-05-07 10:23:02 -07:00
|
|
|
);
|
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ExecuteAndCommitTransactionsOutput {
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
executed_transactions_count,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
commit_transactions_result,
|
|
|
|
..
|
|
|
|
} = process_transactions_batch_output.execute_and_commit_transactions_output;
|
|
|
|
|
|
|
|
assert_eq!(transactions_attempted_execution_count, 2);
|
|
|
|
assert_eq!(executed_transactions_count, 1);
|
|
|
|
assert_eq!(retryable_transaction_indexes, vec![1],);
|
|
|
|
assert!(commit_transactions_result.is_ok());
|
2019-05-07 10:23:02 -07:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2019-05-07 10:23:02 -07:00
|
|
|
}
|
2019-05-10 14:28:38 -07:00
|
|
|
|
2019-06-26 22:39:50 -07:00
|
|
|
#[test]
|
|
|
|
fn test_process_transactions_returns_unprocessed_txs() {
|
|
|
|
solana_logger::setup();
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-06-26 22:39:50 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2021-03-24 14:05:43 -07:00
|
|
|
} = create_slow_genesis_config(10_000);
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2021-10-27 10:09:16 -07:00
|
|
|
let transactions = sanitize_transactions(vec![system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&pubkey,
|
|
|
|
1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
)]);
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-06-26 22:39:50 -07:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
2019-06-26 22:39:50 -07:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-06-26 22:39:50 -07:00
|
|
|
bank.ticks_per_slot(),
|
2020-10-19 12:12:08 -07:00
|
|
|
&solana_sdk::pubkey::new_rand(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-06-26 22:39:50 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
Arc::new(AtomicBool::default()),
|
2019-06-26 22:39:50 -07:00
|
|
|
);
|
|
|
|
|
2021-03-23 07:10:04 -07:00
|
|
|
// Poh Recorder has no working bank, so should throw MaxHeightReached error on
|
2019-06-26 22:39:50 -07:00
|
|
|
// record
|
2021-03-23 07:10:04 -07:00
|
|
|
let recorder = poh_recorder.recorder();
|
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &Arc::new(RwLock::new(poh_recorder)));
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let process_transactions_summary = BankingStage::process_transactions(
|
|
|
|
&bank,
|
|
|
|
&Instant::now(),
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-02-03 00:56:36 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-02-03 00:56:36 -08:00
|
|
|
);
|
2019-06-26 22:39:50 -07:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ProcessTransactionsSummary {
|
|
|
|
reached_max_poh_height,
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
committed_transactions_count,
|
|
|
|
committed_transactions_with_successful_result_count,
|
|
|
|
failed_commit_count,
|
|
|
|
mut retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = process_transactions_summary;
|
|
|
|
assert!(reached_max_poh_height);
|
|
|
|
assert_eq!(transactions_attempted_execution_count, 1);
|
|
|
|
assert_eq!(failed_commit_count, 1);
|
|
|
|
// MaxHeightReached error does not commit, should be zero here
|
|
|
|
assert_eq!(committed_transactions_count, 0);
|
|
|
|
assert_eq!(committed_transactions_with_successful_result_count, 0);
|
|
|
|
|
|
|
|
retryable_transaction_indexes.sort_unstable();
|
2019-06-26 22:39:50 -07:00
|
|
|
let expected: Vec<usize> = (0..transactions.len()).collect();
|
2022-02-03 00:56:36 -08:00
|
|
|
assert_eq!(retryable_transaction_indexes, expected);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
recorder.is_exited.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
2019-06-26 22:39:50 -07:00
|
|
|
}
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn execute_transactions_with_dummy_poh_service(
|
|
|
|
bank: Arc<Bank>,
|
|
|
|
transactions: Vec<Transaction>,
|
|
|
|
) -> ProcessTransactionsSummary {
|
|
|
|
let transactions = sanitize_transactions(transactions);
|
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
|
|
|
bank.clone(),
|
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
&Arc::new(blockstore),
|
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
Arc::new(AtomicBool::default()),
|
|
|
|
);
|
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2022-02-03 00:56:36 -08:00
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
|
|
|
|
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
let process_transactions_summary = BankingStage::process_transactions(
|
|
|
|
&bank,
|
|
|
|
&Instant::now(),
|
|
|
|
&transactions,
|
|
|
|
&recorder,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2022-02-03 00:56:36 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-02-03 00:56:36 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2022-02-03 00:56:36 -08:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
|
|
|
let _ = poh_simulator.join();
|
|
|
|
|
|
|
|
process_transactions_summary
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_process_transactions_instruction_error() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let lamports = 10_000;
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(lamports);
|
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2022-03-14 07:58:10 -07:00
|
|
|
// set cost tracker limits to MAX so it will not filter out TXs
|
|
|
|
bank.write_cost_tracker()
|
|
|
|
.unwrap()
|
|
|
|
.set_limits(std::u64::MAX, std::u64::MAX, std::u64::MAX);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
// Transfer more than the balance of the mint keypair, should cause a
|
|
|
|
// InstructionError::InsufficientFunds that is then committed. Needs to be
|
|
|
|
// MAX_NUM_TRANSACTIONS_PER_BATCH at least so it doesn't conflict on account locks
|
|
|
|
// with the below transaction
|
|
|
|
let mut transactions = vec![
|
|
|
|
system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
lamports + 1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
);
|
|
|
|
MAX_NUM_TRANSACTIONS_PER_BATCH
|
|
|
|
];
|
|
|
|
|
|
|
|
// Make one transaction that will succeed.
|
|
|
|
transactions.push(system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
));
|
|
|
|
|
|
|
|
let transactions_count = transactions.len();
|
|
|
|
let ProcessTransactionsSummary {
|
|
|
|
reached_max_poh_height,
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
committed_transactions_count,
|
|
|
|
committed_transactions_with_successful_result_count,
|
|
|
|
failed_commit_count,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = execute_transactions_with_dummy_poh_service(bank, transactions);
|
|
|
|
|
|
|
|
// All the transactions should have been replayed, but only 1 committed
|
|
|
|
assert!(!reached_max_poh_height);
|
|
|
|
assert_eq!(transactions_attempted_execution_count, transactions_count);
|
|
|
|
// Both transactions should have been committed, even though one was an error,
|
|
|
|
// because InstructionErrors are committed
|
|
|
|
assert_eq!(committed_transactions_count, 2);
|
|
|
|
assert_eq!(committed_transactions_with_successful_result_count, 1);
|
|
|
|
assert_eq!(failed_commit_count, 0);
|
|
|
|
assert_eq!(
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
(1..transactions_count - 1).collect::<Vec<usize>>()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_process_transactions_account_in_use() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(10_000);
|
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2022-03-14 07:58:10 -07:00
|
|
|
// set cost tracker limits to MAX so it will not filter out TXs
|
|
|
|
bank.write_cost_tracker()
|
|
|
|
.unwrap()
|
|
|
|
.set_limits(std::u64::MAX, std::u64::MAX, std::u64::MAX);
|
2022-02-03 00:56:36 -08:00
|
|
|
|
|
|
|
// Make all repetitive transactions that conflict on the `mint_keypair`, so only 1 should be executed
|
|
|
|
let mut transactions = vec![
|
|
|
|
system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
1,
|
|
|
|
genesis_config.hash()
|
|
|
|
);
|
|
|
|
MAX_NUM_TRANSACTIONS_PER_BATCH
|
|
|
|
];
|
|
|
|
|
|
|
|
// Make one more in separate batch that also conflicts, but because it's in a separate batch, it
|
|
|
|
// should be executed
|
|
|
|
transactions.push(system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
1,
|
|
|
|
genesis_config.hash(),
|
|
|
|
));
|
|
|
|
|
|
|
|
let transactions_count = transactions.len();
|
|
|
|
let ProcessTransactionsSummary {
|
|
|
|
reached_max_poh_height,
|
|
|
|
transactions_attempted_execution_count,
|
|
|
|
committed_transactions_count,
|
|
|
|
committed_transactions_with_successful_result_count,
|
|
|
|
failed_commit_count,
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
..
|
|
|
|
} = execute_transactions_with_dummy_poh_service(bank, transactions);
|
|
|
|
|
|
|
|
// All the transactions should have been replayed, but only 2 committed (first and last)
|
|
|
|
assert!(!reached_max_poh_height);
|
|
|
|
assert_eq!(transactions_attempted_execution_count, transactions_count);
|
|
|
|
assert_eq!(committed_transactions_count, 2);
|
|
|
|
assert_eq!(committed_transactions_with_successful_result_count, 2);
|
|
|
|
assert_eq!(failed_commit_count, 0,);
|
|
|
|
|
|
|
|
// Everything except first and last index of the transactions failed and are last retryable
|
|
|
|
assert_eq!(
|
|
|
|
retryable_transaction_indexes,
|
|
|
|
(1..transactions_count - 1).collect::<Vec<usize>>()
|
|
|
|
);
|
2019-06-26 22:39:50 -07:00
|
|
|
}
|
2019-11-20 15:43:10 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_persist_transaction_status() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
2022-01-11 10:32:25 -08:00
|
|
|
mut genesis_config,
|
2019-11-20 15:43:10 -08:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2022-01-11 10:32:25 -08:00
|
|
|
} = create_slow_genesis_config(solana_sdk::native_token::sol_to_lamports(1000.0));
|
|
|
|
genesis_config.rent.lamports_per_byte_year = 50;
|
|
|
|
genesis_config.rent.exemption_threshold = 2.0;
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
|
|
|
let pubkey1 = solana_sdk::pubkey::new_rand();
|
2019-11-20 15:43:10 -08:00
|
|
|
let keypair1 = Keypair::new();
|
|
|
|
|
2022-01-11 10:32:25 -08:00
|
|
|
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
|
|
|
|
|
|
|
|
let success_tx = system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&pubkey,
|
|
|
|
rent_exempt_amount,
|
|
|
|
genesis_config.hash(),
|
|
|
|
);
|
2019-11-20 15:43:10 -08:00
|
|
|
let success_signature = success_tx.signatures[0];
|
|
|
|
let entry_1 = next_entry(&genesis_config.hash(), 1, vec![success_tx.clone()]);
|
2022-01-11 10:32:25 -08:00
|
|
|
let ix_error_tx = system_transaction::transfer(
|
|
|
|
&keypair1,
|
|
|
|
&pubkey1,
|
|
|
|
2 * rent_exempt_amount,
|
|
|
|
genesis_config.hash(),
|
|
|
|
);
|
2019-11-20 15:43:10 -08:00
|
|
|
let ix_error_signature = ix_error_tx.signatures[0];
|
|
|
|
let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx.clone()]);
|
2022-02-09 21:28:18 -08:00
|
|
|
let entries = vec![entry_1, entry_2];
|
2019-11-20 15:43:10 -08:00
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
let transactions = sanitize_transactions(vec![success_tx, ix_error_tx]);
|
2022-01-11 10:32:25 -08:00
|
|
|
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair1.pubkey())
|
|
|
|
.unwrap();
|
2019-11-20 15:43:10 -08:00
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2019-11-20 15:43:10 -08:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2020-01-13 13:13:52 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let blockstore = Arc::new(blockstore);
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
2019-11-20 15:43:10 -08:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2019-11-20 15:43:10 -08:00
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
&blockstore,
|
2019-11-20 15:43:10 -08:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
Arc::new(AtomicBool::default()),
|
2019-11-20 15:43:10 -08:00
|
|
|
);
|
2021-03-23 07:10:04 -07:00
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2019-11-20 15:43:10 -08:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2019-11-20 15:43:10 -08:00
|
|
|
|
2022-09-15 14:51:41 -07:00
|
|
|
let shreds = entries_to_test_shreds(
|
|
|
|
&entries,
|
|
|
|
bank.slot(),
|
|
|
|
0, // parent_slot
|
|
|
|
true, // is_full_slot
|
|
|
|
0, // version
|
|
|
|
true, // merkle_variant
|
|
|
|
);
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
2021-07-01 20:02:40 -07:00
|
|
|
blockstore.set_roots(std::iter::once(&bank.slot())).unwrap();
|
2019-11-20 15:43:10 -08:00
|
|
|
|
2019-11-21 13:23:40 -08:00
|
|
|
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
2019-11-20 15:43:10 -08:00
|
|
|
let transaction_status_service = TransactionStatusService::new(
|
|
|
|
transaction_status_receiver,
|
2021-03-26 15:47:35 -07:00
|
|
|
Arc::new(AtomicU64::default()),
|
2021-11-23 09:55:53 -08:00
|
|
|
true,
|
|
|
|
None,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore.clone(),
|
2022-02-11 20:29:07 -08:00
|
|
|
false,
|
2019-11-20 15:43:10 -08:00
|
|
|
&Arc::new(AtomicBool::new(false)),
|
|
|
|
);
|
|
|
|
|
2020-08-07 11:21:35 -07:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
2019-11-20 15:43:10 -08:00
|
|
|
let _ = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&transactions,
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2019-11-20 15:43:10 -08:00
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&Some(TransactionStatusSender {
|
2021-02-01 13:00:51 -08:00
|
|
|
sender: transaction_status_sender,
|
|
|
|
}),
|
2020-08-07 11:21:35 -07:00
|
|
|
&gossip_vote_sender,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2019-11-20 15:43:10 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
transaction_status_service.join().unwrap();
|
|
|
|
|
2021-03-26 15:47:35 -07:00
|
|
|
let confirmed_block = blockstore.get_rooted_block(bank.slot(), false).unwrap();
|
2022-02-09 21:28:18 -08:00
|
|
|
let actual_tx_results: Vec<_> = confirmed_block
|
|
|
|
.transactions
|
|
|
|
.into_iter()
|
|
|
|
.map(|VersionedTransactionWithStatusMeta { transaction, meta }| {
|
|
|
|
(transaction.signatures[0], meta.status)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let expected_tx_results = vec![
|
|
|
|
(success_signature, Ok(())),
|
|
|
|
(
|
|
|
|
ix_error_signature,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
|
|
|
InstructionError::Custom(1),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
assert_eq!(actual_tx_results, expected_tx_results);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
2019-11-20 15:43:10 -08:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2019-11-20 15:43:10 -08:00
|
|
|
}
|
2021-02-12 03:27:37 -08:00
|
|
|
|
2022-01-13 23:24:41 -08:00
|
|
|
fn generate_new_address_lookup_table(
|
|
|
|
authority: Option<Pubkey>,
|
|
|
|
num_addresses: usize,
|
|
|
|
) -> AddressLookupTable<'static> {
|
|
|
|
let mut addresses = Vec::with_capacity(num_addresses);
|
|
|
|
addresses.resize_with(num_addresses, Pubkey::new_unique);
|
|
|
|
AddressLookupTable {
|
|
|
|
meta: LookupTableMeta {
|
|
|
|
authority,
|
|
|
|
..LookupTableMeta::default()
|
|
|
|
},
|
|
|
|
addresses: Cow::Owned(addresses),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn store_address_lookup_table(
|
|
|
|
bank: &Bank,
|
|
|
|
account_address: Pubkey,
|
|
|
|
address_lookup_table: AddressLookupTable<'static>,
|
|
|
|
) -> AccountSharedData {
|
2022-03-07 23:20:34 -08:00
|
|
|
let data = address_lookup_table.serialize_for_tests().unwrap();
|
2022-01-13 23:24:41 -08:00
|
|
|
let mut account =
|
|
|
|
AccountSharedData::new(1, data.len(), &solana_address_lookup_table_program::id());
|
|
|
|
account.set_data(data);
|
|
|
|
bank.store_account(&account_address, &account);
|
|
|
|
|
|
|
|
account
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_write_persist_loaded_addresses() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(10_000);
|
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(&genesis_config));
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
|
|
|
|
let address_table_key = Pubkey::new_unique();
|
|
|
|
let address_table_state = generate_new_address_lookup_table(None, 2);
|
|
|
|
store_address_lookup_table(&bank, address_table_key, address_table_state);
|
|
|
|
|
|
|
|
let bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::new_unique(), 1));
|
|
|
|
let message = VersionedMessage::V0(v0::Message {
|
|
|
|
header: MessageHeader {
|
|
|
|
num_required_signatures: 1,
|
|
|
|
num_readonly_signed_accounts: 0,
|
|
|
|
num_readonly_unsigned_accounts: 0,
|
|
|
|
},
|
|
|
|
recent_blockhash: genesis_config.hash(),
|
|
|
|
account_keys: vec![keypair.pubkey()],
|
|
|
|
address_table_lookups: vec![MessageAddressTableLookup {
|
|
|
|
account_key: address_table_key,
|
|
|
|
writable_indexes: vec![0],
|
|
|
|
readonly_indexes: vec![1],
|
|
|
|
}],
|
|
|
|
instructions: vec![],
|
|
|
|
});
|
|
|
|
|
|
|
|
let tx = VersionedTransaction::try_new(message, &[&keypair]).unwrap();
|
2022-03-14 21:02:22 -07:00
|
|
|
let sanitized_tx = SanitizedTransaction::try_create(
|
|
|
|
tx.clone(),
|
|
|
|
MessageHash::Compute,
|
|
|
|
Some(false),
|
|
|
|
bank.as_ref(),
|
2022-05-06 12:19:50 -07:00
|
|
|
true, // require_static_program_ids
|
2022-03-14 21:02:22 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2022-01-13 23:24:41 -08:00
|
|
|
|
|
|
|
let entry = next_versioned_entry(&genesis_config.hash(), 1, vec![tx]);
|
|
|
|
let entries = vec![entry];
|
|
|
|
|
|
|
|
bank.transfer(1, &mint_keypair, &keypair.pubkey()).unwrap();
|
|
|
|
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2022-01-13 23:24:41 -08:00
|
|
|
{
|
2022-02-03 00:56:36 -08:00
|
|
|
let blockstore = Blockstore::open(ledger_path.path())
|
2022-01-13 23:24:41 -08:00
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let blockstore = Arc::new(blockstore);
|
|
|
|
let (poh_recorder, _entry_receiver, record_receiver) = PohRecorder::new(
|
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
|
|
|
bank.clone(),
|
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::new_unique(),
|
|
|
|
&blockstore,
|
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
Arc::new(AtomicBool::default()),
|
|
|
|
);
|
|
|
|
let recorder = poh_recorder.recorder();
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2022-01-13 23:24:41 -08:00
|
|
|
|
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
|
|
|
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2022-01-13 23:24:41 -08:00
|
|
|
|
2022-09-15 14:51:41 -07:00
|
|
|
let shreds = entries_to_test_shreds(
|
|
|
|
&entries,
|
|
|
|
bank.slot(),
|
|
|
|
0, // parent_slot
|
|
|
|
true, // is_full_slot
|
|
|
|
0, // version
|
|
|
|
true, // merkle_variant
|
|
|
|
);
|
2022-01-13 23:24:41 -08:00
|
|
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
blockstore.set_roots(std::iter::once(&bank.slot())).unwrap();
|
|
|
|
|
|
|
|
let (transaction_status_sender, transaction_status_receiver) = unbounded();
|
|
|
|
let transaction_status_service = TransactionStatusService::new(
|
|
|
|
transaction_status_receiver,
|
|
|
|
Arc::new(AtomicU64::default()),
|
|
|
|
true,
|
|
|
|
None,
|
|
|
|
blockstore.clone(),
|
2022-02-11 20:29:07 -08:00
|
|
|
false,
|
2022-01-13 23:24:41 -08:00
|
|
|
&Arc::new(AtomicBool::new(false)),
|
|
|
|
);
|
|
|
|
|
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
let _ = BankingStage::process_and_record_transactions(
|
|
|
|
&bank,
|
|
|
|
&[sanitized_tx.clone()],
|
|
|
|
&recorder,
|
|
|
|
0,
|
2022-10-20 14:10:48 -07:00
|
|
|
&Some(TransactionStatusSender {
|
2022-01-13 23:24:41 -08:00
|
|
|
sender: transaction_status_sender,
|
|
|
|
}),
|
|
|
|
&gossip_vote_sender,
|
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2022-01-13 23:24:41 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
transaction_status_service.join().unwrap();
|
|
|
|
|
|
|
|
let mut confirmed_block = blockstore.get_rooted_block(bank.slot(), false).unwrap();
|
|
|
|
assert_eq!(confirmed_block.transactions.len(), 1);
|
|
|
|
|
|
|
|
let recorded_meta = confirmed_block.transactions.pop().unwrap().meta;
|
|
|
|
assert_eq!(
|
|
|
|
recorded_meta,
|
2022-02-09 21:28:18 -08:00
|
|
|
TransactionStatusMeta {
|
2022-01-13 23:24:41 -08:00
|
|
|
status: Ok(()),
|
|
|
|
pre_balances: vec![1, 0, 0],
|
|
|
|
post_balances: vec![1, 0, 0],
|
|
|
|
pre_token_balances: Some(vec![]),
|
|
|
|
post_token_balances: Some(vec![]),
|
|
|
|
rewards: Some(vec![]),
|
|
|
|
loaded_addresses: sanitized_tx.get_loaded_addresses(),
|
2022-08-06 10:14:31 -07:00
|
|
|
compute_units_consumed: Some(0),
|
2022-01-13 23:24:41 -08:00
|
|
|
..TransactionStatusMeta::default()
|
2022-02-09 21:28:18 -08:00
|
|
|
}
|
2022-01-13 23:24:41 -08:00
|
|
|
);
|
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2022-01-13 23:24:41 -08:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
|
|
|
let _ = poh_simulator.join();
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2022-01-13 23:24:41 -08:00
|
|
|
}
|
|
|
|
|
2021-03-23 07:10:04 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-02-12 03:27:37 -08:00
|
|
|
fn setup_conflicting_transactions(
|
|
|
|
ledger_path: &Path,
|
|
|
|
) -> (
|
|
|
|
Vec<Transaction>,
|
|
|
|
Arc<Bank>,
|
2022-07-05 07:29:44 -07:00
|
|
|
Arc<RwLock<PohRecorder>>,
|
2021-02-12 03:27:37 -08:00
|
|
|
Receiver<WorkingBankEntry>,
|
2021-03-23 07:10:04 -07:00
|
|
|
JoinHandle<()>,
|
2021-02-12 03:27:37 -08:00
|
|
|
) {
|
2021-06-18 06:34:46 -07:00
|
|
|
Blockstore::destroy(ledger_path).unwrap();
|
2021-03-24 14:05:43 -07:00
|
|
|
let genesis_config_info = create_slow_genesis_config(10_000);
|
2021-02-12 03:27:37 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = &genesis_config_info;
|
|
|
|
let blockstore =
|
2021-06-18 06:34:46 -07:00
|
|
|
Blockstore::open(ledger_path).expect("Expected to be able to open database ledger");
|
2021-08-05 12:50:25 -07:00
|
|
|
let bank = Arc::new(Bank::new_no_wallclock_throttle_for_tests(genesis_config));
|
2021-04-14 10:07:21 -07:00
|
|
|
let exit = Arc::new(AtomicBool::default());
|
2021-03-23 07:10:04 -07:00
|
|
|
let (poh_recorder, entry_receiver, record_receiver) = PohRecorder::new(
|
2021-02-12 03:27:37 -08:00
|
|
|
bank.tick_height(),
|
|
|
|
bank.last_blockhash(),
|
2021-09-13 16:55:35 -07:00
|
|
|
bank.clone(),
|
2021-02-12 03:27:37 -08:00
|
|
|
Some((4, 4)),
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&solana_sdk::pubkey::new_rand(),
|
|
|
|
&Arc::new(blockstore),
|
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
2021-04-14 10:07:21 -07:00
|
|
|
exit,
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
2022-07-05 07:29:44 -07:00
|
|
|
let poh_recorder = Arc::new(RwLock::new(poh_recorder));
|
2021-02-12 03:27:37 -08:00
|
|
|
|
|
|
|
// Set up unparallelizable conflicting transactions
|
|
|
|
let pubkey0 = solana_sdk::pubkey::new_rand();
|
|
|
|
let pubkey1 = solana_sdk::pubkey::new_rand();
|
|
|
|
let pubkey2 = solana_sdk::pubkey::new_rand();
|
|
|
|
let transactions = vec![
|
2021-06-18 06:34:46 -07:00
|
|
|
system_transaction::transfer(mint_keypair, &pubkey0, 1, genesis_config.hash()),
|
|
|
|
system_transaction::transfer(mint_keypair, &pubkey1, 1, genesis_config.hash()),
|
|
|
|
system_transaction::transfer(mint_keypair, &pubkey2, 1, genesis_config.hash()),
|
2021-02-12 03:27:37 -08:00
|
|
|
];
|
2021-04-14 10:07:21 -07:00
|
|
|
let poh_simulator = simulate_poh(record_receiver, &poh_recorder);
|
2021-03-23 07:10:04 -07:00
|
|
|
|
|
|
|
(
|
|
|
|
transactions,
|
|
|
|
bank,
|
|
|
|
poh_recorder,
|
|
|
|
entry_receiver,
|
|
|
|
poh_simulator,
|
|
|
|
)
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_consume_buffered_packets() {
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2021-02-12 03:27:37 -08:00
|
|
|
{
|
2021-04-14 10:07:21 -07:00
|
|
|
let (transactions, bank, poh_recorder, _entry_receiver, poh_simulator) =
|
2022-02-03 00:56:36 -08:00
|
|
|
setup_conflicting_transactions(ledger_path.path());
|
2022-07-05 07:29:44 -07:00
|
|
|
let recorder = poh_recorder.read().unwrap().recorder();
|
2021-02-12 03:27:37 -08:00
|
|
|
let num_conflicting_transactions = transactions.len();
|
2022-05-04 19:50:56 -07:00
|
|
|
let deserialized_packets =
|
|
|
|
unprocessed_packet_batches::transactions_to_deserialized_packets(&transactions)
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(deserialized_packets.len(), num_conflicting_transactions);
|
2022-10-20 14:10:48 -07:00
|
|
|
let mut buffered_packet_batches =
|
|
|
|
UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
UnprocessedPacketBatches::from_iter(
|
|
|
|
deserialized_packets.into_iter(),
|
|
|
|
num_conflicting_transactions,
|
|
|
|
),
|
|
|
|
ThreadType::Transactions,
|
2022-05-04 19:50:56 -07:00
|
|
|
);
|
2021-02-12 03:27:37 -08:00
|
|
|
|
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
// When the working bank in poh_recorder is None, no packets should be processed
|
2022-07-05 07:29:44 -07:00
|
|
|
assert!(!poh_recorder.read().unwrap().has_bank());
|
2021-03-15 17:11:15 -07:00
|
|
|
let max_tx_processing_ns = std::u128::MAX;
|
2021-02-12 03:27:37 -08:00
|
|
|
BankingStage::consume_buffered_packets(
|
|
|
|
&Pubkey::default(),
|
2021-03-15 17:11:15 -07:00
|
|
|
max_tx_processing_ns,
|
2021-02-12 03:27:37 -08:00
|
|
|
&poh_recorder,
|
2021-12-11 06:44:15 -08:00
|
|
|
&mut buffered_packet_batches,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2021-02-12 03:27:37 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
None::<Box<dyn Fn()>>,
|
2021-04-12 23:28:08 -07:00
|
|
|
&BankingStageStats::default(),
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-02-11 00:07:45 -08:00
|
|
|
&mut LeaderSlotMetricsTracker::new(0),
|
2022-05-04 19:50:56 -07:00
|
|
|
num_conflicting_transactions,
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
assert_eq!(buffered_packet_batches.len(), num_conflicting_transactions);
|
2021-02-12 03:27:37 -08:00
|
|
|
// When the poh recorder has a bank, should process all non conflicting buffered packets.
|
|
|
|
// Processes one packet per iteration of the loop
|
2022-05-04 19:50:56 -07:00
|
|
|
let num_packets_to_process_per_iteration = num_conflicting_transactions;
|
2021-02-12 03:27:37 -08:00
|
|
|
for num_expected_unprocessed in (0..num_conflicting_transactions).rev() {
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2021-02-12 03:27:37 -08:00
|
|
|
BankingStage::consume_buffered_packets(
|
|
|
|
&Pubkey::default(),
|
2021-03-15 17:11:15 -07:00
|
|
|
max_tx_processing_ns,
|
2021-02-12 03:27:37 -08:00
|
|
|
&poh_recorder,
|
2021-12-11 06:44:15 -08:00
|
|
|
&mut buffered_packet_batches,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2021-02-12 03:27:37 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
None::<Box<dyn Fn()>>,
|
2021-04-12 23:28:08 -07:00
|
|
|
&BankingStageStats::default(),
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-02-11 00:07:45 -08:00
|
|
|
&mut LeaderSlotMetricsTracker::new(0),
|
2022-05-04 19:50:56 -07:00
|
|
|
num_packets_to_process_per_iteration,
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
|
|
|
if num_expected_unprocessed == 0 {
|
2021-12-11 06:44:15 -08:00
|
|
|
assert!(buffered_packet_batches.is_empty())
|
2021-02-12 03:27:37 -08:00
|
|
|
} else {
|
2022-05-04 19:50:56 -07:00
|
|
|
assert_eq!(buffered_packet_batches.len(), num_expected_unprocessed);
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
}
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_consume_buffered_packets_interrupted() {
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2021-02-12 03:27:37 -08:00
|
|
|
{
|
|
|
|
let (continue_sender, continue_receiver) = unbounded();
|
|
|
|
let (finished_packet_sender, finished_packet_receiver) = unbounded();
|
2022-05-04 19:50:56 -07:00
|
|
|
let (transactions, bank, poh_recorder, _entry_receiver, poh_simulator) =
|
|
|
|
setup_conflicting_transactions(ledger_path.path());
|
2021-02-12 03:27:37 -08:00
|
|
|
|
|
|
|
let test_fn = Some(move || {
|
|
|
|
finished_packet_sender.send(()).unwrap();
|
|
|
|
continue_receiver.recv().unwrap();
|
|
|
|
});
|
|
|
|
// When the poh recorder has a bank, it should process all non conflicting buffered packets.
|
2021-12-11 06:44:15 -08:00
|
|
|
// Because each conflicting transaction is in it's own `Packet` within a `PacketBatch`, then
|
|
|
|
// each iteration of this loop will process one element of the batch per iteration of the
|
2021-02-12 03:27:37 -08:00
|
|
|
// loop.
|
|
|
|
let interrupted_iteration = 1;
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder.write().unwrap().set_bank(&bank, false);
|
2021-02-12 03:27:37 -08:00
|
|
|
let poh_recorder_ = poh_recorder.clone();
|
2022-07-05 07:29:44 -07:00
|
|
|
let recorder = poh_recorder_.read().unwrap().recorder();
|
2021-02-12 03:27:37 -08:00
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
|
|
|
// Start up thread to process the banks
|
|
|
|
let t_consume = Builder::new()
|
|
|
|
.name("consume-buffered-packets".to_string())
|
|
|
|
.spawn(move || {
|
2022-05-04 19:50:56 -07:00
|
|
|
let num_conflicting_transactions = transactions.len();
|
|
|
|
let deserialized_packets =
|
|
|
|
unprocessed_packet_batches::transactions_to_deserialized_packets(
|
|
|
|
&transactions,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(deserialized_packets.len(), num_conflicting_transactions);
|
|
|
|
let num_packets_to_process_per_iteration = 1;
|
2022-10-20 14:10:48 -07:00
|
|
|
let mut buffered_packet_batches =
|
|
|
|
UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
UnprocessedPacketBatches::from_iter(
|
|
|
|
deserialized_packets.clone().into_iter(),
|
|
|
|
num_conflicting_transactions,
|
|
|
|
),
|
|
|
|
ThreadType::Transactions,
|
2022-05-04 19:50:56 -07:00
|
|
|
);
|
|
|
|
let all_packet_message_hashes: HashSet<Hash> = buffered_packet_batches
|
|
|
|
.iter()
|
|
|
|
.map(|packet| *packet.immutable_section().message_hash())
|
|
|
|
.collect();
|
2021-02-12 03:27:37 -08:00
|
|
|
BankingStage::consume_buffered_packets(
|
|
|
|
&Pubkey::default(),
|
2021-03-15 17:11:15 -07:00
|
|
|
std::u128::MAX,
|
2021-02-12 03:27:37 -08:00
|
|
|
&poh_recorder_,
|
2021-12-11 06:44:15 -08:00
|
|
|
&mut buffered_packet_batches,
|
2022-10-20 14:10:48 -07:00
|
|
|
&None,
|
2021-02-12 03:27:37 -08:00
|
|
|
&gossip_vote_sender,
|
|
|
|
test_fn,
|
2021-04-12 23:28:08 -07:00
|
|
|
&BankingStageStats::default(),
|
2021-03-23 07:10:04 -07:00
|
|
|
&recorder,
|
2021-12-22 13:39:59 -08:00
|
|
|
&QosService::new(Arc::new(RwLock::new(CostModel::default())), 1),
|
2022-02-11 00:07:45 -08:00
|
|
|
&mut LeaderSlotMetricsTracker::new(0),
|
2022-05-04 19:50:56 -07:00
|
|
|
num_packets_to_process_per_iteration,
|
2022-07-11 08:53:18 -07:00
|
|
|
None,
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Check everything is correct. All indexes after `interrupted_iteration`
|
|
|
|
// should still be unprocessed
|
|
|
|
assert_eq!(
|
2021-12-11 06:44:15 -08:00
|
|
|
buffered_packet_batches.len(),
|
2022-05-04 19:50:56 -07:00
|
|
|
deserialized_packets[interrupted_iteration + 1..].len()
|
2021-02-12 03:27:37 -08:00
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
for packet in buffered_packet_batches.iter() {
|
|
|
|
assert!(all_packet_message_hashes
|
|
|
|
.contains(packet.immutable_section().message_hash()));
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
for i in 0..=interrupted_iteration {
|
|
|
|
finished_packet_receiver.recv().unwrap();
|
|
|
|
if i == interrupted_iteration {
|
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.write()
|
2021-02-12 03:27:37 -08:00
|
|
|
.unwrap()
|
|
|
|
.schedule_dummy_max_height_reached_failure();
|
|
|
|
}
|
|
|
|
continue_sender.send(()).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
t_consume.join().unwrap();
|
2021-04-14 10:07:21 -07:00
|
|
|
poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-04-14 10:07:21 -07:00
|
|
|
.unwrap()
|
|
|
|
.is_exited
|
|
|
|
.store(true, Ordering::Relaxed);
|
2021-03-23 07:10:04 -07:00
|
|
|
let _ = poh_simulator.join();
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2021-02-12 03:27:37 -08:00
|
|
|
}
|
|
|
|
|
2021-09-21 08:49:41 -07:00
|
|
|
#[test]
|
2022-08-19 07:15:15 -07:00
|
|
|
#[ignore]
|
2021-09-21 08:49:41 -07:00
|
|
|
fn test_forwarder_budget() {
|
|
|
|
solana_logger::setup();
|
2021-12-11 06:44:15 -08:00
|
|
|
// Create `PacketBatch` with 1 unprocessed packet
|
2022-03-10 10:47:46 -08:00
|
|
|
let tx = system_transaction::transfer(
|
|
|
|
&Keypair::new(),
|
|
|
|
&solana_sdk::pubkey::new_rand(),
|
|
|
|
1,
|
|
|
|
Hash::new_unique(),
|
|
|
|
);
|
2022-11-09 11:39:38 -08:00
|
|
|
let packet = Packet::from_data(None, tx).unwrap();
|
2022-05-15 21:06:33 -07:00
|
|
|
let deserialized_packet = DeserializedPacket::new(packet).unwrap();
|
2021-09-21 08:49:41 -07:00
|
|
|
|
|
|
|
let genesis_config_info = create_slow_genesis_config(10_000);
|
2021-12-29 10:34:31 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
validator_pubkey,
|
|
|
|
..
|
|
|
|
} = &genesis_config_info;
|
2021-09-21 08:49:41 -07:00
|
|
|
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2021-09-21 08:49:41 -07:00
|
|
|
{
|
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2021-09-21 08:49:41 -07:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
|
|
|
);
|
|
|
|
let poh_config = PohConfig {
|
|
|
|
// limit tick count to avoid clearing working_bank at
|
|
|
|
// PohRecord then PohRecorderError(MaxHeightReached) at BankingStage
|
|
|
|
target_tick_count: Some(bank.max_tick_height() - 1),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let (exit, poh_recorder, poh_service, _entry_receiver) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
2021-09-21 08:49:41 -07:00
|
|
|
|
2021-12-29 10:34:31 -08:00
|
|
|
let local_node = Node::new_localhost_with_pubkey(validator_pubkey);
|
|
|
|
let cluster_info = new_test_cluster_info(local_node.info);
|
|
|
|
let recv_socket = &local_node.sockets.tpu_forwards[0];
|
|
|
|
|
|
|
|
let test_cases = vec![
|
|
|
|
("budget-restricted", DataBudget::restricted(), 0),
|
|
|
|
("budget-available", DataBudget::default(), 1),
|
|
|
|
];
|
|
|
|
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = ConnectionCache::default();
|
2022-06-21 05:56:11 -07:00
|
|
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2021-12-29 10:34:31 -08:00
|
|
|
for (name, data_budget, expected_num_forwarded) in test_cases {
|
2022-10-20 14:10:48 -07:00
|
|
|
let unprocessed_packet_batches: UnprocessedPacketBatches =
|
2022-05-04 19:50:56 -07:00
|
|
|
UnprocessedPacketBatches::from_iter(
|
|
|
|
vec![deserialized_packet.clone()].into_iter(),
|
|
|
|
1,
|
|
|
|
);
|
2022-06-02 11:14:58 -07:00
|
|
|
let stats = BankingStageStats::default();
|
2021-12-29 10:34:31 -08:00
|
|
|
BankingStage::handle_forwarding(
|
|
|
|
&cluster_info,
|
2022-10-20 14:10:48 -07:00
|
|
|
&mut UnprocessedTransactionStorage::new_transaction_storage(
|
|
|
|
unprocessed_packet_batches,
|
|
|
|
ThreadType::Transactions,
|
|
|
|
),
|
2021-12-29 10:34:31 -08:00
|
|
|
&poh_recorder,
|
2022-06-21 05:56:11 -07:00
|
|
|
&socket,
|
2021-12-29 10:34:31 -08:00
|
|
|
true,
|
|
|
|
&data_budget,
|
2022-02-11 00:07:45 -08:00
|
|
|
&mut LeaderSlotMetricsTracker::new(0),
|
2022-06-02 11:14:58 -07:00
|
|
|
&stats,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2022-06-08 22:25:37 -07:00
|
|
|
&mut TracerPacketStats::new(0),
|
2022-07-05 21:24:58 -07:00
|
|
|
&bank_forks,
|
2021-12-29 10:34:31 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
recv_socket
|
|
|
|
.set_nonblocking(expected_num_forwarded == 0)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let mut packets = vec![Packet::default(); 2];
|
2022-01-04 06:08:15 -08:00
|
|
|
let num_received = recv_mmsg(recv_socket, &mut packets[..]).unwrap_or_default();
|
2021-12-29 10:34:31 -08:00
|
|
|
assert_eq!(num_received, expected_num_forwarded, "{}", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2021-12-29 10:34:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-08-19 07:15:15 -07:00
|
|
|
#[ignore]
|
2021-12-29 10:34:31 -08:00
|
|
|
fn test_handle_forwarding() {
|
|
|
|
solana_logger::setup();
|
2022-03-10 10:47:46 -08:00
|
|
|
// packets are deserialized upon receiving, failed packets will not be
|
|
|
|
// forwarded; Therefore need to create real packets here.
|
|
|
|
let keypair = Keypair::new();
|
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2021-12-29 10:34:31 -08:00
|
|
|
|
2022-03-10 10:47:46 -08:00
|
|
|
let fwd_block_hash = Hash::new_unique();
|
2021-12-29 10:34:31 -08:00
|
|
|
let forwarded_packet = {
|
2022-03-10 10:47:46 -08:00
|
|
|
let transaction = system_transaction::transfer(&keypair, &pubkey, 1, fwd_block_hash);
|
2022-11-09 11:39:38 -08:00
|
|
|
let mut packet = Packet::from_data(None, transaction).unwrap();
|
2022-01-02 09:10:32 -08:00
|
|
|
packet.meta.flags |= PacketFlags::FORWARDED;
|
2022-05-15 21:06:33 -07:00
|
|
|
DeserializedPacket::new(packet).unwrap()
|
2021-12-29 10:34:31 -08:00
|
|
|
};
|
|
|
|
|
2022-03-10 10:47:46 -08:00
|
|
|
let normal_block_hash = Hash::new_unique();
|
|
|
|
let normal_packet = {
|
|
|
|
let transaction = system_transaction::transfer(&keypair, &pubkey, 1, normal_block_hash);
|
2022-11-09 11:39:38 -08:00
|
|
|
let packet = Packet::from_data(None, transaction).unwrap();
|
2022-05-15 21:06:33 -07:00
|
|
|
DeserializedPacket::new(packet).unwrap()
|
2022-03-10 10:47:46 -08:00
|
|
|
};
|
2021-12-29 10:34:31 -08:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let mut unprocessed_packet_batches = UnprocessedTransactionStorage::new_transaction_storage(
|
2022-05-04 19:50:56 -07:00
|
|
|
UnprocessedPacketBatches::from_iter(
|
|
|
|
vec![forwarded_packet, normal_packet].into_iter(),
|
|
|
|
2,
|
2022-10-20 14:10:48 -07:00
|
|
|
),
|
|
|
|
ThreadType::Transactions,
|
|
|
|
);
|
2021-12-29 10:34:31 -08:00
|
|
|
|
|
|
|
let genesis_config_info = create_slow_genesis_config(10_000);
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
validator_pubkey,
|
|
|
|
..
|
|
|
|
} = &genesis_config_info;
|
2022-07-05 21:24:58 -07:00
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
2022-02-03 00:56:36 -08:00
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
2021-12-29 10:34:31 -08:00
|
|
|
{
|
|
|
|
let blockstore = Arc::new(
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::open(ledger_path.path())
|
2021-12-29 10:34:31 -08:00
|
|
|
.expect("Expected to be able to open database ledger"),
|
2021-09-21 08:49:41 -07:00
|
|
|
);
|
2021-12-29 10:34:31 -08:00
|
|
|
let poh_config = PohConfig {
|
|
|
|
// limit tick count to avoid clearing working_bank at
|
|
|
|
// PohRecord then PohRecorderError(MaxHeightReached) at BankingStage
|
|
|
|
target_tick_count: Some(bank.max_tick_height() - 1),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let (exit, poh_recorder, poh_service, _entry_receiver) =
|
2022-02-07 18:28:28 -08:00
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
2021-12-29 10:34:31 -08:00
|
|
|
|
|
|
|
let local_node = Node::new_localhost_with_pubkey(validator_pubkey);
|
|
|
|
let cluster_info = new_test_cluster_info(local_node.info);
|
|
|
|
let recv_socket = &local_node.sockets.tpu_forwards[0];
|
2022-06-08 04:57:12 -07:00
|
|
|
let connection_cache = ConnectionCache::default();
|
2021-12-29 10:34:31 -08:00
|
|
|
|
|
|
|
let test_cases = vec![
|
2022-10-20 14:10:48 -07:00
|
|
|
("fwd-normal", true, vec![normal_block_hash], 2),
|
|
|
|
("fwd-no-op", true, vec![], 2),
|
|
|
|
("fwd-no-hold", false, vec![], 0),
|
2021-12-29 10:34:31 -08:00
|
|
|
];
|
|
|
|
|
2022-06-21 05:56:11 -07:00
|
|
|
let socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2022-10-20 14:10:48 -07:00
|
|
|
for (name, hold, expected_ids, expected_num_unprocessed) in test_cases {
|
2022-06-02 11:14:58 -07:00
|
|
|
let stats = BankingStageStats::default();
|
2021-12-29 10:34:31 -08:00
|
|
|
BankingStage::handle_forwarding(
|
|
|
|
&cluster_info,
|
|
|
|
&mut unprocessed_packet_batches,
|
|
|
|
&poh_recorder,
|
2022-06-21 05:56:11 -07:00
|
|
|
&socket,
|
2021-12-29 10:34:31 -08:00
|
|
|
hold,
|
|
|
|
&DataBudget::default(),
|
2022-02-11 00:07:45 -08:00
|
|
|
&mut LeaderSlotMetricsTracker::new(0),
|
2022-06-02 11:14:58 -07:00
|
|
|
&stats,
|
2022-06-08 04:57:12 -07:00
|
|
|
&connection_cache,
|
2022-06-08 22:25:37 -07:00
|
|
|
&mut TracerPacketStats::new(0),
|
2022-07-05 21:24:58 -07:00
|
|
|
&bank_forks,
|
2021-12-29 10:34:31 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
recv_socket
|
|
|
|
.set_nonblocking(expected_ids.is_empty())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let mut packets = vec![Packet::default(); 2];
|
2022-01-04 06:08:15 -08:00
|
|
|
let num_received = recv_mmsg(recv_socket, &mut packets[..]).unwrap_or_default();
|
2021-12-29 10:34:31 -08:00
|
|
|
assert_eq!(num_received, expected_ids.len(), "{}", name);
|
|
|
|
for (i, expected_id) in expected_ids.iter().enumerate() {
|
2022-03-10 10:47:46 -08:00
|
|
|
assert_eq!(packets[i].meta.size, 215);
|
|
|
|
let recv_transaction: VersionedTransaction =
|
2022-05-23 20:15:20 -07:00
|
|
|
packets[i].deserialize_slice(..).unwrap();
|
2022-03-10 10:47:46 -08:00
|
|
|
assert_eq!(
|
|
|
|
recv_transaction.message.recent_blockhash(),
|
|
|
|
expected_id,
|
|
|
|
"{}",
|
|
|
|
name
|
|
|
|
);
|
2021-12-29 10:34:31 -08:00
|
|
|
}
|
|
|
|
|
2022-05-04 19:50:56 -07:00
|
|
|
let num_unprocessed_packets: usize = unprocessed_packet_batches.len();
|
2021-12-29 10:34:31 -08:00
|
|
|
assert_eq!(
|
|
|
|
num_unprocessed_packets, expected_num_unprocessed,
|
|
|
|
"{}",
|
|
|
|
name
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-09-21 08:49:41 -07:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
2022-02-03 00:56:36 -08:00
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2021-09-21 08:49:41 -07:00
|
|
|
}
|
|
|
|
|
2022-01-14 15:44:18 -08:00
|
|
|
#[test]
|
|
|
|
fn test_accumulate_batched_transaction_costs() {
|
2022-04-19 11:25:47 -07:00
|
|
|
let signature_cost = 1;
|
|
|
|
let write_lock_cost = 2;
|
|
|
|
let data_bytes_cost = 3;
|
|
|
|
let builtins_execution_cost = 4;
|
|
|
|
let bpf_execution_cost = 10;
|
|
|
|
let num_txs = 4;
|
|
|
|
|
|
|
|
let tx_costs: Vec<_> = (0..num_txs)
|
|
|
|
.map(|_| TransactionCost {
|
|
|
|
signature_cost,
|
|
|
|
write_lock_cost,
|
|
|
|
data_bytes_cost,
|
|
|
|
builtins_execution_cost,
|
|
|
|
bpf_execution_cost,
|
2022-01-14 15:44:18 -08:00
|
|
|
..TransactionCost::default()
|
2022-04-19 11:25:47 -07:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let tx_results: Vec<_> = (0..num_txs)
|
|
|
|
.map(|n| {
|
|
|
|
if n % 2 == 0 {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(TransactionError::WouldExceedMaxBlockCostLimit)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
// should only accumulate half of the costs that are OK
|
|
|
|
let expected_signatures = signature_cost * (num_txs / 2);
|
|
|
|
let expected_write_locks = write_lock_cost * (num_txs / 2);
|
|
|
|
let expected_data_bytes = data_bytes_cost * (num_txs / 2);
|
|
|
|
let expected_builtins_execution_costs = builtins_execution_cost * (num_txs / 2);
|
|
|
|
let expected_bpf_execution_costs = bpf_execution_cost * (num_txs / 2);
|
2022-03-13 08:58:57 -07:00
|
|
|
let batched_transaction_details =
|
2022-01-14 15:44:18 -08:00
|
|
|
BankingStage::accumulate_batched_transaction_costs(tx_costs.iter(), tx_results.iter());
|
2022-03-13 08:58:57 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected_signatures,
|
|
|
|
batched_transaction_details.costs.batched_signature_cost
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
expected_write_locks,
|
|
|
|
batched_transaction_details.costs.batched_write_lock_cost
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
expected_data_bytes,
|
|
|
|
batched_transaction_details.costs.batched_data_bytes_cost
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-19 11:25:47 -07:00
|
|
|
expected_builtins_execution_costs,
|
|
|
|
batched_transaction_details
|
|
|
|
.costs
|
|
|
|
.batched_builtins_execute_cost
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
expected_bpf_execution_costs,
|
|
|
|
batched_transaction_details.costs.batched_bpf_execute_cost
|
2022-03-13 08:58:57 -07:00
|
|
|
);
|
2022-01-14 15:44:18 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_accumulate_execute_units_and_time() {
|
|
|
|
let mut execute_timings = ExecuteTimings::default();
|
|
|
|
let mut expected_units = 0;
|
|
|
|
let mut expected_us = 0;
|
|
|
|
|
|
|
|
for n in 0..10 {
|
|
|
|
execute_timings.details.per_program_timings.insert(
|
|
|
|
Pubkey::new_unique(),
|
|
|
|
ProgramTiming {
|
|
|
|
accumulated_us: n * 100,
|
|
|
|
accumulated_units: n * 1000,
|
|
|
|
count: n as u32,
|
|
|
|
errored_txs_compute_consumed: vec![],
|
|
|
|
total_errored_units: 0,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
expected_us += n * 100;
|
|
|
|
expected_units += n * 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (units, us) = BankingStage::accumulate_execute_units_and_time(&execute_timings);
|
|
|
|
|
|
|
|
assert_eq!(expected_units, units);
|
|
|
|
assert_eq!(expected_us, us);
|
|
|
|
}
|
2022-05-04 19:50:56 -07:00
|
|
|
|
|
|
|
#[test]
|
2022-10-20 14:10:48 -07:00
|
|
|
fn test_unprocessed_transaction_storage_full_send() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
mut genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_slow_genesis_config(10000);
|
|
|
|
activate_feature(
|
|
|
|
&mut genesis_config,
|
|
|
|
allow_votes_to_directly_update_vote_state::id(),
|
|
|
|
);
|
|
|
|
let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank = Arc::new(bank_forks.read().unwrap().get(0).unwrap());
|
|
|
|
let start_hash = bank.last_blockhash();
|
|
|
|
let (verified_sender, verified_receiver) = unbounded();
|
|
|
|
let (tpu_vote_sender, tpu_vote_receiver) = unbounded();
|
|
|
|
let (gossip_verified_vote_sender, gossip_verified_vote_receiver) = unbounded();
|
|
|
|
let ledger_path = get_tmp_ledger_path_auto_delete!();
|
|
|
|
{
|
|
|
|
let blockstore = Arc::new(
|
|
|
|
Blockstore::open(ledger_path.path())
|
|
|
|
.expect("Expected to be able to open database ledger"),
|
|
|
|
);
|
|
|
|
let poh_config = PohConfig {
|
|
|
|
// limit tick count to avoid clearing working_bank at PohRecord then
|
|
|
|
// PohRecorderError(MaxHeightReached) at BankingStage
|
|
|
|
target_tick_count: Some(bank.max_tick_height() - 1),
|
|
|
|
..PohConfig::default()
|
|
|
|
};
|
|
|
|
let (exit, poh_recorder, poh_service, _entry_receiver) =
|
|
|
|
create_test_recorder(&bank, &blockstore, Some(poh_config), None);
|
|
|
|
let cluster_info = new_test_cluster_info(Node::new_localhost().info);
|
|
|
|
let cluster_info = Arc::new(cluster_info);
|
|
|
|
let (gossip_vote_sender, _gossip_vote_receiver) = unbounded();
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let banking_stage = BankingStage::new(
|
|
|
|
&cluster_info,
|
|
|
|
&poh_recorder,
|
|
|
|
verified_receiver,
|
|
|
|
tpu_vote_receiver,
|
|
|
|
gossip_verified_vote_receiver,
|
|
|
|
None,
|
|
|
|
gossip_vote_sender,
|
|
|
|
Arc::new(RwLock::new(CostModel::default())),
|
|
|
|
None,
|
|
|
|
Arc::new(ConnectionCache::default()),
|
|
|
|
bank_forks,
|
|
|
|
);
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let keypairs = (0..100).map(|_| Keypair::new()).collect_vec();
|
|
|
|
let vote_keypairs = (0..100).map(|_| Keypair::new()).collect_vec();
|
|
|
|
for keypair in keypairs.iter() {
|
|
|
|
bank.process_transaction(&system_transaction::transfer(
|
|
|
|
&mint_keypair,
|
|
|
|
&keypair.pubkey(),
|
|
|
|
20,
|
|
|
|
start_hash,
|
|
|
|
))
|
|
|
|
.unwrap();
|
|
|
|
}
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
// Send a bunch of votes and transfers
|
|
|
|
let tpu_votes = (0..100_usize)
|
|
|
|
.map(|i| {
|
|
|
|
new_vote_state_update_transaction(
|
|
|
|
VoteStateUpdate::from(vec![
|
|
|
|
(0, 8),
|
|
|
|
(1, 7),
|
|
|
|
(i as u64 + 10, 6),
|
|
|
|
(i as u64 + 11, 1),
|
|
|
|
]),
|
|
|
|
Hash::new_unique(),
|
|
|
|
&keypairs[i],
|
|
|
|
&vote_keypairs[i],
|
|
|
|
&vote_keypairs[i],
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.collect_vec();
|
|
|
|
let gossip_votes = (0..100_usize)
|
|
|
|
.map(|i| {
|
|
|
|
new_vote_state_update_transaction(
|
|
|
|
VoteStateUpdate::from(vec![
|
|
|
|
(0, 8),
|
|
|
|
(1, 7),
|
|
|
|
(i as u64 + 64 + 5, 6),
|
|
|
|
(i as u64 + 7, 1),
|
|
|
|
]),
|
|
|
|
Hash::new_unique(),
|
|
|
|
&keypairs[i],
|
|
|
|
&vote_keypairs[i],
|
|
|
|
&vote_keypairs[i],
|
|
|
|
None,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.collect_vec();
|
|
|
|
let txs = (0..100_usize)
|
|
|
|
.map(|i| {
|
|
|
|
system_transaction::transfer(
|
|
|
|
&keypairs[i],
|
|
|
|
&keypairs[(i + 1) % 100].pubkey(),
|
|
|
|
10,
|
|
|
|
start_hash,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.collect_vec();
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
let tpu_packet_batches = to_packet_batches(&tpu_votes, 10);
|
|
|
|
let gossip_packet_batches = to_packet_batches(&gossip_votes, 10);
|
|
|
|
let tx_packet_batches = to_packet_batches(&txs, 10);
|
2022-05-04 19:50:56 -07:00
|
|
|
|
2022-10-20 14:10:48 -07:00
|
|
|
// Send em all
|
|
|
|
[
|
|
|
|
(tpu_packet_batches, tpu_vote_sender.clone()),
|
|
|
|
(gossip_packet_batches, gossip_verified_vote_sender.clone()),
|
|
|
|
(tx_packet_batches, verified_sender.clone()),
|
|
|
|
]
|
|
|
|
.into_iter()
|
|
|
|
.map(|(packet_batches, sender)| {
|
|
|
|
Builder::new()
|
|
|
|
.spawn(move || sender.send((packet_batches, None)).unwrap())
|
|
|
|
.unwrap()
|
|
|
|
})
|
|
|
|
.for_each(|handle| handle.join().unwrap());
|
|
|
|
|
|
|
|
drop(verified_sender);
|
|
|
|
drop(tpu_vote_sender);
|
|
|
|
drop(gossip_verified_vote_sender);
|
|
|
|
banking_stage.join().unwrap();
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
|
|
|
Blockstore::destroy(ledger_path.path()).unwrap();
|
2022-05-04 19:50:56 -07:00
|
|
|
}
|
2018-09-25 15:01:51 -07:00
|
|
|
}
|