Browse Source

ForwardingStage hookup, BankingStage forwarding removal (#4518)

Andrew Fitzgerald 9 months ago
parent
commit
03594e48d4

+ 0 - 22
banking-bench/src/main.rs

@@ -7,7 +7,6 @@ use {
     log::*,
     log::*,
     rand::{thread_rng, Rng},
     rand::{thread_rng, Rng},
     rayon::prelude::*,
     rayon::prelude::*,
-    solana_client::connection_cache::ConnectionCache,
     solana_core::{
     solana_core::{
         banking_stage::{update_bank_forks_and_poh_recorder_for_new_tpu_bank, BankingStage},
         banking_stage::{update_bank_forks_and_poh_recorder_for_new_tpu_bank, BankingStage},
         banking_trace::{BankingTracer, Channels, BANKING_TRACE_DIR_DEFAULT_BYTE_LIMIT},
         banking_trace::{BankingTracer, Channels, BANKING_TRACE_DIR_DEFAULT_BYTE_LIMIT},
@@ -37,7 +36,6 @@ use {
         transaction::Transaction,
         transaction::Transaction,
     },
     },
     solana_streamer::socket::SocketAddrSpace,
     solana_streamer::socket::SocketAddrSpace,
-    solana_tpu_client::tpu_client::DEFAULT_TPU_CONNECTION_POOL_SIZE,
     std::{
     std::{
         sync::{atomic::Ordering, Arc, RwLock},
         sync::{atomic::Ordering, Arc, RwLock},
         thread::sleep,
         thread::sleep,
@@ -304,12 +302,6 @@ fn main() {
                 .takes_value(true)
                 .takes_value(true)
                 .help("Number of threads to use in the banking stage"),
                 .help("Number of threads to use in the banking stage"),
         )
         )
-        .arg(
-            Arg::new("tpu_disable_quic")
-                .long("tpu-disable-quic")
-                .takes_value(false)
-                .help("Disable forwarding messages to TPU using QUIC"),
-        )
         .arg(
         .arg(
             Arg::new("simulate_mint")
             Arg::new("simulate_mint")
                 .long("simulate-mint")
                 .long("simulate-mint")
@@ -468,18 +460,6 @@ fn main() {
         gossip_vote_sender,
         gossip_vote_sender,
         gossip_vote_receiver,
         gossip_vote_receiver,
     } = banking_tracer.create_channels(false);
     } = banking_tracer.create_channels(false);
-    let tpu_disable_quic = matches.is_present("tpu_disable_quic");
-    let connection_cache = if tpu_disable_quic {
-        ConnectionCache::with_udp(
-            "connection_cache_banking_bench_udp",
-            DEFAULT_TPU_CONNECTION_POOL_SIZE,
-        )
-    } else {
-        ConnectionCache::new_quic(
-            "connection_cache_banking_bench_quic",
-            DEFAULT_TPU_CONNECTION_POOL_SIZE,
-        )
-    };
     let banking_stage = BankingStage::new_num_threads(
     let banking_stage = BankingStage::new_num_threads(
         block_production_method,
         block_production_method,
         transaction_struct,
         transaction_struct,
@@ -492,10 +472,8 @@ fn main() {
         None,
         None,
         replay_vote_sender,
         replay_vote_sender,
         None,
         None,
-        Arc::new(connection_cache),
         bank_forks.clone(),
         bank_forks.clone(),
         &prioritization_fee_cache,
         &prioritization_fee_cache,
-        false,
     );
     );
 
 
     // This is so that the signal_receiver does not go out of scope after the closure.
     // This is so that the signal_receiver does not go out of scope after the closure.

+ 0 - 3
core/benches/banking_stage.rs

@@ -18,7 +18,6 @@ use {
     log::*,
     log::*,
     rand::{thread_rng, Rng},
     rand::{thread_rng, Rng},
     rayon::prelude::*,
     rayon::prelude::*,
-    solana_client::connection_cache::ConnectionCache,
     solana_core::{
     solana_core::{
         banking_stage::{
         banking_stage::{
             committer::Committer,
             committer::Committer,
@@ -316,10 +315,8 @@ fn bench_banking(
         None,
         None,
         s,
         s,
         None,
         None,
-        Arc::new(ConnectionCache::new("connection_cache_test")),
         bank_forks,
         bank_forks,
         &Arc::new(PrioritizationFeeCache::new(0u64)),
         &Arc::new(PrioritizationFeeCache::new(0u64)),
-        false,
     );
     );
 
 
     let chunk_len = verified.len() / CHUNKS;
     let chunk_len = verified.len() / CHUNKS;

+ 0 - 177
core/benches/forwarder.rs

@@ -1,177 +0,0 @@
-#![feature(test)]
-extern crate test;
-use {
-    itertools::Itertools,
-    solana_client::connection_cache::ConnectionCache,
-    solana_core::banking_stage::{
-        forwarder::Forwarder,
-        leader_slot_metrics::LeaderSlotMetricsTracker,
-        unprocessed_packet_batches::{DeserializedPacket, UnprocessedPacketBatches},
-        unprocessed_transaction_storage::{ThreadType, UnprocessedTransactionStorage},
-        BankingStageStats,
-    },
-    solana_gossip::cluster_info::{ClusterInfo, Node},
-    solana_ledger::{
-        blockstore::Blockstore,
-        genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo},
-    },
-    solana_perf::{data_budget::DataBudget, packet::Packet},
-    solana_poh::{poh_recorder::create_test_recorder, poh_service::PohService},
-    solana_runtime::{bank::Bank, genesis_utils::bootstrap_validator_stake_lamports},
-    solana_sdk::{poh_config::PohConfig, signature::Keypair, signer::Signer, system_transaction},
-    solana_streamer::socket::SocketAddrSpace,
-    std::sync::{
-        atomic::{AtomicBool, Ordering},
-        Arc,
-    },
-    tempfile::TempDir,
-    test::Bencher,
-};
-
-struct BenchSetup {
-    exit: Arc<AtomicBool>,
-    poh_service: PohService,
-    forwarder: Forwarder<Arc<ClusterInfo>>,
-    unprocessed_packet_batches: UnprocessedTransactionStorage,
-    tracker: LeaderSlotMetricsTracker,
-    stats: BankingStageStats,
-}
-
-fn setup(num_packets: usize, contentious_transaction: bool) -> BenchSetup {
-    let validator_keypair = Arc::new(Keypair::new());
-    let genesis_config_info = create_genesis_config_with_leader(
-        10_000,
-        &validator_keypair.pubkey(),
-        bootstrap_validator_stake_lamports(),
-    );
-    let GenesisConfigInfo { genesis_config, .. } = &genesis_config_info;
-
-    let (bank, bank_forks) = Bank::new_no_wallclock_throttle_for_tests(genesis_config);
-
-    let ledger_path = TempDir::new().unwrap();
-    let blockstore = Arc::new(
-        Blockstore::open(ledger_path.as_ref())
-            .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().saturating_sub(1)),
-        ..PohConfig::default()
-    };
-
-    let (exit, poh_recorder, poh_service, _entry_receiver) =
-        create_test_recorder(bank, blockstore, Some(poh_config), None);
-
-    let local_node = Node::new_localhost_with_pubkey(&validator_keypair.pubkey());
-    let cluster_info = ClusterInfo::new(
-        local_node.info.clone(),
-        validator_keypair,
-        SocketAddrSpace::Unspecified,
-    );
-    let cluster_info = Arc::new(cluster_info);
-    let min_balance = genesis_config.rent.minimum_balance(0);
-    let hash = genesis_config.hash();
-
-    // packets are deserialized upon receiving, failed packets will not be
-    // forwarded; Therefore need to create real packets here.
-    let keypair = Keypair::new();
-    let packets = (0..num_packets)
-        .map(|_| {
-            let mut transaction =
-                system_transaction::transfer(&keypair, &Keypair::new().pubkey(), min_balance, hash);
-            if !contentious_transaction {
-                transaction.message.account_keys[0] = solana_pubkey::Pubkey::new_unique();
-            }
-            let mut packet = Packet::from_data(None, transaction).unwrap();
-            packet.meta_mut().set_from_staked_node(true);
-            DeserializedPacket::new(packet).unwrap()
-        })
-        .collect_vec();
-
-    let unprocessed_packet_batches = UnprocessedTransactionStorage::new_transaction_storage(
-        UnprocessedPacketBatches::from_iter(packets, num_packets),
-        ThreadType::Transactions,
-    );
-
-    let connection_cache = ConnectionCache::new("connection_cache_test");
-    // use a restrictive data budget to bench everything except actual sending data over
-    // connection.
-    let data_budget = DataBudget::restricted();
-    let forwarder = Forwarder::new(
-        poh_recorder,
-        bank_forks,
-        cluster_info,
-        Arc::new(connection_cache),
-        Arc::new(data_budget),
-    );
-
-    BenchSetup {
-        exit,
-        poh_service,
-        forwarder,
-        unprocessed_packet_batches,
-        tracker: LeaderSlotMetricsTracker::new(0),
-        stats: BankingStageStats::default(),
-    }
-}
-
-#[bench]
-fn bench_forwarder_handle_forwading_contentious_transaction(bencher: &mut Bencher) {
-    let num_packets = 10240;
-    let BenchSetup {
-        exit,
-        poh_service,
-        mut forwarder,
-        mut unprocessed_packet_batches,
-        mut tracker,
-        stats,
-    } = setup(num_packets, true);
-
-    // hold packets so they can be reused for benching
-    let hold = true;
-    bencher.iter(|| {
-        forwarder.handle_forwarding(&mut unprocessed_packet_batches, hold, &mut tracker, &stats);
-        // reset packet.forwarded flag to reuse `unprocessed_packet_batches`
-        if let UnprocessedTransactionStorage::LocalTransactionStorage(unprocessed_packets) =
-            &mut unprocessed_packet_batches
-        {
-            for deserialized_packet in unprocessed_packets.iter_mut() {
-                deserialized_packet.forwarded = false;
-            }
-        }
-    });
-
-    exit.store(true, Ordering::Relaxed);
-    poh_service.join().unwrap();
-}
-
-#[bench]
-fn bench_forwarder_handle_forwading_parallel_transactions(bencher: &mut Bencher) {
-    let num_packets = 10240;
-    let BenchSetup {
-        exit,
-        poh_service,
-        mut forwarder,
-        mut unprocessed_packet_batches,
-        mut tracker,
-        stats,
-    } = setup(num_packets, false);
-
-    // hold packets so they can be reused for benching
-    let hold = true;
-    bencher.iter(|| {
-        forwarder.handle_forwarding(&mut unprocessed_packet_batches, hold, &mut tracker, &stats);
-        // reset packet.forwarded flag to reuse `unprocessed_packet_batches`
-        if let UnprocessedTransactionStorage::LocalTransactionStorage(unprocessed_packets) =
-            &mut unprocessed_packet_batches
-        {
-            for deserialized_packet in unprocessed_packets.iter_mut() {
-                deserialized_packet.forwarded = false;
-            }
-        }
-    });
-
-    exit.store(true, Ordering::Relaxed);
-    poh_service.join().unwrap();
-}

+ 2 - 2
core/benches/sigverify_stage.rs

@@ -157,7 +157,7 @@ fn bench_sigverify_stage(bencher: &mut Bencher, use_same_tx: bool) {
     trace!("start");
     trace!("start");
     let (packet_s, packet_r) = unbounded();
     let (packet_s, packet_r) = unbounded();
     let (verified_s, verified_r) = BankingTracer::channel_for_test();
     let (verified_s, verified_r) = BankingTracer::channel_for_test();
-    let verifier = TransactionSigVerifier::new(verified_s);
+    let verifier = TransactionSigVerifier::new(verified_s, None);
     let stage = SigVerifyStage::new(packet_r, verifier, "solSigVerBench", "bench");
     let stage = SigVerifyStage::new(packet_r, verifier, "solSigVerBench", "bench");
 
 
     bencher.iter(move || {
     bencher.iter(move || {
@@ -231,7 +231,7 @@ fn prepare_batches(discard_factor: i32) -> (Vec<PacketBatch>, usize) {
 fn bench_shrink_sigverify_stage_core(bencher: &mut Bencher, discard_factor: i32) {
 fn bench_shrink_sigverify_stage_core(bencher: &mut Bencher, discard_factor: i32) {
     let (batches0, num_valid_packets) = prepare_batches(discard_factor);
     let (batches0, num_valid_packets) = prepare_batches(discard_factor);
     let (verified_s, _verified_r) = BankingTracer::channel_for_test();
     let (verified_s, _verified_r) = BankingTracer::channel_for_test();
-    let verifier = TransactionSigVerifier::new(verified_s);
+    let verifier = TransactionSigVerifier::new(verified_s, None);
 
 
     let mut c = 0;
     let mut c = 0;
     let mut total_shrink_time = 0;
     let mut total_shrink_time = 0;

+ 0 - 4
core/src/banking_simulation.rs

@@ -16,7 +16,6 @@ use {
     crossbeam_channel::{unbounded, Sender},
     crossbeam_channel::{unbounded, Sender},
     itertools::Itertools,
     itertools::Itertools,
     log::*,
     log::*,
-    solana_client::connection_cache::ConnectionCache,
     solana_gossip::{
     solana_gossip::{
         cluster_info::{ClusterInfo, Node},
         cluster_info::{ClusterInfo, Node},
         contact_info::ContactInfoQuery,
         contact_info::ContactInfoQuery,
@@ -787,7 +786,6 @@ impl BankingSimulator {
             gossip_vote_receiver,
             gossip_vote_receiver,
         } = retracer.create_channels(false);
         } = retracer.create_channels(false);
 
 
-        let connection_cache = Arc::new(ConnectionCache::new("connection_cache_sim"));
         let (replay_vote_sender, _replay_vote_receiver) = unbounded();
         let (replay_vote_sender, _replay_vote_receiver) = unbounded();
         let (retransmit_slots_sender, retransmit_slots_receiver) = unbounded();
         let (retransmit_slots_sender, retransmit_slots_receiver) = unbounded();
         let shred_version = compute_shred_version(
         let shred_version = compute_shred_version(
@@ -833,10 +831,8 @@ impl BankingSimulator {
             None,
             None,
             replay_vote_sender,
             replay_vote_sender,
             None,
             None,
-            connection_cache,
             bank_forks.clone(),
             bank_forks.clone(),
             prioritization_fee_cache,
             prioritization_fee_cache,
-            false,
         );
         );
 
 
         let (&_slot, &raw_base_event_time) = freeze_time_by_slot
         let (&_slot, &raw_base_event_time) = freeze_time_by_slot

+ 20 - 128
core/src/banking_stage.rs

@@ -9,7 +9,6 @@ use {
         committer::Committer,
         committer::Committer,
         consumer::Consumer,
         consumer::Consumer,
         decision_maker::{BufferedPacketsDecision, DecisionMaker},
         decision_maker::{BufferedPacketsDecision, DecisionMaker},
-        forwarder::Forwarder,
         latest_unprocessed_votes::{LatestUnprocessedVotes, VoteSource},
         latest_unprocessed_votes::{LatestUnprocessedVotes, VoteSource},
         leader_slot_metrics::LeaderSlotMetricsTracker,
         leader_slot_metrics::LeaderSlotMetricsTracker,
         packet_receiver::PacketReceiver,
         packet_receiver::PacketReceiver,
@@ -30,11 +29,10 @@ use {
     agave_banking_stage_ingress_types::BankingPacketReceiver,
     agave_banking_stage_ingress_types::BankingPacketReceiver,
     crossbeam_channel::{unbounded, Receiver, RecvTimeoutError, Sender},
     crossbeam_channel::{unbounded, Receiver, RecvTimeoutError, Sender},
     histogram::Histogram,
     histogram::Histogram,
-    solana_client::connection_cache::ConnectionCache,
     solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfoQuery},
     solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfoQuery},
     solana_ledger::blockstore_processor::TransactionStatusSender,
     solana_ledger::blockstore_processor::TransactionStatusSender,
     solana_measure::measure_us,
     solana_measure::measure_us,
-    solana_perf::{data_budget::DataBudget, packet::PACKETS_PER_BATCH},
+    solana_perf::packet::PACKETS_PER_BATCH,
     solana_poh::poh_recorder::{PohRecorder, TransactionRecorder},
     solana_poh::poh_recorder::{PohRecorder, TransactionRecorder},
     solana_runtime::{
     solana_runtime::{
         bank::Bank, bank_forks::BankForks, prioritization_fee_cache::PrioritizationFeeCache,
         bank::Bank, bank_forks::BankForks, prioritization_fee_cache::PrioritizationFeeCache,
@@ -64,7 +62,6 @@ use {
 // Below modules are pub to allow use by banking_stage bench
 // Below modules are pub to allow use by banking_stage bench
 pub mod committer;
 pub mod committer;
 pub mod consumer;
 pub mod consumer;
-pub mod forwarder;
 pub mod leader_slot_metrics;
 pub mod leader_slot_metrics;
 pub mod qos_service;
 pub mod qos_service;
 pub mod unprocessed_packet_batches;
 pub mod unprocessed_packet_batches;
@@ -72,7 +69,6 @@ pub mod unprocessed_transaction_storage;
 
 
 mod consume_worker;
 mod consume_worker;
 mod decision_maker;
 mod decision_maker;
-mod forward_packet_batches_by_accounts;
 mod immutable_deserialized_packet;
 mod immutable_deserialized_packet;
 mod latest_unprocessed_votes;
 mod latest_unprocessed_votes;
 mod leader_slot_timing_metrics;
 mod leader_slot_timing_metrics;
@@ -115,8 +111,6 @@ pub struct BankingStageStats {
     current_buffered_packets_count: AtomicUsize,
     current_buffered_packets_count: AtomicUsize,
     rebuffered_packets_count: AtomicUsize,
     rebuffered_packets_count: AtomicUsize,
     consumed_buffered_packets_count: AtomicUsize,
     consumed_buffered_packets_count: AtomicUsize,
-    forwarded_transaction_count: AtomicUsize,
-    forwarded_vote_count: AtomicUsize,
     batch_packet_indexes_len: Histogram,
     batch_packet_indexes_len: Histogram,
 
 
     // Timing
     // Timing
@@ -161,8 +155,6 @@ impl BankingStageStats {
             + self.filter_pending_packets_elapsed.load(Ordering::Relaxed)
             + self.filter_pending_packets_elapsed.load(Ordering::Relaxed)
             + self.packet_conversion_elapsed.load(Ordering::Relaxed)
             + self.packet_conversion_elapsed.load(Ordering::Relaxed)
             + self.transaction_processing_elapsed.load(Ordering::Relaxed)
             + self.transaction_processing_elapsed.load(Ordering::Relaxed)
-            + self.forwarded_transaction_count.load(Ordering::Relaxed) as u64
-            + self.forwarded_vote_count.load(Ordering::Relaxed) as u64
             + self.batch_packet_indexes_len.entries()
             + self.batch_packet_indexes_len.entries()
     }
     }
 
 
@@ -226,16 +218,6 @@ impl BankingStageStats {
                         .swap(0, Ordering::Relaxed),
                         .swap(0, Ordering::Relaxed),
                     i64
                     i64
                 ),
                 ),
-                (
-                    "forwarded_transaction_count",
-                    self.forwarded_transaction_count.swap(0, Ordering::Relaxed),
-                    i64
-                ),
-                (
-                    "forwarded_vote_count",
-                    self.forwarded_vote_count.swap(0, Ordering::Relaxed),
-                    i64
-                ),
                 (
                 (
                     "consume_buffered_packets_elapsed",
                     "consume_buffered_packets_elapsed",
                     self.consume_buffered_packets_elapsed
                     self.consume_buffered_packets_elapsed
@@ -320,21 +302,6 @@ pub struct BankingStage {
     bank_thread_hdls: Vec<JoinHandle<()>>,
     bank_thread_hdls: Vec<JoinHandle<()>>,
 }
 }
 
 
-#[derive(Debug, Clone)]
-pub enum ForwardOption {
-    NotForward,
-    ForwardTpuVote,
-    ForwardTransaction,
-}
-
-#[derive(Debug, Default)]
-pub struct FilterForwardingResults {
-    pub(crate) total_forwardable_packets: usize,
-    pub(crate) total_dropped_packets: usize,
-    pub(crate) total_packet_conversion_us: u64,
-    pub(crate) total_filter_packets_us: u64,
-}
-
 pub trait LikeClusterInfo: Send + Sync + 'static + Clone {
 pub trait LikeClusterInfo: Send + Sync + 'static + Clone {
     fn id(&self) -> Pubkey;
     fn id(&self) -> Pubkey;
 
 
@@ -365,10 +332,8 @@ impl BankingStage {
         transaction_status_sender: Option<TransactionStatusSender>,
         transaction_status_sender: Option<TransactionStatusSender>,
         replay_vote_sender: ReplayVoteSender,
         replay_vote_sender: ReplayVoteSender,
         log_messages_bytes_limit: Option<usize>,
         log_messages_bytes_limit: Option<usize>,
-        connection_cache: Arc<ConnectionCache>,
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
-        enable_forwarding: bool,
     ) -> Self {
     ) -> Self {
         Self::new_num_threads(
         Self::new_num_threads(
             block_production_method,
             block_production_method,
@@ -382,10 +347,8 @@ impl BankingStage {
             transaction_status_sender,
             transaction_status_sender,
             replay_vote_sender,
             replay_vote_sender,
             log_messages_bytes_limit,
             log_messages_bytes_limit,
-            connection_cache,
             bank_forks,
             bank_forks,
             prioritization_fee_cache,
             prioritization_fee_cache,
-            enable_forwarding,
         )
         )
     }
     }
 
 
@@ -402,10 +365,8 @@ impl BankingStage {
         transaction_status_sender: Option<TransactionStatusSender>,
         transaction_status_sender: Option<TransactionStatusSender>,
         replay_vote_sender: ReplayVoteSender,
         replay_vote_sender: ReplayVoteSender,
         log_messages_bytes_limit: Option<usize>,
         log_messages_bytes_limit: Option<usize>,
-        connection_cache: Arc<ConnectionCache>,
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
-        enable_forwarding: bool,
     ) -> Self {
     ) -> Self {
         match block_production_method {
         match block_production_method {
             BlockProductionMethod::CentralScheduler
             BlockProductionMethod::CentralScheduler
@@ -426,10 +387,8 @@ impl BankingStage {
                     transaction_status_sender,
                     transaction_status_sender,
                     replay_vote_sender,
                     replay_vote_sender,
                     log_messages_bytes_limit,
                     log_messages_bytes_limit,
-                    connection_cache,
                     bank_forks,
                     bank_forks,
                     prioritization_fee_cache,
                     prioritization_fee_cache,
-                    enable_forwarding,
                 )
                 )
             }
             }
         }
         }
@@ -448,16 +407,10 @@ impl BankingStage {
         transaction_status_sender: Option<TransactionStatusSender>,
         transaction_status_sender: Option<TransactionStatusSender>,
         replay_vote_sender: ReplayVoteSender,
         replay_vote_sender: ReplayVoteSender,
         log_messages_bytes_limit: Option<usize>,
         log_messages_bytes_limit: Option<usize>,
-        connection_cache: Arc<ConnectionCache>,
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
         prioritization_fee_cache: &Arc<PrioritizationFeeCache>,
-        enable_forwarding: bool,
     ) -> Self {
     ) -> Self {
         assert!(num_threads >= MIN_TOTAL_THREADS);
         assert!(num_threads >= MIN_TOTAL_THREADS);
-        // Single thread to generate entries from many banks.
-        // This thread talks to poh_service and broadcasts the entries once they have been recorded.
-        // Once an entry has been recorded, its blockhash is registered with the bank.
-        let data_budget = Arc::new(DataBudget::default());
         // Keeps track of extraneous vote transactions for the vote threads
         // Keeps track of extraneous vote transactions for the vote threads
         let latest_unprocessed_votes = {
         let latest_unprocessed_votes = {
             let bank = bank_forks.read().unwrap().working_bank();
             let bank = bank_forks.read().unwrap().working_bank();
@@ -484,16 +437,10 @@ impl BankingStage {
                 id,
                 id,
                 packet_receiver,
                 packet_receiver,
                 decision_maker.clone(),
                 decision_maker.clone(),
+                bank_forks.clone(),
                 committer.clone(),
                 committer.clone(),
                 transaction_recorder.clone(),
                 transaction_recorder.clone(),
                 log_messages_bytes_limit,
                 log_messages_bytes_limit,
-                Forwarder::new(
-                    poh_recorder.clone(),
-                    bank_forks.clone(),
-                    cluster_info.clone(),
-                    connection_cache.clone(),
-                    data_budget.clone(),
-                ),
                 UnprocessedTransactionStorage::new_vote_storage(
                 UnprocessedTransactionStorage::new_vote_storage(
                     latest_unprocessed_votes.clone(),
                     latest_unprocessed_votes.clone(),
                     vote_source,
                     vote_source,
@@ -501,22 +448,11 @@ impl BankingStage {
             ));
             ));
         }
         }
 
 
-        let transaction_struct =
-            if enable_forwarding && !matches!(transaction_struct, TransactionStructure::Sdk) {
-                warn!(
-                "Forwarding only supported for `Sdk` transaction struct. Overriding to use `Sdk`."
-            );
-                TransactionStructure::Sdk
-            } else {
-                transaction_struct
-            };
-
         match transaction_struct {
         match transaction_struct {
             TransactionStructure::Sdk => {
             TransactionStructure::Sdk => {
                 let receive_and_buffer = SanitizedTransactionReceiveAndBuffer::new(
                 let receive_and_buffer = SanitizedTransactionReceiveAndBuffer::new(
                     PacketDeserializer::new(non_vote_receiver),
                     PacketDeserializer::new(non_vote_receiver),
                     bank_forks.clone(),
                     bank_forks.clone(),
-                    enable_forwarding,
                 );
                 );
                 Self::spawn_scheduler_and_workers(
                 Self::spawn_scheduler_and_workers(
                     &mut bank_thread_hdls,
                     &mut bank_thread_hdls,
@@ -524,14 +460,10 @@ impl BankingStage {
                     use_greedy_scheduler,
                     use_greedy_scheduler,
                     decision_maker,
                     decision_maker,
                     committer,
                     committer,
-                    cluster_info,
                     poh_recorder,
                     poh_recorder,
                     num_threads,
                     num_threads,
                     log_messages_bytes_limit,
                     log_messages_bytes_limit,
-                    connection_cache,
                     bank_forks,
                     bank_forks,
-                    enable_forwarding,
-                    data_budget,
                 );
                 );
             }
             }
             TransactionStructure::View => {
             TransactionStructure::View => {
@@ -545,14 +477,10 @@ impl BankingStage {
                     use_greedy_scheduler,
                     use_greedy_scheduler,
                     decision_maker,
                     decision_maker,
                     committer,
                     committer,
-                    cluster_info,
                     poh_recorder,
                     poh_recorder,
                     num_threads,
                     num_threads,
                     log_messages_bytes_limit,
                     log_messages_bytes_limit,
-                    connection_cache,
                     bank_forks,
                     bank_forks,
-                    enable_forwarding,
-                    data_budget,
                 );
                 );
             }
             }
         }
         }
@@ -567,14 +495,10 @@ impl BankingStage {
         use_greedy_scheduler: bool,
         use_greedy_scheduler: bool,
         decision_maker: DecisionMaker,
         decision_maker: DecisionMaker,
         committer: Committer,
         committer: Committer,
-        cluster_info: &impl LikeClusterInfo,
         poh_recorder: &Arc<RwLock<PohRecorder>>,
         poh_recorder: &Arc<RwLock<PohRecorder>>,
         num_threads: u32,
         num_threads: u32,
         log_messages_bytes_limit: Option<usize>,
         log_messages_bytes_limit: Option<usize>,
-        connection_cache: Arc<ConnectionCache>,
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
-        enable_forwarding: bool,
-        data_budget: Arc<DataBudget>,
     ) {
     ) {
         // Create channels for communication between scheduler and workers
         // Create channels for communication between scheduler and workers
         let num_workers = (num_threads).saturating_sub(NUM_VOTE_PROCESSING_THREADS);
         let num_workers = (num_threads).saturating_sub(NUM_VOTE_PROCESSING_THREADS);
@@ -610,16 +534,6 @@ impl BankingStage {
             )
             )
         }
         }
 
 
-        let forwarder = enable_forwarding.then(|| {
-            Forwarder::new(
-                poh_recorder.clone(),
-                bank_forks.clone(),
-                cluster_info.clone(),
-                connection_cache.clone(),
-                data_budget.clone(),
-            )
-        });
-
         // Spawn the central scheduler thread
         // Spawn the central scheduler thread
         if use_greedy_scheduler {
         if use_greedy_scheduler {
             bank_thread_hdls.push(
             bank_thread_hdls.push(
@@ -637,7 +551,6 @@ impl BankingStage {
                             bank_forks,
                             bank_forks,
                             scheduler,
                             scheduler,
                             worker_metrics,
                             worker_metrics,
-                            forwarder,
                         );
                         );
 
 
                         match scheduler_controller.run() {
                         match scheduler_controller.run() {
@@ -666,7 +579,6 @@ impl BankingStage {
                             bank_forks,
                             bank_forks,
                             scheduler,
                             scheduler,
                             worker_metrics,
                             worker_metrics,
-                            forwarder,
                         );
                         );
 
 
                         match scheduler_controller.run() {
                         match scheduler_controller.run() {
@@ -682,14 +594,14 @@ impl BankingStage {
         }
         }
     }
     }
 
 
-    fn spawn_thread_local_multi_iterator_thread<T: LikeClusterInfo>(
+    fn spawn_thread_local_multi_iterator_thread(
         id: u32,
         id: u32,
         packet_receiver: BankingPacketReceiver,
         packet_receiver: BankingPacketReceiver,
         mut decision_maker: DecisionMaker,
         mut decision_maker: DecisionMaker,
+        bank_forks: Arc<RwLock<BankForks>>,
         committer: Committer,
         committer: Committer,
         transaction_recorder: TransactionRecorder,
         transaction_recorder: TransactionRecorder,
         log_messages_bytes_limit: Option<usize>,
         log_messages_bytes_limit: Option<usize>,
-        mut forwarder: Forwarder<T>,
         unprocessed_transaction_storage: UnprocessedTransactionStorage,
         unprocessed_transaction_storage: UnprocessedTransactionStorage,
     ) -> JoinHandle<()> {
     ) -> JoinHandle<()> {
         let mut packet_receiver = PacketReceiver::new(id, packet_receiver);
         let mut packet_receiver = PacketReceiver::new(id, packet_receiver);
@@ -706,7 +618,7 @@ impl BankingStage {
                 Self::process_loop(
                 Self::process_loop(
                     &mut packet_receiver,
                     &mut packet_receiver,
                     &mut decision_maker,
                     &mut decision_maker,
-                    &mut forwarder,
+                    &bank_forks,
                     &consumer,
                     &consumer,
                     id,
                     id,
                     unprocessed_transaction_storage,
                     unprocessed_transaction_storage,
@@ -716,9 +628,9 @@ impl BankingStage {
     }
     }
 
 
     #[allow(clippy::too_many_arguments)]
     #[allow(clippy::too_many_arguments)]
-    fn process_buffered_packets<T: LikeClusterInfo>(
+    fn process_buffered_packets(
         decision_maker: &mut DecisionMaker,
         decision_maker: &mut DecisionMaker,
-        forwarder: &mut Forwarder<T>,
+        bank_forks: &RwLock<BankForks>,
         consumer: &Consumer,
         consumer: &Consumer,
         unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
         unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
         banking_stage_stats: &BankingStageStats,
         banking_stage_stats: &BankingStageStats,
@@ -753,36 +665,26 @@ impl BankingStage {
                     .increment_consume_buffered_packets_us(consume_buffered_packets_us);
                     .increment_consume_buffered_packets_us(consume_buffered_packets_us);
             }
             }
             BufferedPacketsDecision::Forward => {
             BufferedPacketsDecision::Forward => {
-                let ((), forward_us) = measure_us!(forwarder.handle_forwarding(
-                    unprocessed_transaction_storage,
-                    false,
-                    slot_metrics_tracker,
-                    banking_stage_stats,
-                ));
-                slot_metrics_tracker.increment_forward_us(forward_us);
-                // Take metrics action after forwarding packets to include forwarded
-                // metrics into current slot
-                slot_metrics_tracker.apply_action(metrics_action);
+                // get current working bank from bank_forks, use it to sanitize transaction and
+                // load all accounts from address loader;
+                let current_bank = bank_forks.read().unwrap().working_bank();
+                unprocessed_transaction_storage.cache_epoch_boundary_info(&current_bank);
+                unprocessed_transaction_storage.clear();
             }
             }
             BufferedPacketsDecision::ForwardAndHold => {
             BufferedPacketsDecision::ForwardAndHold => {
-                let ((), forward_and_hold_us) = measure_us!(forwarder.handle_forwarding(
-                    unprocessed_transaction_storage,
-                    true,
-                    slot_metrics_tracker,
-                    banking_stage_stats,
-                ));
-                slot_metrics_tracker.increment_forward_and_hold_us(forward_and_hold_us);
-                // Take metrics action after forwarding packets
-                slot_metrics_tracker.apply_action(metrics_action);
+                // get current working bank from bank_forks, use it to sanitize transaction and
+                // load all accounts from address loader;
+                let current_bank = bank_forks.read().unwrap().working_bank();
+                unprocessed_transaction_storage.cache_epoch_boundary_info(&current_bank);
             }
             }
-            _ => (),
+            BufferedPacketsDecision::Hold => {}
         }
         }
     }
     }
 
 
-    fn process_loop<T: LikeClusterInfo>(
+    fn process_loop(
         packet_receiver: &mut PacketReceiver,
         packet_receiver: &mut PacketReceiver,
         decision_maker: &mut DecisionMaker,
         decision_maker: &mut DecisionMaker,
-        forwarder: &mut Forwarder<T>,
+        bank_forks: &RwLock<BankForks>,
         consumer: &Consumer,
         consumer: &Consumer,
         id: u32,
         id: u32,
         mut unprocessed_transaction_storage: UnprocessedTransactionStorage,
         mut unprocessed_transaction_storage: UnprocessedTransactionStorage,
@@ -798,7 +700,7 @@ impl BankingStage {
             {
             {
                 let (_, process_buffered_packets_us) = measure_us!(Self::process_buffered_packets(
                 let (_, process_buffered_packets_us) = measure_us!(Self::process_buffered_packets(
                     decision_maker,
                     decision_maker,
-                    forwarder,
+                    bank_forks,
                     consumer,
                     consumer,
                     &mut unprocessed_transaction_storage,
                     &mut unprocessed_transaction_storage,
                     &banking_stage_stats,
                     &banking_stage_stats,
@@ -949,10 +851,8 @@ mod tests {
             None,
             None,
             replay_vote_sender,
             replay_vote_sender,
             None,
             None,
-            Arc::new(ConnectionCache::new("connection_cache_test")),
             bank_forks,
             bank_forks,
             &Arc::new(PrioritizationFeeCache::new(0u64)),
             &Arc::new(PrioritizationFeeCache::new(0u64)),
-            false,
         );
         );
         drop(non_vote_sender);
         drop(non_vote_sender);
         drop(tpu_vote_sender);
         drop(tpu_vote_sender);
@@ -1008,10 +908,8 @@ mod tests {
             None,
             None,
             replay_vote_sender,
             replay_vote_sender,
             None,
             None,
-            Arc::new(ConnectionCache::new("connection_cache_test")),
             bank_forks,
             bank_forks,
             &Arc::new(PrioritizationFeeCache::new(0u64)),
             &Arc::new(PrioritizationFeeCache::new(0u64)),
-            false,
         );
         );
         trace!("sending bank");
         trace!("sending bank");
         drop(non_vote_sender);
         drop(non_vote_sender);
@@ -1093,10 +991,8 @@ mod tests {
             None,
             None,
             replay_vote_sender,
             replay_vote_sender,
             None,
             None,
-            Arc::new(ConnectionCache::new("connection_cache_test")),
             bank_forks.clone(), // keep a local-copy of bank-forks so worker threads do not lose weak access to bank-forks
             bank_forks.clone(), // keep a local-copy of bank-forks so worker threads do not lose weak access to bank-forks
             &Arc::new(PrioritizationFeeCache::new(0u64)),
             &Arc::new(PrioritizationFeeCache::new(0u64)),
-            false,
         );
         );
 
 
         // fund another account so we can send 2 good transactions in a single batch.
         // fund another account so we can send 2 good transactions in a single batch.
@@ -1265,10 +1161,8 @@ mod tests {
                 None,
                 None,
                 replay_vote_sender,
                 replay_vote_sender,
                 None,
                 None,
-                Arc::new(ConnectionCache::new("connection_cache_test")),
                 bank_forks,
                 bank_forks,
                 &Arc::new(PrioritizationFeeCache::new(0u64)),
                 &Arc::new(PrioritizationFeeCache::new(0u64)),
-                false,
             );
             );
 
 
             // wait for banking_stage to eat the packets
             // wait for banking_stage to eat the packets
@@ -1455,10 +1349,8 @@ mod tests {
             None,
             None,
             replay_vote_sender,
             replay_vote_sender,
             None,
             None,
-            Arc::new(ConnectionCache::new("connection_cache_test")),
             bank_forks,
             bank_forks,
             &Arc::new(PrioritizationFeeCache::new(0u64)),
             &Arc::new(PrioritizationFeeCache::new(0u64)),
-            false,
         );
         );
 
 
         let keypairs = (0..100).map(|_| Keypair::new()).collect_vec();
         let keypairs = (0..100).map(|_| Keypair::new()).collect_vec();

+ 1 - 1
core/src/banking_stage/consumer.rs

@@ -214,7 +214,7 @@ impl Consumer {
             packets_to_process_len.saturating_sub(retryable_transaction_indexes.len());
             packets_to_process_len.saturating_sub(retryable_transaction_indexes.len());
 
 
         // Out of the buffered packets just retried, collect any still unprocessed
         // Out of the buffered packets just retried, collect any still unprocessed
-        // transactions in this batch for forwarding
+        // transactions in this batch
         *rebuffered_packet_count += retryable_transaction_indexes.len();
         *rebuffered_packet_count += retryable_transaction_indexes.len();
 
 
         payload
         payload

+ 0 - 429
core/src/banking_stage/forward_packet_batches_by_accounts.rs

@@ -1,429 +0,0 @@
-use {
-    super::immutable_deserialized_packet::ImmutableDeserializedPacket,
-    core::num::NonZeroU64,
-    solana_cost_model::{
-        block_cost_limits,
-        cost_model::CostModel,
-        cost_tracker::{CostTracker, UpdatedCosts},
-    },
-    solana_feature_set::FeatureSet,
-    solana_perf::packet::Packet,
-    solana_runtime_transaction::transaction_with_meta::TransactionWithMeta,
-    std::sync::Arc,
-};
-
-/// `ForwardBatch` to have half of default cost_tracker limits, as smaller batch
-/// allows better granularity in composing forwarding transactions; e.g.,
-/// transactions in each batch are potentially more evenly distributed across accounts.
-const FORWARDED_BLOCK_COMPUTE_RATIO: u32 = 2;
-/// this number divided by`FORWARDED_BLOCK_COMPUTE_RATIO` is the total blocks to forward.
-/// To accommodate transactions without `compute_budget` instruction, which will
-/// have default 200_000 compute units, it has 100 batches as default to forward
-/// up to 12_000 such transaction. (120 such transactions fill up a batch, 100
-/// batches allows 12_000 transactions)
-const DEFAULT_NUMBER_OF_BATCHES: u32 = 100;
-
-/// `ForwardBatch` represents one forwardable batch of transactions with a
-/// limited number of total compute units
-#[derive(Debug, Default)]
-pub struct ForwardBatch {
-    // `forwardable_packets` keeps forwardable packets in a vector in its
-    // original fee prioritized order
-    forwardable_packets: Vec<Arc<ImmutableDeserializedPacket>>,
-}
-
-impl ForwardBatch {
-    pub fn get_forwardable_packets(&self) -> impl Iterator<Item = &Packet> {
-        self.forwardable_packets
-            .iter()
-            .map(|immutable_packet| immutable_packet.original_packet())
-    }
-
-    pub fn len(&self) -> usize {
-        self.forwardable_packets.len()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.forwardable_packets.is_empty()
-    }
-
-    pub fn reset(&mut self) {
-        self.forwardable_packets.clear();
-    }
-}
-
-/// To avoid forward queue being saturated by transactions for single hot account,
-/// the forwarder will group and send prioritized transactions by account limit
-/// to allow transactions on non-congested accounts to be forwarded alongside higher fee
-/// transactions that saturate those highly demanded accounts.
-#[derive(Debug)]
-pub struct ForwardPacketBatchesByAccounts {
-    // Forwardable packets are staged in number of batches, each batch is limited
-    // by cost_tracker on both account limit and block limits. Those limits are
-    // set as `limit_ratio` of regular block limits to facilitate quicker iteration.
-    forward_batches: Vec<ForwardBatch>,
-
-    // Single cost tracker that imposes the total cu limits for forwarding.
-    cost_tracker: CostTracker,
-
-    // Compute Unit limits for each batch
-    batch_block_limit: NonZeroU64,
-    batch_account_limit: NonZeroU64,
-}
-
-impl ForwardPacketBatchesByAccounts {
-    pub fn new_with_default_batch_limits() -> Self {
-        Self::new(FORWARDED_BLOCK_COMPUTE_RATIO, DEFAULT_NUMBER_OF_BATCHES)
-    }
-
-    pub fn new(limit_ratio: u32, number_of_batches: u32) -> Self {
-        let forward_batches = (0..number_of_batches)
-            .map(|_| ForwardBatch::default())
-            .collect();
-
-        let batch_vote_limit =
-            NonZeroU64::new(block_cost_limits::MAX_VOTE_UNITS.saturating_div(limit_ratio as u64))
-                .expect("batch vote limit must not be zero");
-        let batch_block_limit =
-            NonZeroU64::new(block_cost_limits::MAX_BLOCK_UNITS.saturating_div(limit_ratio as u64))
-                .expect("batch block limit must not be zero");
-        let batch_account_limit = NonZeroU64::new(
-            block_cost_limits::MAX_WRITABLE_ACCOUNT_UNITS.saturating_div(limit_ratio as u64),
-        )
-        .expect("batch account limit must not be zero");
-
-        let mut cost_tracker = CostTracker::default();
-        cost_tracker.set_limits(
-            batch_account_limit
-                .get()
-                .saturating_mul(number_of_batches as u64),
-            batch_block_limit
-                .get()
-                .saturating_mul(number_of_batches as u64),
-            batch_vote_limit
-                .get()
-                .saturating_mul(number_of_batches as u64),
-        );
-        Self {
-            forward_batches,
-            cost_tracker,
-            batch_block_limit,
-            batch_account_limit,
-        }
-    }
-
-    pub fn try_add_packet(
-        &mut self,
-        sanitized_transaction: &impl TransactionWithMeta,
-        immutable_packet: Arc<ImmutableDeserializedPacket>,
-        feature_set: &FeatureSet,
-    ) -> bool {
-        let tx_cost = CostModel::calculate_cost(sanitized_transaction, feature_set);
-
-        if let Ok(updated_costs) = self.cost_tracker.try_add(&tx_cost) {
-            let batch_index = self.get_batch_index_by_updated_costs(&updated_costs);
-
-            if let Some(forward_batch) = self.forward_batches.get_mut(batch_index) {
-                forward_batch.forwardable_packets.push(immutable_packet);
-            } else {
-                // A successfully added tx_cost means it does not exceed block limit, nor vote
-                // limit, nor account limit. batch_index calculated as quotient from division
-                // will not be out of bounds.
-                unreachable!("batch_index out of bounds");
-            }
-            true
-        } else {
-            false
-        }
-    }
-
-    pub fn iter_batches(&self) -> impl Iterator<Item = &ForwardBatch> {
-        self.forward_batches.iter()
-    }
-
-    pub fn reset(&mut self) {
-        for forward_batch in self.forward_batches.iter_mut() {
-            forward_batch.reset();
-        }
-
-        self.cost_tracker.reset();
-    }
-
-    // Successfully added packet should be placed into the batch where no block/vote/account limits
-    // would be exceeded. Eg, if by block limit, it can be put into batch #1; by vote limit, it can
-    // be put into batch #2; and by account limit, it can be put into batch #3; then it should be
-    // put into batch #3 to satisfy all batch limits.
-    fn get_batch_index_by_updated_costs(&self, updated_costs: &UpdatedCosts) -> usize {
-        let batch_index_by_block_cost =
-            updated_costs.updated_block_cost / self.batch_block_limit.get();
-        let batch_index_by_account_limit =
-            updated_costs.updated_costliest_account_cost / self.batch_account_limit.get();
-        batch_index_by_block_cost.max(batch_index_by_account_limit) as usize
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::banking_stage::unprocessed_packet_batches::DeserializedPacket,
-        solana_feature_set::FeatureSet,
-        solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
-        solana_sdk::{
-            compute_budget::ComputeBudgetInstruction,
-            message::Message,
-            pubkey::Pubkey,
-            system_instruction,
-            transaction::{SanitizedTransaction, Transaction},
-        },
-    };
-
-    /// build test transaction, return corresponding sanitized_transaction and deserialized_packet,
-    /// and the batch limit_ratio that would only allow one transaction per bucket.
-    fn build_test_transaction_and_packet(
-        priority: u64,
-        write_to_account: &Pubkey,
-    ) -> (
-        RuntimeTransaction<SanitizedTransaction>,
-        DeserializedPacket,
-        u32,
-    ) {
-        let from_account = solana_pubkey::new_rand();
-
-        let transaction = Transaction::new_unsigned(Message::new(
-            &[
-                ComputeBudgetInstruction::set_compute_unit_price(priority),
-                system_instruction::transfer(&from_account, write_to_account, 2),
-            ],
-            Some(&from_account),
-        ));
-        let sanitized_transaction =
-            RuntimeTransaction::from_transaction_for_tests(transaction.clone());
-        let tx_cost = CostModel::calculate_cost(&sanitized_transaction, &FeatureSet::all_enabled());
-        let cost = tx_cost.sum();
-        let deserialized_packet =
-            DeserializedPacket::new(Packet::from_data(None, transaction).unwrap()).unwrap();
-
-        // set limit ratio so each batch can only have one test transaction
-        let limit_ratio: u32 =
-            ((block_cost_limits::MAX_WRITABLE_ACCOUNT_UNITS - cost + 1) / cost) as u32;
-        (sanitized_transaction, deserialized_packet, limit_ratio)
-    }
-
-    #[test]
-    fn test_try_add_packet_to_multiple_batches() {
-        // setup two transactions, one has high priority that writes to hot account, the
-        // other write to non-contentious account with no priority
-        let hot_account = solana_pubkey::new_rand();
-        let other_account = solana_pubkey::new_rand();
-        let (tx_high_priority, packet_high_priority, limit_ratio) =
-            build_test_transaction_and_packet(10, &hot_account);
-        let (tx_low_priority, packet_low_priority, _) =
-            build_test_transaction_and_packet(0, &other_account);
-
-        // setup forwarding with 2 buckets, each only allow one transaction
-        let number_of_batches = 2;
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new(limit_ratio, number_of_batches);
-
-        // Assert initially both batches are empty
-        {
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(0, batches.next().unwrap().len());
-            assert_eq!(0, batches.next().unwrap().len());
-            assert!(batches.next().is_none());
-        }
-
-        // Assert one high-priority packet will be added to 1st bucket successfully
-        {
-            assert!(forward_packet_batches_by_accounts.try_add_packet(
-                &tx_high_priority,
-                packet_high_priority.immutable_section().clone(),
-                &FeatureSet::all_enabled(),
-            ));
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(1, batches.next().unwrap().len());
-            assert_eq!(0, batches.next().unwrap().len());
-            assert!(batches.next().is_none());
-        }
-
-        // Assert second high-priority packet will not fit in first bucket, but will
-        // be added to 2nd bucket
-        {
-            assert!(forward_packet_batches_by_accounts.try_add_packet(
-                &tx_high_priority,
-                packet_high_priority.immutable_section().clone(),
-                &FeatureSet::all_enabled(),
-            ));
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(1, batches.next().unwrap().len());
-            assert_eq!(1, batches.next().unwrap().len());
-        }
-
-        // Assert 3rd high-priority packet can not added since both buckets would
-        // exceed hot-account limit
-        {
-            assert!(!forward_packet_batches_by_accounts.try_add_packet(
-                &tx_high_priority,
-                packet_high_priority.immutable_section().clone(),
-                &FeatureSet::all_enabled(),
-            ));
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(1, batches.next().unwrap().len());
-            assert_eq!(1, batches.next().unwrap().len());
-            assert!(batches.next().is_none());
-        }
-
-        // Assert lower priority packet will be successfully added to first bucket
-        // since non-contentious account is still free
-        {
-            assert!(forward_packet_batches_by_accounts.try_add_packet(
-                &tx_low_priority,
-                packet_low_priority.immutable_section().clone(),
-                &FeatureSet::all_enabled(),
-            ));
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(2, batches.next().unwrap().len());
-            assert_eq!(1, batches.next().unwrap().len());
-            assert!(batches.next().is_none());
-        }
-    }
-
-    #[test]
-    fn test_try_add_packet_to_single_batch() {
-        let (tx, packet, limit_ratio) =
-            build_test_transaction_and_packet(10, &solana_pubkey::new_rand());
-        let number_of_batches = 1;
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new(limit_ratio, number_of_batches);
-
-        // Assert initially batch is empty, and accepting new packets
-        {
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(0, batches.next().unwrap().len());
-            assert!(batches.next().is_none());
-        }
-
-        // Assert can successfully add first packet to forwarding buffer
-        {
-            assert!(forward_packet_batches_by_accounts.try_add_packet(
-                &tx,
-                packet.immutable_section().clone(),
-                &FeatureSet::all_enabled()
-            ));
-
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(1, batches.next().unwrap().len());
-        }
-
-        // Assert cannot add same packet to forwarding buffer again, due to reached account limit;
-        {
-            assert!(!forward_packet_batches_by_accounts.try_add_packet(
-                &tx,
-                packet.immutable_section().clone(),
-                &FeatureSet::all_enabled()
-            ));
-
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(1, batches.next().unwrap().len());
-        }
-
-        // Assert can still add non-contentious packet to same batch
-        {
-            // build a small packet to a non-contentious account with high priority
-            let (tx2, packet2, _) =
-                build_test_transaction_and_packet(100, &solana_pubkey::new_rand());
-
-            assert!(forward_packet_batches_by_accounts.try_add_packet(
-                &tx2,
-                packet2.immutable_section().clone(),
-                &FeatureSet::all_enabled()
-            ));
-
-            let mut batches = forward_packet_batches_by_accounts.iter_batches();
-            assert_eq!(2, batches.next().unwrap().len());
-        }
-    }
-
-    #[test]
-    fn test_get_batch_index_by_updated_costs() {
-        let test_cost = 99;
-
-        // check against block limit only
-        {
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-            forward_packet_batches_by_accounts.batch_block_limit =
-                NonZeroU64::new(test_cost + 1).unwrap();
-
-            assert_eq!(
-                0,
-                forward_packet_batches_by_accounts.get_batch_index_by_updated_costs(
-                    &UpdatedCosts {
-                        updated_block_cost: test_cost,
-                        updated_costliest_account_cost: 0
-                    }
-                )
-            );
-            assert_eq!(
-                1,
-                forward_packet_batches_by_accounts.get_batch_index_by_updated_costs(
-                    &UpdatedCosts {
-                        updated_block_cost: test_cost + 1,
-                        updated_costliest_account_cost: 0
-                    }
-                )
-            );
-        }
-
-        // check against account limit only
-        {
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-            forward_packet_batches_by_accounts.batch_account_limit =
-                NonZeroU64::new(test_cost + 1).unwrap();
-
-            assert_eq!(
-                0,
-                forward_packet_batches_by_accounts.get_batch_index_by_updated_costs(
-                    &UpdatedCosts {
-                        updated_block_cost: 0,
-                        updated_costliest_account_cost: test_cost
-                    }
-                )
-            );
-            assert_eq!(
-                1,
-                forward_packet_batches_by_accounts.get_batch_index_by_updated_costs(
-                    &UpdatedCosts {
-                        updated_block_cost: 0,
-                        updated_costliest_account_cost: test_cost + 1
-                    }
-                )
-            );
-        }
-
-        // by block limit, it can be put into batch #1;
-        // by vote limit, it can be put into batch #2;
-        // by account limit, it can be put into batch #3;
-        // it should be put into batch #3 to satisfy all batch limits.
-        {
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-            forward_packet_batches_by_accounts.batch_block_limit =
-                NonZeroU64::new(test_cost + 1).unwrap();
-            forward_packet_batches_by_accounts.batch_account_limit =
-                NonZeroU64::new(test_cost / 3 + 1).unwrap();
-
-            assert_eq!(
-                2,
-                forward_packet_batches_by_accounts.get_batch_index_by_updated_costs(
-                    &UpdatedCosts {
-                        updated_block_cost: test_cost,
-                        updated_costliest_account_cost: test_cost
-                    }
-                )
-            );
-        }
-    }
-}

+ 0 - 592
core/src/banking_stage/forwarder.rs

@@ -1,592 +0,0 @@
-use {
-    super::{
-        forward_packet_batches_by_accounts::ForwardPacketBatchesByAccounts,
-        leader_slot_metrics::LeaderSlotMetricsTracker,
-        unprocessed_transaction_storage::UnprocessedTransactionStorage, BankingStageStats,
-        ForwardOption,
-    },
-    crate::{
-        banking_stage::{
-            immutable_deserialized_packet::ImmutableDeserializedPacket, LikeClusterInfo,
-        },
-        next_leader::{next_leader, next_leader_tpu_vote},
-    },
-    solana_client::connection_cache::ConnectionCache,
-    solana_connection_cache::client_connection::ClientConnection as TpuConnection,
-    solana_feature_set::FeatureSet,
-    solana_measure::measure_us,
-    solana_net_utils::bind_to_unspecified,
-    solana_perf::{data_budget::DataBudget, packet::Packet},
-    solana_poh::poh_recorder::PohRecorder,
-    solana_runtime::bank_forks::BankForks,
-    solana_runtime_transaction::transaction_with_meta::TransactionWithMeta,
-    solana_sdk::{pubkey::Pubkey, transport::TransportError},
-    solana_streamer::sendmmsg::batch_send,
-    std::{
-        net::{SocketAddr, UdpSocket},
-        sync::{atomic::Ordering, Arc, RwLock},
-    },
-};
-
-pub struct Forwarder<T: LikeClusterInfo> {
-    poh_recorder: Arc<RwLock<PohRecorder>>,
-    bank_forks: Arc<RwLock<BankForks>>,
-    socket: UdpSocket,
-    cluster_info: T,
-    connection_cache: Arc<ConnectionCache>,
-    data_budget: Arc<DataBudget>,
-    forward_packet_batches_by_accounts: ForwardPacketBatchesByAccounts,
-}
-
-impl<T: LikeClusterInfo> Forwarder<T> {
-    pub fn new(
-        poh_recorder: Arc<RwLock<PohRecorder>>,
-        bank_forks: Arc<RwLock<BankForks>>,
-        cluster_info: T,
-        connection_cache: Arc<ConnectionCache>,
-        data_budget: Arc<DataBudget>,
-    ) -> Self {
-        Self {
-            poh_recorder,
-            bank_forks,
-            socket: bind_to_unspecified().unwrap(),
-            cluster_info,
-            connection_cache,
-            data_budget,
-            forward_packet_batches_by_accounts:
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits(),
-        }
-    }
-
-    pub fn clear_batches(&mut self) {
-        self.forward_packet_batches_by_accounts.reset();
-    }
-
-    pub fn try_add_packet(
-        &mut self,
-        sanitized_transaction: &impl TransactionWithMeta,
-        immutable_packet: Arc<ImmutableDeserializedPacket>,
-        feature_set: &FeatureSet,
-    ) -> bool {
-        self.forward_packet_batches_by_accounts.try_add_packet(
-            sanitized_transaction,
-            immutable_packet,
-            feature_set,
-        )
-    }
-
-    pub fn forward_batched_packets(&self, forward_option: &ForwardOption) {
-        self.forward_packet_batches_by_accounts
-            .iter_batches()
-            .filter(|&batch| !batch.is_empty())
-            .for_each(|forwardable_batch| {
-                let _ = self
-                    .forward_packets(forward_option, forwardable_batch.get_forwardable_packets());
-            });
-    }
-
-    /// This function is exclusively used by multi-iterator banking threads to handle forwarding
-    /// logic per thread. Central scheduler Controller uses try_add_packet() ... forward_batched_packets()
-    /// to handle forwarding slight differently.
-    pub fn handle_forwarding(
-        &mut self,
-        unprocessed_transaction_storage: &mut UnprocessedTransactionStorage,
-        hold: bool,
-        slot_metrics_tracker: &mut LeaderSlotMetricsTracker,
-        banking_stage_stats: &BankingStageStats,
-    ) {
-        let forward_option = unprocessed_transaction_storage.forward_option();
-
-        // get current working bank from bank_forks, use it to sanitize transaction and
-        // load all accounts from address loader;
-        let current_bank = self.bank_forks.read().unwrap().working_bank();
-
-        // if we have crossed an epoch boundary, recache any state
-        unprocessed_transaction_storage.cache_epoch_boundary_info(&current_bank);
-
-        // sanitize and filter packets that are no longer valid (could be too old, a duplicate of something
-        // already processed), then add to forwarding buffer.
-        let filter_forwarding_result = unprocessed_transaction_storage
-            .filter_forwardable_packets_and_add_batches(
-                current_bank,
-                &mut self.forward_packet_batches_by_accounts,
-            );
-        slot_metrics_tracker.increment_transactions_from_packets_us(
-            filter_forwarding_result.total_packet_conversion_us,
-        );
-        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,
-            );
-        banking_stage_stats.dropped_forward_packets_count.fetch_add(
-            filter_forwarding_result.total_dropped_packets,
-            Ordering::Relaxed,
-        );
-
-        self.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, successful_forwarded_packets_count, _leader_pubkey) = self
-                    .forward_buffered_packets(
-                        &forward_option,
-                        forward_batch.get_forwardable_packets(),
-                        banking_stage_stats,
-                    );
-
-                let failed_forwarded_packets_count = batched_forwardable_packets_count
-                    .saturating_sub(successful_forwarded_packets_count);
-
-                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 successful_forwarded_packets_count > 0 {
-                    slot_metrics_tracker.increment_successful_forwarded_packets_count(
-                        successful_forwarded_packets_count as u64,
-                    );
-                }
-            });
-        self.clear_batches();
-
-        if !hold {
-            slot_metrics_tracker.increment_cleared_from_buffer_after_forward_count(
-                filter_forwarding_result.total_forwardable_packets as u64,
-            );
-            unprocessed_transaction_storage.clear_forwarded_packets();
-        }
-    }
-
-    /// Forwards all valid, unprocessed packets in the iterator, up to a rate limit.
-    /// Returns whether forwarding succeeded, the number of attempted forwarded packets
-    /// if any, the time spent forwarding in us, and the leader pubkey if any.
-    pub fn forward_packets<'a>(
-        &self,
-        forward_option: &ForwardOption,
-        forwardable_packets: impl Iterator<Item = &'a Packet>,
-    ) -> (
-        std::result::Result<(), TransportError>,
-        usize,
-        u64,
-        Option<Pubkey>,
-    ) {
-        let Some((leader_pubkey, addr)) = self.get_leader_and_addr(forward_option) else {
-            return (Ok(()), 0, 0, None);
-        };
-
-        self.update_data_budget();
-        let packet_vec: Vec<_> = forwardable_packets
-            .filter(|p| !p.meta().forwarded())
-            .filter(|p| p.meta().is_from_staked_node())
-            .filter(|p| self.data_budget.take(p.meta().size))
-            .filter_map(|p| p.data(..).map(|data| data.to_vec()))
-            .collect();
-
-        let packet_vec_len = packet_vec.len();
-        // 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
-        let (res, forward_us) = if !packet_vec.is_empty() {
-            measure_us!(self.forward(forward_option, packet_vec, &addr))
-        } else {
-            (Ok(()), 0)
-        };
-
-        (res, packet_vec_len, forward_us, Some(leader_pubkey))
-    }
-
-    /// 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
-    fn forward_buffered_packets<'a>(
-        &self,
-        forward_option: &ForwardOption,
-        forwardable_packets: impl Iterator<Item = &'a Packet>,
-        banking_stage_stats: &BankingStageStats,
-    ) -> (
-        std::result::Result<(), TransportError>,
-        usize,
-        Option<Pubkey>,
-    ) {
-        let (res, num_packets, _forward_us, leader_pubkey) =
-            self.forward_packets(forward_option, forwardable_packets);
-        if let Err(ref err) = res {
-            warn!("failed to forward packets: {err}");
-        }
-
-        if num_packets > 0 {
-            if let ForwardOption::ForwardTpuVote = forward_option {
-                banking_stage_stats
-                    .forwarded_vote_count
-                    .fetch_add(num_packets, Ordering::Relaxed);
-            } else {
-                banking_stage_stats
-                    .forwarded_transaction_count
-                    .fetch_add(num_packets, Ordering::Relaxed);
-            }
-        }
-
-        (res, num_packets, leader_pubkey)
-    }
-
-    /// Get the pubkey and socket address for the leader to forward to
-    fn get_leader_and_addr(&self, forward_option: &ForwardOption) -> Option<(Pubkey, SocketAddr)> {
-        match forward_option {
-            ForwardOption::NotForward => None,
-            ForwardOption::ForwardTransaction => {
-                next_leader(&self.cluster_info, &self.poh_recorder, |node| {
-                    node.tpu_forwards(self.connection_cache.protocol())
-                })
-            }
-            ForwardOption::ForwardTpuVote => {
-                next_leader_tpu_vote(&self.cluster_info, &self.poh_recorder)
-            }
-        }
-    }
-
-    /// Re-fill the data budget if enough time has passed
-    fn update_data_budget(&self) {
-        const INTERVAL_MS: u64 = 100;
-        // 12 MB outbound limit per second
-        const MAX_BYTES_PER_SECOND: usize = 12_000_000;
-        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;
-        self.data_budget.update(INTERVAL_MS, |bytes| {
-            std::cmp::min(
-                bytes.saturating_add(MAX_BYTES_PER_INTERVAL),
-                MAX_BYTES_BUDGET,
-            )
-        });
-    }
-
-    fn forward(
-        &self,
-        forward_option: &ForwardOption,
-        packet_vec: Vec<Vec<u8>>,
-        addr: &SocketAddr,
-    ) -> Result<(), TransportError> {
-        match forward_option {
-            ForwardOption::ForwardTpuVote => {
-                // The vote must be forwarded using only UDP.
-                let pkts = packet_vec.iter().map(|pkt| (pkt, addr));
-                batch_send(&self.socket, pkts).map_err(TransportError::from)
-            }
-            ForwardOption::ForwardTransaction => {
-                let conn = self.connection_cache.get_connection(addr);
-                conn.send_data_batch_async(packet_vec)
-            }
-            ForwardOption::NotForward => panic!("should not forward"),
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::banking_stage::{
-            tests::{create_slow_genesis_config_with_leader, new_test_cluster_info},
-            unprocessed_packet_batches::{DeserializedPacket, UnprocessedPacketBatches},
-            unprocessed_transaction_storage::ThreadType,
-        },
-        solana_client::rpc_client::SerializableTransaction,
-        solana_gossip::cluster_info::{ClusterInfo, Node},
-        solana_ledger::{blockstore::Blockstore, genesis_utils::GenesisConfigInfo},
-        solana_perf::packet::PacketFlags,
-        solana_poh::{poh_recorder::create_test_recorder, poh_service::PohService},
-        solana_runtime::bank::Bank,
-        solana_sdk::{
-            hash::Hash, poh_config::PohConfig, signature::Keypair, signer::Signer,
-            system_transaction, transaction::VersionedTransaction,
-        },
-        solana_streamer::{
-            nonblocking::testing_utilities::{
-                setup_quic_server_with_sockets, SpawnTestServerResult, TestServerConfig,
-            },
-            quic::rt,
-        },
-        std::{
-            sync::atomic::AtomicBool,
-            time::{Duration, Instant},
-        },
-        tempfile::TempDir,
-        tokio::time::sleep,
-    };
-
-    struct TestSetup {
-        _ledger_dir: TempDir,
-        blockhash: Hash,
-        rent_min_balance: u64,
-
-        bank_forks: Arc<RwLock<BankForks>>,
-        poh_recorder: Arc<RwLock<PohRecorder>>,
-        exit: Arc<AtomicBool>,
-        poh_service: PohService,
-        cluster_info: Arc<ClusterInfo>,
-        local_node: Node,
-    }
-
-    fn setup() -> TestSetup {
-        let validator_keypair = Arc::new(Keypair::new());
-        let genesis_config_info =
-            create_slow_genesis_config_with_leader(10_000, &validator_keypair.pubkey());
-        let GenesisConfigInfo { genesis_config, .. } = &genesis_config_info;
-
-        let (bank, bank_forks) = Bank::new_no_wallclock_throttle_for_tests(genesis_config);
-
-        let ledger_path = TempDir::new().unwrap();
-        let blockstore = Arc::new(
-            Blockstore::open(ledger_path.as_ref())
-                .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 (local_node, cluster_info) = new_test_cluster_info(Some(validator_keypair));
-        let cluster_info = Arc::new(cluster_info);
-
-        TestSetup {
-            _ledger_dir: ledger_path,
-            blockhash: genesis_config.hash(),
-            rent_min_balance: genesis_config.rent.minimum_balance(0),
-
-            bank_forks,
-            poh_recorder,
-            exit,
-            poh_service,
-            cluster_info,
-            local_node,
-        }
-    }
-
-    async fn check_all_received(
-        socket: UdpSocket,
-        expected_num_packets: usize,
-        expected_packet_size: usize,
-        expected_blockhash: &Hash,
-    ) {
-        let SpawnTestServerResult {
-            join_handle,
-            exit,
-            receiver,
-            server_address: _,
-            stats: _,
-        } = setup_quic_server_with_sockets(vec![socket], None, TestServerConfig::default());
-
-        let now = Instant::now();
-        let mut total_packets = 0;
-        while now.elapsed().as_secs() < 5 {
-            if let Ok(packets) = receiver.try_recv() {
-                total_packets += packets.len();
-                for packet in packets.iter() {
-                    assert_eq!(packet.meta().size, expected_packet_size);
-                    let tx: VersionedTransaction = packet.deserialize_slice(..).unwrap();
-                    assert_eq!(
-                        tx.get_recent_blockhash(),
-                        expected_blockhash,
-                        "Unexpected blockhash, tx: {tx:?}, expected blockhash: {expected_blockhash}."
-                    );
-                }
-            } else {
-                sleep(Duration::from_millis(100)).await;
-            }
-            if total_packets >= expected_num_packets {
-                break;
-            }
-        }
-        assert_eq!(total_packets, expected_num_packets);
-
-        exit.store(true, Ordering::Relaxed);
-        join_handle.await.unwrap();
-    }
-
-    #[test]
-    fn test_forwarder_budget() {
-        let TestSetup {
-            blockhash,
-            rent_min_balance,
-            bank_forks,
-            poh_recorder,
-            exit,
-            poh_service,
-            cluster_info,
-            local_node,
-            ..
-        } = setup();
-
-        // Create `PacketBatch` with 1 unprocessed packet
-        let tx = system_transaction::transfer(
-            &Keypair::new(),
-            &solana_pubkey::new_rand(),
-            rent_min_balance,
-            blockhash,
-        );
-        let mut packet = Packet::from_data(None, tx).unwrap();
-        // unstaked transactions will not be forwarded
-        packet.meta_mut().set_from_staked_node(true);
-        let expected_packet_size = packet.meta().size;
-        let deserialized_packet = DeserializedPacket::new(packet).unwrap();
-
-        let test_cases = vec![
-            ("budget-restricted", DataBudget::restricted(), 0),
-            ("budget-available", DataBudget::default(), 1),
-        ];
-        let runtime = rt("solQuicTestRt".to_string());
-        for (_name, data_budget, expected_num_forwarded) in test_cases {
-            let mut forwarder = Forwarder::new(
-                poh_recorder.clone(),
-                bank_forks.clone(),
-                cluster_info.clone(),
-                Arc::new(ConnectionCache::new("connection_cache_test")),
-                Arc::new(data_budget),
-            );
-            let unprocessed_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(
-                    vec![deserialized_packet.clone()].into_iter(),
-                    1,
-                );
-            let stats = BankingStageStats::default();
-            forwarder.handle_forwarding(
-                &mut UnprocessedTransactionStorage::new_transaction_storage(
-                    unprocessed_packet_batches,
-                    ThreadType::Transactions,
-                ),
-                true,
-                &mut LeaderSlotMetricsTracker::new(0),
-                &stats,
-            );
-
-            let recv_socket = &local_node.sockets.tpu_forwards_quic[0];
-            runtime.block_on(check_all_received(
-                (*recv_socket).try_clone().unwrap(),
-                expected_num_forwarded,
-                expected_packet_size,
-                &blockhash,
-            ));
-        }
-
-        exit.store(true, Ordering::Relaxed);
-        poh_service.join().unwrap();
-    }
-
-    #[test]
-    fn test_handle_forwarding() {
-        let TestSetup {
-            blockhash,
-            rent_min_balance,
-            bank_forks,
-            poh_recorder,
-            exit,
-            poh_service,
-            cluster_info,
-            local_node,
-            ..
-        } = setup();
-
-        let keypair = Keypair::new();
-        let pubkey = solana_pubkey::new_rand();
-
-        // forwarded packets will not be forwarded again
-        let forwarded_packet = {
-            let transaction =
-                system_transaction::transfer(&keypair, &pubkey, rent_min_balance, blockhash);
-            let mut packet = Packet::from_data(None, transaction).unwrap();
-            packet.meta_mut().flags |= PacketFlags::FORWARDED;
-            DeserializedPacket::new(packet).unwrap()
-        };
-        // packets from unstaked nodes will not be forwarded
-        let unstaked_packet = {
-            let transaction =
-                system_transaction::transfer(&keypair, &pubkey, rent_min_balance, blockhash);
-            let packet = Packet::from_data(None, transaction).unwrap();
-            DeserializedPacket::new(packet).unwrap()
-        };
-        // packets with incorrect blockhash will be filtered out
-        let incorrect_blockhash_packet = {
-            let transaction =
-                system_transaction::transfer(&keypair, &pubkey, rent_min_balance, Hash::default());
-            let packet = Packet::from_data(None, transaction).unwrap();
-            DeserializedPacket::new(packet).unwrap()
-        };
-
-        // maybe also add packet without stake and packet with incorrect blockhash?
-        let (expected_packet_size, normal_packet) = {
-            let transaction = system_transaction::transfer(&keypair, &pubkey, 1, blockhash);
-            let mut packet = Packet::from_data(None, transaction).unwrap();
-            packet.meta_mut().set_from_staked_node(true);
-            (packet.meta().size, DeserializedPacket::new(packet).unwrap())
-        };
-
-        let mut unprocessed_packet_batches = UnprocessedTransactionStorage::new_transaction_storage(
-            UnprocessedPacketBatches::from_iter(
-                vec![
-                    forwarded_packet,
-                    unstaked_packet,
-                    incorrect_blockhash_packet,
-                    normal_packet,
-                ],
-                4,
-            ),
-            ThreadType::Transactions,
-        );
-        let connection_cache = ConnectionCache::new("connection_cache_test");
-
-        let test_cases = vec![
-            ("fwd-normal", true, 2, 1),
-            ("fwd-no-op", true, 2, 0),
-            ("fwd-no-hold", false, 0, 0),
-        ];
-
-        let mut forwarder = Forwarder::new(
-            poh_recorder,
-            bank_forks,
-            cluster_info,
-            Arc::new(connection_cache),
-            Arc::new(DataBudget::default()),
-        );
-        let runtime = rt("solQuicTestRt".to_string());
-        for (name, hold, expected_num_unprocessed, expected_num_processed) in test_cases {
-            let stats = BankingStageStats::default();
-            forwarder.handle_forwarding(
-                &mut unprocessed_packet_batches,
-                hold,
-                &mut LeaderSlotMetricsTracker::new(0),
-                &stats,
-            );
-
-            let recv_socket = &local_node.sockets.tpu_forwards_quic[0];
-
-            runtime.block_on(check_all_received(
-                (*recv_socket).try_clone().unwrap(),
-                expected_num_processed,
-                expected_packet_size,
-                &blockhash,
-            ));
-
-            let num_unprocessed_packets: usize = unprocessed_packet_batches.len();
-            assert_eq!(num_unprocessed_packets, expected_num_unprocessed, "{name}");
-        }
-
-        exit.store(true, Ordering::Relaxed);
-        poh_service.join().unwrap();
-    }
-}

+ 8 - 193
core/src/banking_stage/latest_unprocessed_votes.rs

@@ -1,8 +1,5 @@
 use {
 use {
-    super::{
-        forward_packet_batches_by_accounts::ForwardPacketBatchesByAccounts,
-        immutable_deserialized_packet::{DeserializedPacketError, ImmutableDeserializedPacket},
-    },
+    super::immutable_deserialized_packet::{DeserializedPacketError, ImmutableDeserializedPacket},
     itertools::Itertools,
     itertools::Itertools,
     rand::{thread_rng, Rng},
     rand::{thread_rng, Rng},
     solana_perf::packet::Packet,
     solana_perf::packet::Packet,
@@ -35,7 +32,7 @@ pub enum VoteSource {
     Tpu,
     Tpu,
 }
 }
 
 
-/// Holds deserialized vote messages as well as their source, forward status and slot
+/// Holds deserialized vote messages as well as their source, and slot
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
 pub struct LatestValidatorVotePacket {
 pub struct LatestValidatorVotePacket {
     vote_source: VoteSource,
     vote_source: VoteSource,
@@ -43,7 +40,6 @@ pub struct LatestValidatorVotePacket {
     vote: Option<Arc<ImmutableDeserializedPacket>>,
     vote: Option<Arc<ImmutableDeserializedPacket>>,
     slot: Slot,
     slot: Slot,
     hash: Hash,
     hash: Hash,
-    forwarded: bool,
     timestamp: Option<UnixTimestamp>,
     timestamp: Option<UnixTimestamp>,
 }
 }
 
 
@@ -108,7 +104,6 @@ impl LatestValidatorVotePacket {
                     hash,
                     hash,
                     vote_pubkey,
                     vote_pubkey,
                     vote_source,
                     vote_source,
-                    forwarded: false,
                     timestamp,
                     timestamp,
                 })
                 })
             }
             }
@@ -136,11 +131,6 @@ impl LatestValidatorVotePacket {
         self.timestamp
         self.timestamp
     }
     }
 
 
-    pub fn is_forwarded(&self) -> bool {
-        // By definition all gossip votes have been forwarded
-        self.forwarded || matches!(self.vote_source, VoteSource::Gossip)
-    }
-
     pub fn is_vote_taken(&self) -> bool {
     pub fn is_vote_taken(&self) -> bool {
         self.vote.is_none()
         self.vote.is_none()
     }
     }
@@ -399,57 +389,6 @@ impl LatestUnprocessedVotes {
         );
         );
     }
     }
 
 
-    /// Returns how many packets were forwardable
-    /// Performs a weighted random order based on stake and stops forwarding at the first error
-    /// Votes from validators with 0 stakes are ignored
-    pub fn get_and_insert_forwardable_packets(
-        &self,
-        bank: Arc<Bank>,
-        forward_packet_batches_by_accounts: &mut ForwardPacketBatchesByAccounts,
-    ) -> usize {
-        let pubkeys_by_stake = self.weighted_random_order_by_stake();
-        let mut forwarded_count: usize = 0;
-        for pubkey in pubkeys_by_stake {
-            let Some(vote) = self.get_entry(pubkey) else {
-                continue;
-            };
-
-            let mut vote = vote.write().unwrap();
-            if vote.is_vote_taken() || vote.is_forwarded() {
-                continue;
-            }
-
-            let deserialized_vote_packet = vote.vote.as_ref().unwrap().clone();
-            let Some((sanitized_vote_transaction, _deactivation_slot)) = deserialized_vote_packet
-                .build_sanitized_transaction(
-                    bank.vote_only_bank(),
-                    bank.as_ref(),
-                    bank.get_reserved_account_keys(),
-                )
-            else {
-                continue;
-            };
-
-            let forwarding_successful = forward_packet_batches_by_accounts.try_add_packet(
-                &sanitized_vote_transaction,
-                deserialized_vote_packet,
-                &bank.feature_set,
-            );
-
-            if !forwarding_successful {
-                // To match behavior of regular transactions we stop forwarding votes as soon as one
-                // fails. We are assuming that failure (try_add_packet) means no more space
-                // available.
-                break;
-            }
-
-            vote.forwarded = true;
-            forwarded_count += 1;
-        }
-
-        forwarded_count
-    }
-
     /// Drains all votes yet to be processed sorted by a weighted random ordering by stake
     /// Drains all votes yet to be processed sorted by a weighted random ordering by stake
     /// Do not touch votes that are for a different fork from `bank` as we know they will fail,
     /// Do not touch votes that are for a different fork from `bank` as we know they will fail,
     /// however the next bank could be built on a different fork and consume these votes.
     /// however the next bank could be built on a different fork and consume these votes.
@@ -495,17 +434,14 @@ impl LatestUnprocessedVotes {
             .unwrap_or(false)
             .unwrap_or(false)
     }
     }
 
 
-    /// Sometimes we forward and hold the packets, sometimes we forward and clear.
-    /// This also clears all gossip votes since by definition they have been forwarded
-    pub fn clear_forwarded_packets(&self) {
+    pub fn clear(&self) {
         self.latest_vote_per_vote_pubkey
         self.latest_vote_per_vote_pubkey
             .read()
             .read()
             .unwrap()
             .unwrap()
             .values()
             .values()
-            .filter(|lock| lock.read().unwrap().is_forwarded())
             .for_each(|lock| {
             .for_each(|lock| {
                 let mut vote = lock.write().unwrap();
                 let mut vote = lock.write().unwrap();
-                if vote.is_forwarded() && vote.take_vote().is_some() {
+                if vote.take_vote().is_some() {
                     self.num_unprocessed_votes.fetch_sub(1, Ordering::Relaxed);
                     self.num_unprocessed_votes.fetch_sub(1, Ordering::Relaxed);
                 }
                 }
             });
             });
@@ -525,7 +461,6 @@ mod tests {
         solana_perf::packet::{Packet, PacketBatch, PacketFlags},
         solana_perf::packet::{Packet, PacketBatch, PacketFlags},
         solana_runtime::{
         solana_runtime::{
             bank::Bank,
             bank::Bank,
-            epoch_stakes::EpochStakes,
             genesis_utils::{self, ValidatorVoteKeypairs},
             genesis_utils::{self, ValidatorVoteKeypairs},
         },
         },
         solana_sdk::{
         solana_sdk::{
@@ -966,126 +901,7 @@ mod tests {
     }
     }
 
 
     #[test]
     #[test]
-    fn test_forwardable_packets() {
-        let latest_unprocessed_votes = LatestUnprocessedVotes::new_for_tests(&[]);
-        let bank_0 = Bank::new_for_tests(&GenesisConfig::default());
-        let mut bank = Bank::new_from_parent(
-            Arc::new(bank_0),
-            &Pubkey::new_unique(),
-            MINIMUM_SLOTS_PER_EPOCH,
-        );
-        assert_eq!(bank.epoch(), 1);
-        bank.set_epoch_stakes_for_test(
-            bank.epoch().saturating_add(2),
-            EpochStakes::new_for_tests(HashMap::new(), bank.epoch().saturating_add(2)),
-        );
-        let bank = Arc::new(bank);
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-
-        let keypair_a = ValidatorVoteKeypairs::new_rand();
-        let keypair_b = ValidatorVoteKeypairs::new_rand();
-
-        let vote_a = from_slots(vec![(1, 1)], VoteSource::Gossip, &keypair_a, None);
-        let vote_b = from_slots(vec![(2, 1)], VoteSource::Tpu, &keypair_b, None);
-        latest_unprocessed_votes
-            .update_latest_vote(vote_a.clone(), false /* should replenish */);
-        latest_unprocessed_votes
-            .update_latest_vote(vote_b.clone(), false /* should replenish */);
-
-        // Recache on epoch boundary and don't forward 0 stake accounts
-        latest_unprocessed_votes.cache_epoch_boundary_info(&bank);
-        let forwarded = latest_unprocessed_votes
-            .get_and_insert_forwardable_packets(bank, &mut forward_packet_batches_by_accounts);
-        assert_eq!(0, forwarded);
-        assert_eq!(
-            0,
-            forward_packet_batches_by_accounts
-                .iter_batches()
-                .filter(|&batch| !batch.is_empty())
-                .count()
-        );
-
-        let config =
-            genesis_utils::create_genesis_config_with_vote_accounts(100, &[keypair_a], vec![200])
-                .genesis_config;
-        let bank_0 = Bank::new_for_tests(&config);
-        let bank = Bank::new_from_parent(
-            Arc::new(bank_0),
-            &Pubkey::new_unique(),
-            2 * MINIMUM_SLOTS_PER_EPOCH,
-        );
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-
-        // Don't forward votes from gossip
-        latest_unprocessed_votes.cache_epoch_boundary_info(&bank);
-        latest_unprocessed_votes
-            .update_latest_vote(vote_a.clone(), false /* should replenish */);
-        latest_unprocessed_votes
-            .update_latest_vote(vote_b.clone(), false /* should replenish */);
-        let forwarded = latest_unprocessed_votes.get_and_insert_forwardable_packets(
-            Arc::new(bank),
-            &mut forward_packet_batches_by_accounts,
-        );
-
-        assert_eq!(0, forwarded);
-        assert_eq!(
-            0,
-            forward_packet_batches_by_accounts
-                .iter_batches()
-                .filter(|&batch| !batch.is_empty())
-                .count()
-        );
-
-        let config =
-            genesis_utils::create_genesis_config_with_vote_accounts(100, &[keypair_b], vec![200])
-                .genesis_config;
-        let bank_0 = Bank::new_for_tests(&config);
-        let bank = Arc::new(Bank::new_from_parent(
-            Arc::new(bank_0),
-            &Pubkey::new_unique(),
-            3 * MINIMUM_SLOTS_PER_EPOCH,
-        ));
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-
-        // Forward from TPU
-        latest_unprocessed_votes.cache_epoch_boundary_info(&bank);
-        latest_unprocessed_votes.update_latest_vote(vote_a, false /* should replenish */);
-        latest_unprocessed_votes.update_latest_vote(vote_b, false /* should replenish */);
-        let forwarded = latest_unprocessed_votes.get_and_insert_forwardable_packets(
-            bank.clone(),
-            &mut forward_packet_batches_by_accounts,
-        );
-
-        assert_eq!(1, forwarded);
-        assert_eq!(
-            1,
-            forward_packet_batches_by_accounts
-                .iter_batches()
-                .filter(|&batch| !batch.is_empty())
-                .count()
-        );
-
-        // Don't forward again
-        let mut forward_packet_batches_by_accounts =
-            ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-        let forwarded = latest_unprocessed_votes
-            .get_and_insert_forwardable_packets(bank, &mut forward_packet_batches_by_accounts);
-
-        assert_eq!(0, forwarded);
-        assert_eq!(
-            0,
-            forward_packet_batches_by_accounts
-                .iter_batches()
-                .filter(|&batch| !batch.is_empty())
-                .count()
-        );
-    }
-
-    #[test]
-    fn test_clear_forwarded_packets() {
+    fn test_clear() {
         let keypair_a = ValidatorVoteKeypairs::new_rand();
         let keypair_a = ValidatorVoteKeypairs::new_rand();
         let keypair_b = ValidatorVoteKeypairs::new_rand();
         let keypair_b = ValidatorVoteKeypairs::new_rand();
         let keypair_c = ValidatorVoteKeypairs::new_rand();
         let keypair_c = ValidatorVoteKeypairs::new_rand();
@@ -1098,8 +914,7 @@ mod tests {
         ]);
         ]);
 
 
         let vote_a = from_slots(vec![(1, 1)], VoteSource::Gossip, &keypair_a, None);
         let vote_a = from_slots(vec![(1, 1)], VoteSource::Gossip, &keypair_a, None);
-        let mut vote_b = from_slots(vec![(2, 1)], VoteSource::Tpu, &keypair_b, None);
-        vote_b.forwarded = true;
+        let vote_b = from_slots(vec![(2, 1)], VoteSource::Tpu, &keypair_b, None);
         let vote_c = from_slots(vec![(3, 1)], VoteSource::Tpu, &keypair_c, None);
         let vote_c = from_slots(vec![(3, 1)], VoteSource::Tpu, &keypair_c, None);
         let vote_d = from_slots(vec![(4, 1)], VoteSource::Gossip, &keypair_d, None);
         let vote_d = from_slots(vec![(4, 1)], VoteSource::Gossip, &keypair_d, None);
 
 
@@ -1109,8 +924,8 @@ mod tests {
         latest_unprocessed_votes.update_latest_vote(vote_d, false /* should replenish */);
         latest_unprocessed_votes.update_latest_vote(vote_d, false /* should replenish */);
         assert_eq!(4, latest_unprocessed_votes.len());
         assert_eq!(4, latest_unprocessed_votes.len());
 
 
-        latest_unprocessed_votes.clear_forwarded_packets();
-        assert_eq!(1, latest_unprocessed_votes.len());
+        latest_unprocessed_votes.clear();
+        assert_eq!(0, latest_unprocessed_votes.len());
 
 
         assert_eq!(
         assert_eq!(
             Some(1),
             Some(1),

+ 0 - 116
core/src/banking_stage/leader_slot_metrics.rs

@@ -220,24 +220,6 @@ struct LeaderSlotPacketCountMetrics {
     // according to the cost model. These transactions are added back to the buffered queue and are
     // according to the cost model. These transactions are added back to the buffered queue and are
     // already counted in `self.retrayble_errored_transaction_count`.
     // already counted in `self.retrayble_errored_transaction_count`.
     cost_model_throttled_transactions_count: u64,
     cost_model_throttled_transactions_count: u64,
-
-    // total number of forwardsable packets that failed forwarding
-    failed_forwarded_packets_count: u64,
-
-    // total number of forwardsable packets that were successfully forwarded
-    successful_forwarded_packets_count: u64,
-
-    // total number of attempted forwards that failed. Note this is not a count of the number of packets
-    // that failed, just the total number of batches of packets that failed forwarding
-    packet_batch_forward_failure_count: u64,
-
-    // total number of valid unprocessed packets in the buffer that were removed after being forwarded
-    cleared_from_buffer_after_forward_count: u64,
-
-    // total number of forwardable batches that were attempted for forwarding. A forwardable batch
-    // is defined in `ForwardPacketBatchesByAccounts` in `forward_packet_batches_by_accounts.rs`
-    forwardable_batches_count: u64,
-
     // min prioritization fees for scheduled transactions
     // min prioritization fees for scheduled transactions
     min_prioritization_fees: u64,
     min_prioritization_fees: u64,
     // max prioritization fees for scheduled transactions
     // max prioritization fees for scheduled transactions
@@ -354,31 +336,6 @@ impl LeaderSlotPacketCountMetrics {
                 self.cost_model_throttled_transactions_count,
                 self.cost_model_throttled_transactions_count,
                 i64
                 i64
             ),
             ),
-            (
-                "failed_forwarded_packets_count",
-                self.failed_forwarded_packets_count,
-                i64
-            ),
-            (
-                "successful_forwarded_packets_count",
-                self.successful_forwarded_packets_count,
-                i64
-            ),
-            (
-                "packet_batch_forward_failure_count",
-                self.packet_batch_forward_failure_count,
-                i64
-            ),
-            (
-                "cleared_from_buffer_after_forward_count",
-                self.cleared_from_buffer_after_forward_count,
-                i64
-            ),
-            (
-                "forwardable_batches_count",
-                self.forwardable_batches_count,
-                i64
-            ),
             (
             (
                 "end_of_slot_unprocessed_buffer_len",
                 "end_of_slot_unprocessed_buffer_len",
                 self.end_of_slot_unprocessed_buffer_len,
                 self.end_of_slot_unprocessed_buffer_len,
@@ -883,61 +840,6 @@ impl LeaderSlotMetricsTracker {
         }
         }
     }
     }
 
 
-    pub(crate) fn increment_failed_forwarded_packets_count(&mut self, count: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            saturating_add_assign!(
-                leader_slot_metrics
-                    .packet_count_metrics
-                    .failed_forwarded_packets_count,
-                count
-            );
-        }
-    }
-
-    pub(crate) fn increment_successful_forwarded_packets_count(&mut self, count: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            saturating_add_assign!(
-                leader_slot_metrics
-                    .packet_count_metrics
-                    .successful_forwarded_packets_count,
-                count
-            );
-        }
-    }
-
-    pub(crate) fn increment_packet_batch_forward_failure_count(&mut self, count: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            saturating_add_assign!(
-                leader_slot_metrics
-                    .packet_count_metrics
-                    .packet_batch_forward_failure_count,
-                count
-            );
-        }
-    }
-
-    pub(crate) fn increment_cleared_from_buffer_after_forward_count(&mut self, count: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            saturating_add_assign!(
-                leader_slot_metrics
-                    .packet_count_metrics
-                    .cleared_from_buffer_after_forward_count,
-                count
-            );
-        }
-    }
-
-    pub(crate) fn increment_forwardable_batches_count(&mut self, count: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            saturating_add_assign!(
-                leader_slot_metrics
-                    .packet_count_metrics
-                    .forwardable_batches_count,
-                count
-            );
-        }
-    }
-
     pub(crate) fn increment_retryable_packets_count(&mut self, count: u64) {
     pub(crate) fn increment_retryable_packets_count(&mut self, count: u64) {
         if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
         if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
             saturating_add_assign!(
             saturating_add_assign!(
@@ -1008,24 +910,6 @@ impl LeaderSlotMetricsTracker {
         }
         }
     }
     }
 
 
-    pub(crate) fn increment_forward_us(&mut self, us: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            leader_slot_metrics
-                .timing_metrics
-                .process_buffered_packets_timings
-                .forward_us += us;
-        }
-    }
-
-    pub(crate) fn increment_forward_and_hold_us(&mut self, us: u64) {
-        if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
-            leader_slot_metrics
-                .timing_metrics
-                .process_buffered_packets_timings
-                .forward_and_hold_us += us;
-        }
-    }
-
     pub(crate) fn increment_process_packets_transactions_us(&mut self, us: u64) {
     pub(crate) fn increment_process_packets_transactions_us(&mut self, us: u64) {
         if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
         if let Some(leader_slot_metrics) = &mut self.leader_slot_metrics {
             leader_slot_metrics
             leader_slot_metrics

+ 0 - 4
core/src/banking_stage/leader_slot_timing_metrics.rs

@@ -182,8 +182,6 @@ impl OuterLoopTimings {
 pub(crate) struct ProcessBufferedPacketsTimings {
 pub(crate) struct ProcessBufferedPacketsTimings {
     pub make_decision_us: u64,
     pub make_decision_us: u64,
     pub consume_buffered_packets_us: u64,
     pub consume_buffered_packets_us: u64,
-    pub forward_us: u64,
-    pub forward_and_hold_us: u64,
 }
 }
 impl ProcessBufferedPacketsTimings {
 impl ProcessBufferedPacketsTimings {
     fn report(&self, id: &str, slot: Slot) {
     fn report(&self, id: &str, slot: Slot) {
@@ -197,8 +195,6 @@ impl ProcessBufferedPacketsTimings {
                 self.consume_buffered_packets_us as i64,
                 self.consume_buffered_packets_us as i64,
                 i64
                 i64
             ),
             ),
-            ("forward_us", self.forward_us as i64, i64),
-            ("forward_and_hold_us", self.forward_and_hold_us as i64, i64),
         );
         );
     }
     }
 }
 }

+ 1 - 10
core/src/banking_stage/transaction_scheduler/greedy_scheduler.rs

@@ -400,7 +400,6 @@ mod test {
     use {
     use {
         super::*,
         super::*,
         crate::banking_stage::{
         crate::banking_stage::{
-            immutable_deserialized_packet::ImmutableDeserializedPacket,
             scheduler_messages::{MaxAge, TransactionId},
             scheduler_messages::{MaxAge, TransactionId},
             transaction_scheduler::{
             transaction_scheduler::{
                 transaction_state::SanitizedTransactionTTL,
                 transaction_state::SanitizedTransactionTTL,
@@ -409,7 +408,6 @@ mod test {
         },
         },
         crossbeam_channel::unbounded,
         crossbeam_channel::unbounded,
         itertools::Itertools,
         itertools::Itertools,
-        solana_perf::packet::Packet,
         solana_pubkey::Pubkey,
         solana_pubkey::Pubkey,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_sdk::{
         solana_sdk::{
@@ -421,7 +419,7 @@ mod test {
             system_instruction,
             system_instruction,
             transaction::{SanitizedTransaction, Transaction},
             transaction::{SanitizedTransaction, Transaction},
         },
         },
-        std::{borrow::Borrow, sync::Arc},
+        std::borrow::Borrow,
     };
     };
 
 
     #[allow(clippy::type_complexity)]
     #[allow(clippy::type_complexity)]
@@ -483,12 +481,6 @@ mod test {
                 lamports,
                 lamports,
                 compute_unit_price,
                 compute_unit_price,
             );
             );
-            let packet = Arc::new(
-                ImmutableDeserializedPacket::new(
-                    Packet::from_data(None, transaction.to_versioned_transaction()).unwrap(),
-                )
-                .unwrap(),
-            );
             let transaction_ttl = SanitizedTransactionTTL {
             let transaction_ttl = SanitizedTransactionTTL {
                 transaction,
                 transaction,
                 max_age: MaxAge::MAX,
                 max_age: MaxAge::MAX,
@@ -496,7 +488,6 @@ mod test {
             const TEST_TRANSACTION_COST: u64 = 5000;
             const TEST_TRANSACTION_COST: u64 = 5000;
             container.insert_new_transaction(
             container.insert_new_transaction(
                 transaction_ttl,
                 transaction_ttl,
-                packet,
                 compute_unit_price,
                 compute_unit_price,
                 TEST_TRANSACTION_COST,
                 TEST_TRANSACTION_COST,
             );
             );

+ 2 - 13
core/src/banking_stage/transaction_scheduler/prio_graph_scheduler.rs

@@ -629,10 +629,7 @@ fn try_schedule_transaction<Tx: TransactionWithMeta>(
 mod tests {
 mod tests {
     use {
     use {
         super::*,
         super::*,
-        crate::banking_stage::{
-            immutable_deserialized_packet::ImmutableDeserializedPacket,
-            transaction_scheduler::transaction_state_container::TransactionStateContainer,
-        },
+        crate::banking_stage::transaction_scheduler::transaction_state_container::TransactionStateContainer,
         crossbeam_channel::{unbounded, Receiver},
         crossbeam_channel::{unbounded, Receiver},
         itertools::Itertools,
         itertools::Itertools,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
@@ -640,14 +637,13 @@ mod tests {
             compute_budget::ComputeBudgetInstruction,
             compute_budget::ComputeBudgetInstruction,
             hash::Hash,
             hash::Hash,
             message::Message,
             message::Message,
-            packet::Packet,
             pubkey::Pubkey,
             pubkey::Pubkey,
             signature::Keypair,
             signature::Keypair,
             signer::Signer,
             signer::Signer,
             system_instruction,
             system_instruction,
             transaction::{SanitizedTransaction, Transaction},
             transaction::{SanitizedTransaction, Transaction},
         },
         },
-        std::{borrow::Borrow, sync::Arc},
+        std::borrow::Borrow,
     };
     };
 
 
     #[allow(clippy::type_complexity)]
     #[allow(clippy::type_complexity)]
@@ -725,12 +721,6 @@ mod tests {
                 lamports,
                 lamports,
                 compute_unit_price,
                 compute_unit_price,
             );
             );
-            let packet = Arc::new(
-                ImmutableDeserializedPacket::new(
-                    Packet::from_data(None, transaction.to_versioned_transaction()).unwrap(),
-                )
-                .unwrap(),
-            );
             let transaction_ttl = SanitizedTransactionTTL {
             let transaction_ttl = SanitizedTransactionTTL {
                 transaction,
                 transaction,
                 max_age: MaxAge::MAX,
                 max_age: MaxAge::MAX,
@@ -738,7 +728,6 @@ mod tests {
             const TEST_TRANSACTION_COST: u64 = 5000;
             const TEST_TRANSACTION_COST: u64 = 5000;
             container.insert_new_transaction(
             container.insert_new_transaction(
                 transaction_ttl,
                 transaction_ttl,
-                packet,
                 compute_unit_price,
                 compute_unit_price,
                 TEST_TRANSACTION_COST,
                 TEST_TRANSACTION_COST,
             );
             );

+ 22 - 39
core/src/banking_stage/transaction_scheduler/receive_and_buffer.rs

@@ -66,8 +66,6 @@ pub(crate) struct SanitizedTransactionReceiveAndBuffer {
     /// Packet/Transaction ingress.
     /// Packet/Transaction ingress.
     packet_receiver: PacketDeserializer,
     packet_receiver: PacketDeserializer,
     bank_forks: Arc<RwLock<BankForks>>,
     bank_forks: Arc<RwLock<BankForks>>,
-
-    forwarding_enabled: bool,
 }
 }
 
 
 impl ReceiveAndBuffer for SanitizedTransactionReceiveAndBuffer {
 impl ReceiveAndBuffer for SanitizedTransactionReceiveAndBuffer {
@@ -93,7 +91,7 @@ impl ReceiveAndBuffer for SanitizedTransactionReceiveAndBuffer {
                 },
                 },
                 true,
                 true,
             ),
             ),
-            BufferedPacketsDecision::Forward => (MAX_PACKET_RECEIVE_TIME, self.forwarding_enabled),
+            BufferedPacketsDecision::Forward => (MAX_PACKET_RECEIVE_TIME, false),
             BufferedPacketsDecision::ForwardAndHold => (MAX_PACKET_RECEIVE_TIME, true),
             BufferedPacketsDecision::ForwardAndHold => (MAX_PACKET_RECEIVE_TIME, true),
         };
         };
 
 
@@ -145,15 +143,10 @@ impl ReceiveAndBuffer for SanitizedTransactionReceiveAndBuffer {
 }
 }
 
 
 impl SanitizedTransactionReceiveAndBuffer {
 impl SanitizedTransactionReceiveAndBuffer {
-    pub fn new(
-        packet_receiver: PacketDeserializer,
-        bank_forks: Arc<RwLock<BankForks>>,
-        forwarding_enabled: bool,
-    ) -> Self {
+    pub fn new(packet_receiver: PacketDeserializer, bank_forks: Arc<RwLock<BankForks>>) -> Self {
         Self {
         Self {
             packet_receiver,
             packet_receiver,
             bank_forks,
             bank_forks,
-            forwarding_enabled,
         }
         }
     }
     }
 
 
@@ -181,7 +174,6 @@ impl SanitizedTransactionReceiveAndBuffer {
         const CHUNK_SIZE: usize = 128;
         const CHUNK_SIZE: usize = 128;
         let lock_results: [_; CHUNK_SIZE] = core::array::from_fn(|_| Ok(()));
         let lock_results: [_; CHUNK_SIZE] = core::array::from_fn(|_| Ok(()));
 
 
-        let mut arc_packets = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut transactions = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut transactions = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut max_ages = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut max_ages = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut fee_budget_limits_vec = ArrayVec::<_, CHUNK_SIZE>::new();
         let mut fee_budget_limits_vec = ArrayVec::<_, CHUNK_SIZE>::new();
@@ -192,32 +184,27 @@ impl SanitizedTransactionReceiveAndBuffer {
             chunk
             chunk
                 .iter()
                 .iter()
                 .filter_map(|packet| {
                 .filter_map(|packet| {
-                    packet
-                        .build_sanitized_transaction(
-                            vote_only,
-                            root_bank.as_ref(),
-                            root_bank.get_reserved_account_keys(),
-                        )
-                        .map(|(tx, deactivation_slot)| (packet.clone(), tx, deactivation_slot))
+                    packet.build_sanitized_transaction(
+                        vote_only,
+                        root_bank.as_ref(),
+                        root_bank.get_reserved_account_keys(),
+                    )
                 })
                 })
                 .inspect(|_| saturating_add_assign!(post_sanitization_count, 1))
                 .inspect(|_| saturating_add_assign!(post_sanitization_count, 1))
-                .filter(|(_packet, tx, _deactivation_slot)| {
+                .filter(|(tx, _deactivation_slot)| {
                     validate_account_locks(
                     validate_account_locks(
                         tx.message().account_keys(),
                         tx.message().account_keys(),
                         transaction_account_lock_limit,
                         transaction_account_lock_limit,
                     )
                     )
                     .is_ok()
                     .is_ok()
                 })
                 })
-                .filter_map(|(packet, tx, deactivation_slot)| {
+                .filter_map(|(tx, deactivation_slot)| {
                     tx.compute_budget_instruction_details()
                     tx.compute_budget_instruction_details()
                         .sanitize_and_convert_to_compute_budget_limits(&working_bank.feature_set)
                         .sanitize_and_convert_to_compute_budget_limits(&working_bank.feature_set)
-                        .map(|compute_budget| {
-                            (packet, tx, deactivation_slot, compute_budget.into())
-                        })
+                        .map(|compute_budget| (tx, deactivation_slot, compute_budget.into()))
                         .ok()
                         .ok()
                 })
                 })
-                .for_each(|(packet, tx, deactivation_slot, fee_budget_limits)| {
-                    arc_packets.push(packet);
+                .for_each(|(tx, deactivation_slot, fee_budget_limits)| {
                     transactions.push(tx);
                     transactions.push(tx);
                     max_ages.push(calculate_max_age(
                     max_ages.push(calculate_max_age(
                         sanitized_epoch,
                         sanitized_epoch,
@@ -238,18 +225,15 @@ impl SanitizedTransactionReceiveAndBuffer {
             let mut post_transaction_check_count: usize = 0;
             let mut post_transaction_check_count: usize = 0;
             let mut num_dropped_on_capacity: usize = 0;
             let mut num_dropped_on_capacity: usize = 0;
             let mut num_buffered: usize = 0;
             let mut num_buffered: usize = 0;
-            for ((((packet, transaction), max_age), fee_budget_limits), _check_result) in
-                arc_packets
-                    .drain(..)
-                    .zip(transactions.drain(..))
-                    .zip(max_ages.drain(..))
-                    .zip(fee_budget_limits_vec.drain(..))
-                    .zip(check_results)
-                    .filter(|(_, check_result)| check_result.is_ok())
-                    .filter(|((((_, tx), _), _), _)| {
-                        Consumer::check_fee_payer_unlocked(&working_bank, tx, &mut error_counts)
-                            .is_ok()
-                    })
+            for (((transaction, max_age), fee_budget_limits), _check_result) in transactions
+                .drain(..)
+                .zip(max_ages.drain(..))
+                .zip(fee_budget_limits_vec.drain(..))
+                .zip(check_results)
+                .filter(|(_, check_result)| check_result.is_ok())
+                .filter(|(((tx, _), _), _)| {
+                    Consumer::check_fee_payer_unlocked(&working_bank, tx, &mut error_counts).is_ok()
+                })
             {
             {
                 saturating_add_assign!(post_transaction_check_count, 1);
                 saturating_add_assign!(post_transaction_check_count, 1);
 
 
@@ -260,7 +244,7 @@ impl SanitizedTransactionReceiveAndBuffer {
                     max_age,
                     max_age,
                 };
                 };
 
 
-                if container.insert_new_transaction(transaction_ttl, packet, priority, cost) {
+                if container.insert_new_transaction(transaction_ttl, priority, cost) {
                     saturating_add_assign!(num_dropped_on_capacity, 1);
                     saturating_add_assign!(num_dropped_on_capacity, 1);
                 }
                 }
                 saturating_add_assign!(num_buffered, 1);
                 saturating_add_assign!(num_buffered, 1);
@@ -395,7 +379,7 @@ impl TransactionViewReceiveAndBuffer {
         working_bank: &Bank,
         working_bank: &Bank,
         packet_batch_message: BankingPacketBatch,
         packet_batch_message: BankingPacketBatch,
     ) -> usize {
     ) -> usize {
-        // Do not support forwarding - only add support for this if we really need it.
+        // If not holding packets, just drop them immediately without parsing.
         if matches!(decision, BufferedPacketsDecision::Forward) {
         if matches!(decision, BufferedPacketsDecision::Forward) {
             return 0;
             return 0;
         }
         }
@@ -616,7 +600,6 @@ impl TransactionViewReceiveAndBuffer {
                 transaction: view,
                 transaction: view,
                 max_age,
                 max_age,
             },
             },
-            None,
             priority,
             priority,
             cost,
             cost,
         ))
         ))

+ 16 - 154
core/src/banking_stage/transaction_scheduler/scheduler_controller.rs

@@ -14,28 +14,19 @@ use {
         consume_worker::ConsumeWorkerMetrics,
         consume_worker::ConsumeWorkerMetrics,
         consumer::Consumer,
         consumer::Consumer,
         decision_maker::{BufferedPacketsDecision, DecisionMaker},
         decision_maker::{BufferedPacketsDecision, DecisionMaker},
-        forwarder::Forwarder,
         transaction_scheduler::transaction_state_container::StateContainer,
         transaction_scheduler::transaction_state_container::StateContainer,
-        ForwardOption, LikeClusterInfo, TOTAL_BUFFERED_PACKETS,
+        TOTAL_BUFFERED_PACKETS,
     },
     },
     solana_measure::measure_us,
     solana_measure::measure_us,
     solana_runtime::{bank::Bank, bank_forks::BankForks},
     solana_runtime::{bank::Bank, bank_forks::BankForks},
-    solana_sdk::{
-        self,
-        clock::{FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET, MAX_PROCESSING_AGE},
-        saturating_add_assign,
-    },
+    solana_sdk::{self, clock::MAX_PROCESSING_AGE, saturating_add_assign},
     solana_svm::transaction_error_metrics::TransactionErrorMetrics,
     solana_svm::transaction_error_metrics::TransactionErrorMetrics,
-    std::{
-        sync::{Arc, RwLock},
-        time::{Duration, Instant},
-    },
+    std::sync::{Arc, RwLock},
 };
 };
 
 
 /// Controls packet and transaction flow into scheduler, and scheduling execution.
 /// Controls packet and transaction flow into scheduler, and scheduling execution.
-pub(crate) struct SchedulerController<C, R, S>
+pub(crate) struct SchedulerController<R, S>
 where
 where
-    C: LikeClusterInfo,
     R: ReceiveAndBuffer,
     R: ReceiveAndBuffer,
     S: Scheduler<R::Transaction>,
     S: Scheduler<R::Transaction>,
 {
 {
@@ -58,13 +49,10 @@ where
     timing_metrics: SchedulerTimingMetrics,
     timing_metrics: SchedulerTimingMetrics,
     /// Metric report handles for the worker threads.
     /// Metric report handles for the worker threads.
     worker_metrics: Vec<Arc<ConsumeWorkerMetrics>>,
     worker_metrics: Vec<Arc<ConsumeWorkerMetrics>>,
-    /// State for forwarding packets to the leader, if enabled.
-    forwarder: Option<Forwarder<C>>,
 }
 }
 
 
-impl<C, R, S> SchedulerController<C, R, S>
+impl<R, S> SchedulerController<R, S>
 where
 where
-    C: LikeClusterInfo,
     R: ReceiveAndBuffer,
     R: ReceiveAndBuffer,
     S: Scheduler<R::Transaction>,
     S: Scheduler<R::Transaction>,
 {
 {
@@ -74,7 +62,6 @@ where
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
         scheduler: S,
         scheduler: S,
         worker_metrics: Vec<Arc<ConsumeWorkerMetrics>>,
         worker_metrics: Vec<Arc<ConsumeWorkerMetrics>>,
-        forwarder: Option<Forwarder<C>>,
     ) -> Self {
     ) -> Self {
         Self {
         Self {
             decision_maker,
             decision_maker,
@@ -86,7 +73,6 @@ where
             count_metrics: SchedulerCountMetrics::default(),
             count_metrics: SchedulerCountMetrics::default(),
             timing_metrics: SchedulerTimingMetrics::default(),
             timing_metrics: SchedulerTimingMetrics::default(),
             worker_metrics,
             worker_metrics,
-            forwarder,
         }
         }
     }
     }
 
 
@@ -144,7 +130,6 @@ where
         &mut self,
         &mut self,
         decision: &BufferedPacketsDecision,
         decision: &BufferedPacketsDecision,
     ) -> Result<(), SchedulerError> {
     ) -> Result<(), SchedulerError> {
-        let forwarding_enabled = self.forwarder.is_some();
         match decision {
         match decision {
             BufferedPacketsDecision::Consume(bank_start) => {
             BufferedPacketsDecision::Consume(bank_start) => {
                 let (scheduling_summary, schedule_time_us) = measure_us!(self.scheduler.schedule(
                 let (scheduling_summary, schedule_time_us) = measure_us!(self.scheduler.schedule(
@@ -184,30 +169,16 @@ where
                 });
                 });
             }
             }
             BufferedPacketsDecision::Forward => {
             BufferedPacketsDecision::Forward => {
-                if forwarding_enabled {
-                    let (_, forward_time_us) = measure_us!(self.forward_packets(false));
-                    self.timing_metrics.update(|timing_metrics| {
-                        saturating_add_assign!(timing_metrics.forward_time_us, forward_time_us);
-                    });
-                } else {
-                    let (_, clear_time_us) = measure_us!(self.clear_container());
-                    self.timing_metrics.update(|timing_metrics| {
-                        saturating_add_assign!(timing_metrics.clear_time_us, clear_time_us);
-                    });
-                }
+                let (_, clear_time_us) = measure_us!(self.clear_container());
+                self.timing_metrics.update(|timing_metrics| {
+                    saturating_add_assign!(timing_metrics.clear_time_us, clear_time_us);
+                });
             }
             }
             BufferedPacketsDecision::ForwardAndHold => {
             BufferedPacketsDecision::ForwardAndHold => {
-                if forwarding_enabled {
-                    let (_, forward_time_us) = measure_us!(self.forward_packets(true));
-                    self.timing_metrics.update(|timing_metrics| {
-                        saturating_add_assign!(timing_metrics.forward_time_us, forward_time_us);
-                    });
-                } else {
-                    let (_, clean_time_us) = measure_us!(self.clean_queue());
-                    self.timing_metrics.update(|timing_metrics| {
-                        saturating_add_assign!(timing_metrics.clean_time_us, clean_time_us);
-                    });
-                }
+                let (_, clean_time_us) = measure_us!(self.clean_queue());
+                self.timing_metrics.update(|timing_metrics| {
+                    saturating_add_assign!(timing_metrics.clean_time_us, clean_time_us);
+                });
             }
             }
             BufferedPacketsDecision::Hold => {}
             BufferedPacketsDecision::Hold => {}
         }
         }
@@ -241,105 +212,6 @@ where
         }
         }
     }
     }
 
 
-    /// Forward packets to the next leader.
-    fn forward_packets(&mut self, hold: bool) {
-        const MAX_FORWARDING_DURATION: Duration = Duration::from_millis(100);
-        let start = Instant::now();
-        let bank = self.bank_forks.read().unwrap().working_bank();
-        let feature_set = &bank.feature_set;
-        let forwarder = self.forwarder.as_mut().expect("forwarder must exist");
-
-        // Pop from the container in chunks, filter using bank checks, then attempt to forward.
-        // This doubles as a way to clean the queue as well as forwarding transactions.
-        const CHUNK_SIZE: usize = 64;
-        let mut num_forwarded: usize = 0;
-        let mut ids_to_add_back = Vec::new();
-        let mut max_time_reached = false;
-        while !self.container.is_empty() {
-            let mut filter_array = [true; CHUNK_SIZE];
-            let mut ids = Vec::with_capacity(CHUNK_SIZE);
-            let mut txs = Vec::with_capacity(CHUNK_SIZE);
-
-            for _ in 0..CHUNK_SIZE {
-                if let Some(id) = self.container.pop() {
-                    ids.push(id);
-                } else {
-                    break;
-                }
-            }
-            let chunk_size = ids.len();
-            ids.iter().for_each(|id| {
-                let transaction = self.container.get_transaction_ttl(id.id).unwrap();
-                txs.push(&transaction.transaction);
-            });
-
-            // use same filter we use for processing transactions:
-            // age, already processed, fee-check.
-            Self::pre_graph_filter(
-                &txs,
-                &mut filter_array,
-                &bank,
-                MAX_PROCESSING_AGE
-                    .saturating_sub(FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET as usize),
-            );
-
-            for (id, filter_result) in ids.iter().zip(&filter_array[..chunk_size]) {
-                if !*filter_result {
-                    self.container.remove_by_id(id.id);
-                    continue;
-                }
-
-                ids_to_add_back.push(*id); // add back to the queue at end
-                let state = self.container.get_mut_transaction_state(id.id).unwrap();
-                let sanitized_transaction = &state.transaction_ttl().transaction;
-                let immutable_packet = state.packet().expect("forwarding requires packet");
-
-                // If not already forwarded and can be forwarded, add to forwardable packets.
-                if state.should_forward()
-                    && forwarder.try_add_packet(
-                        sanitized_transaction,
-                        immutable_packet.clone(),
-                        feature_set,
-                    )
-                {
-                    saturating_add_assign!(num_forwarded, 1);
-                    state.mark_forwarded();
-                }
-            }
-
-            if start.elapsed() >= MAX_FORWARDING_DURATION {
-                max_time_reached = true;
-                break;
-            }
-        }
-
-        // Forward each batch of transactions
-        forwarder.forward_batched_packets(&ForwardOption::ForwardTransaction);
-        forwarder.clear_batches();
-
-        // If we hit the time limit. Drop everything that was not checked/processed.
-        // If we cannot run these simple checks in time, then we cannot run them during
-        // leader slot.
-        if max_time_reached {
-            while let Some(id) = self.container.pop() {
-                self.container.remove_by_id(id.id);
-            }
-        }
-
-        if hold {
-            self.container
-                .push_ids_into_queue(ids_to_add_back.into_iter());
-        } else {
-            for priority_id in ids_to_add_back {
-                self.container.remove_by_id(priority_id.id);
-            }
-        }
-
-        self.count_metrics.update(|count_metrics| {
-            saturating_add_assign!(count_metrics.num_forwarded, num_forwarded);
-        });
-    }
-
     /// Clears the transaction state container.
     /// Clears the transaction state container.
     /// This only clears pending transactions, and does **not** clear in-flight transactions.
     /// This only clears pending transactions, and does **not** clear in-flight transactions.
     fn clear_container(&mut self) {
     fn clear_container(&mut self) {
@@ -469,7 +341,6 @@ mod tests {
         agave_banking_stage_ingress_types::{BankingPacketBatch, BankingPacketReceiver},
         agave_banking_stage_ingress_types::{BankingPacketBatch, BankingPacketReceiver},
         crossbeam_channel::{unbounded, Receiver, Sender},
         crossbeam_channel::{unbounded, Receiver, Sender},
         itertools::Itertools,
         itertools::Itertools,
-        solana_gossip::cluster_info::ClusterInfo,
         solana_ledger::{
         solana_ledger::{
             blockstore::Blockstore, genesis_utils::GenesisConfigInfo,
             blockstore::Blockstore, genesis_utils::GenesisConfigInfo,
             get_tmp_ledger_path_auto_delete, leader_schedule_cache::LeaderScheduleCache,
             get_tmp_ledger_path_auto_delete, leader_schedule_cache::LeaderScheduleCache,
@@ -511,11 +382,7 @@ mod tests {
         receiver: BankingPacketReceiver,
         receiver: BankingPacketReceiver,
         bank_forks: Arc<RwLock<BankForks>>,
         bank_forks: Arc<RwLock<BankForks>>,
     ) -> SanitizedTransactionReceiveAndBuffer {
     ) -> SanitizedTransactionReceiveAndBuffer {
-        SanitizedTransactionReceiveAndBuffer::new(
-            PacketDeserializer::new(receiver),
-            bank_forks,
-            false,
-        )
+        SanitizedTransactionReceiveAndBuffer::new(PacketDeserializer::new(receiver), bank_forks)
     }
     }
 
 
     fn test_create_transaction_view_receive_and_buffer(
     fn test_create_transaction_view_receive_and_buffer(
@@ -534,7 +401,7 @@ mod tests {
         create_receive_and_buffer: impl FnOnce(BankingPacketReceiver, Arc<RwLock<BankForks>>) -> R,
         create_receive_and_buffer: impl FnOnce(BankingPacketReceiver, Arc<RwLock<BankForks>>) -> R,
     ) -> (
     ) -> (
         TestFrame<R::Transaction>,
         TestFrame<R::Transaction>,
-        SchedulerController<Arc<ClusterInfo>, R, PrioGraphScheduler<R::Transaction>>,
+        SchedulerController<R, PrioGraphScheduler<R::Transaction>>,
     ) {
     ) {
         let GenesisConfigInfo {
         let GenesisConfigInfo {
             mut genesis_config,
             mut genesis_config,
@@ -591,7 +458,6 @@ mod tests {
             bank_forks,
             bank_forks,
             scheduler,
             scheduler,
             vec![], // no actual workers with metrics to report, this can be empty
             vec![], // no actual workers with metrics to report, this can be empty
-            None,
         );
         );
 
 
         (test_frame, scheduler_controller)
         (test_frame, scheduler_controller)
@@ -635,11 +501,7 @@ mod tests {
     // In the tests, the decision will not become stale, so it is more convenient
     // In the tests, the decision will not become stale, so it is more convenient
     // to receive first and then schedule.
     // to receive first and then schedule.
     fn test_receive_then_schedule<R: ReceiveAndBuffer>(
     fn test_receive_then_schedule<R: ReceiveAndBuffer>(
-        scheduler_controller: &mut SchedulerController<
-            Arc<ClusterInfo>,
-            R,
-            impl Scheduler<R::Transaction>,
-        >,
+        scheduler_controller: &mut SchedulerController<R, impl Scheduler<R::Transaction>>,
     ) {
     ) {
         let decision = scheduler_controller
         let decision = scheduler_controller
             .decision_maker
             .decision_maker

+ 0 - 9
core/src/banking_stage/transaction_scheduler/scheduler_metrics.rs

@@ -59,8 +59,6 @@ pub struct SchedulerCountMetricsInner {
     pub num_finished: usize,
     pub num_finished: usize,
     /// Number of transactions that were retryable.
     /// Number of transactions that were retryable.
     pub num_retryable: usize,
     pub num_retryable: usize,
-    /// Number of transactions that were scheduled to be forwarded.
-    pub num_forwarded: usize,
 
 
     /// Number of transactions that were immediately dropped on receive.
     /// Number of transactions that were immediately dropped on receive.
     pub num_dropped_on_receive: usize,
     pub num_dropped_on_receive: usize,
@@ -124,7 +122,6 @@ impl SchedulerCountMetricsInner {
             ),
             ),
             ("num_finished", self.num_finished, i64),
             ("num_finished", self.num_finished, i64),
             ("num_retryable", self.num_retryable, i64),
             ("num_retryable", self.num_retryable, i64),
-            ("num_forwarded", self.num_forwarded, i64),
             ("num_dropped_on_receive", self.num_dropped_on_receive, i64),
             ("num_dropped_on_receive", self.num_dropped_on_receive, i64),
             (
             (
                 "num_dropped_on_sanitization",
                 "num_dropped_on_sanitization",
@@ -165,7 +162,6 @@ impl SchedulerCountMetricsInner {
             || self.num_schedule_filtered_out != 0
             || self.num_schedule_filtered_out != 0
             || self.num_finished != 0
             || self.num_finished != 0
             || self.num_retryable != 0
             || self.num_retryable != 0
-            || self.num_forwarded != 0
             || self.num_dropped_on_receive != 0
             || self.num_dropped_on_receive != 0
             || self.num_dropped_on_sanitization != 0
             || self.num_dropped_on_sanitization != 0
             || self.num_dropped_on_validate_locks != 0
             || self.num_dropped_on_validate_locks != 0
@@ -183,7 +179,6 @@ impl SchedulerCountMetricsInner {
         self.num_schedule_filtered_out = 0;
         self.num_schedule_filtered_out = 0;
         self.num_finished = 0;
         self.num_finished = 0;
         self.num_retryable = 0;
         self.num_retryable = 0;
-        self.num_forwarded = 0;
         self.num_dropped_on_receive = 0;
         self.num_dropped_on_receive = 0;
         self.num_dropped_on_sanitization = 0;
         self.num_dropped_on_sanitization = 0;
         self.num_dropped_on_validate_locks = 0;
         self.num_dropped_on_validate_locks = 0;
@@ -275,8 +270,6 @@ pub struct SchedulerTimingMetricsInner {
     pub clear_time_us: u64,
     pub clear_time_us: u64,
     /// Time spent cleaning expired or processed transactions from the container.
     /// Time spent cleaning expired or processed transactions from the container.
     pub clean_time_us: u64,
     pub clean_time_us: u64,
-    /// Time spent forwarding transactions.
-    pub forward_time_us: u64,
     /// Time spent receiving completed transactions.
     /// Time spent receiving completed transactions.
     pub receive_completed_time_us: u64,
     pub receive_completed_time_us: u64,
 }
 }
@@ -318,7 +311,6 @@ impl SchedulerTimingMetricsInner {
             ("schedule_time_us", self.schedule_time_us, i64),
             ("schedule_time_us", self.schedule_time_us, i64),
             ("clear_time_us", self.clear_time_us, i64),
             ("clear_time_us", self.clear_time_us, i64),
             ("clean_time_us", self.clean_time_us, i64),
             ("clean_time_us", self.clean_time_us, i64),
-            ("forward_time_us", self.forward_time_us, i64),
             (
             (
                 "receive_completed_time_us",
                 "receive_completed_time_us",
                 self.receive_completed_time_us,
                 self.receive_completed_time_us,
@@ -339,7 +331,6 @@ impl SchedulerTimingMetricsInner {
         self.schedule_time_us = 0;
         self.schedule_time_us = 0;
         self.clear_time_us = 0;
         self.clear_time_us = 0;
         self.clean_time_us = 0;
         self.clean_time_us = 0;
-        self.forward_time_us = 0;
         self.receive_completed_time_us = 0;
         self.receive_completed_time_us = 0;
     }
     }
 }
 }

+ 5 - 106
core/src/banking_stage/transaction_scheduler/transaction_state.rs

@@ -1,10 +1,4 @@
-use {
-    crate::banking_stage::{
-        immutable_deserialized_packet::ImmutableDeserializedPacket, scheduler_messages::MaxAge,
-    },
-    solana_sdk::packet::{self},
-    std::sync::Arc,
-};
+use crate::banking_stage::scheduler_messages::MaxAge;
 
 
 /// Simple wrapper type to tie a sanitized transaction to max age slot.
 /// Simple wrapper type to tie a sanitized transaction to max age slot.
 pub(crate) struct SanitizedTransactionTTL<Tx> {
 pub(crate) struct SanitizedTransactionTTL<Tx> {
@@ -36,18 +30,11 @@ pub(crate) enum TransactionState<Tx> {
     /// The transaction is available for scheduling.
     /// The transaction is available for scheduling.
     Unprocessed {
     Unprocessed {
         transaction_ttl: SanitizedTransactionTTL<Tx>,
         transaction_ttl: SanitizedTransactionTTL<Tx>,
-        packet: Option<Arc<ImmutableDeserializedPacket>>,
         priority: u64,
         priority: u64,
         cost: u64,
         cost: u64,
-        should_forward: bool,
     },
     },
     /// The transaction is currently scheduled or being processed.
     /// The transaction is currently scheduled or being processed.
-    Pending {
-        packet: Option<Arc<ImmutableDeserializedPacket>>,
-        priority: u64,
-        cost: u64,
-        should_forward: bool,
-    },
+    Pending { priority: u64, cost: u64 },
     /// Only used during transition.
     /// Only used during transition.
     Transitioning,
     Transitioning,
 }
 }
@@ -56,20 +43,13 @@ impl<Tx> TransactionState<Tx> {
     /// Creates a new `TransactionState` in the `Unprocessed` state.
     /// Creates a new `TransactionState` in the `Unprocessed` state.
     pub(crate) fn new(
     pub(crate) fn new(
         transaction_ttl: SanitizedTransactionTTL<Tx>,
         transaction_ttl: SanitizedTransactionTTL<Tx>,
-        packet: Option<Arc<ImmutableDeserializedPacket>>,
         priority: u64,
         priority: u64,
         cost: u64,
         cost: u64,
     ) -> Self {
     ) -> Self {
-        let should_forward = packet
-            .as_ref()
-            .map(|packet| should_forward_from_meta(packet.original_packet().meta()))
-            .unwrap_or_default();
         Self::Unprocessed {
         Self::Unprocessed {
             transaction_ttl,
             transaction_ttl,
-            packet,
             priority,
             priority,
             cost,
             cost,
-            should_forward,
         }
         }
     }
     }
 
 
@@ -93,40 +73,6 @@ impl<Tx> TransactionState<Tx> {
         }
         }
     }
     }
 
 
-    /// Return whether packet should be attempted to be forwarded.
-    pub(crate) fn should_forward(&self) -> bool {
-        match self {
-            Self::Unprocessed {
-                should_forward: forwarded,
-                ..
-            } => *forwarded,
-            Self::Pending {
-                should_forward: forwarded,
-                ..
-            } => *forwarded,
-            Self::Transitioning => unreachable!(),
-        }
-    }
-
-    /// Mark the packet as forwarded.
-    /// This is used to prevent the packet from being forwarded multiple times.
-    pub(crate) fn mark_forwarded(&mut self) {
-        match self {
-            Self::Unprocessed { should_forward, .. } => *should_forward = false,
-            Self::Pending { should_forward, .. } => *should_forward = false,
-            Self::Transitioning => unreachable!(),
-        }
-    }
-
-    /// Return the packet of the transaction.
-    pub(crate) fn packet(&self) -> Option<&Arc<ImmutableDeserializedPacket>> {
-        match self {
-            Self::Unprocessed { packet, .. } => packet.as_ref(),
-            Self::Pending { packet, .. } => packet.as_ref(),
-            Self::Transitioning => unreachable!(),
-        }
-    }
-
     /// Intended to be called when a transaction is scheduled. This method will
     /// Intended to be called when a transaction is scheduled. This method will
     /// transition the transaction from `Unprocessed` to `Pending` and return the
     /// transition the transaction from `Unprocessed` to `Pending` and return the
     /// `SanitizedTransactionTTL` for processing.
     /// `SanitizedTransactionTTL` for processing.
@@ -138,17 +84,10 @@ impl<Tx> TransactionState<Tx> {
         match self.take() {
         match self.take() {
             TransactionState::Unprocessed {
             TransactionState::Unprocessed {
                 transaction_ttl,
                 transaction_ttl,
-                packet,
                 priority,
                 priority,
                 cost,
                 cost,
-                should_forward: forwarded,
             } => {
             } => {
-                *self = TransactionState::Pending {
-                    packet,
-                    priority,
-                    cost,
-                    should_forward: forwarded,
-                };
+                *self = TransactionState::Pending { priority, cost };
                 transaction_ttl
                 transaction_ttl
             }
             }
             TransactionState::Pending { .. } => {
             TransactionState::Pending { .. } => {
@@ -170,18 +109,11 @@ impl<Tx> TransactionState<Tx> {
     ) {
     ) {
         match self.take() {
         match self.take() {
             TransactionState::Unprocessed { .. } => panic!("already unprocessed"),
             TransactionState::Unprocessed { .. } => panic!("already unprocessed"),
-            TransactionState::Pending {
-                packet,
-                priority,
-                cost,
-                should_forward: forwarded,
-            } => {
+            TransactionState::Pending { priority, cost } => {
                 *self = Self::Unprocessed {
                 *self = Self::Unprocessed {
                     transaction_ttl,
                     transaction_ttl,
-                    packet,
                     priority,
                     priority,
                     cost,
                     cost,
-                    should_forward: forwarded,
                 }
                 }
             }
             }
             Self::Transitioning => unreachable!(),
             Self::Transitioning => unreachable!(),
@@ -209,21 +141,15 @@ impl<Tx> TransactionState<Tx> {
     }
     }
 }
 }
 
 
-fn should_forward_from_meta(meta: &packet::Meta) -> bool {
-    !meta.forwarded() && meta.is_from_staked_node()
-}
-
 #[cfg(test)]
 #[cfg(test)]
 mod tests {
 mod tests {
     use {
     use {
         super::*,
         super::*,
-        packet::PacketFlags,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_sdk::{
         solana_sdk::{
             compute_budget::ComputeBudgetInstruction,
             compute_budget::ComputeBudgetInstruction,
             hash::Hash,
             hash::Hash,
             message::Message,
             message::Message,
-            packet::Packet,
             signature::Keypair,
             signature::Keypair,
             signer::Signer,
             signer::Signer,
             system_instruction,
             system_instruction,
@@ -242,20 +168,12 @@ mod tests {
         let message = Message::new(&ixs, Some(&from_keypair.pubkey()));
         let message = Message::new(&ixs, Some(&from_keypair.pubkey()));
         let tx = Transaction::new(&[&from_keypair], message, Hash::default());
         let tx = Transaction::new(&[&from_keypair], message, Hash::default());
 
 
-        let packet = Arc::new(
-            ImmutableDeserializedPacket::new(Packet::from_data(None, tx.clone()).unwrap()).unwrap(),
-        );
         let transaction_ttl = SanitizedTransactionTTL {
         let transaction_ttl = SanitizedTransactionTTL {
             transaction: RuntimeTransaction::from_transaction_for_tests(tx),
             transaction: RuntimeTransaction::from_transaction_for_tests(tx),
             max_age: MaxAge::MAX,
             max_age: MaxAge::MAX,
         };
         };
         const TEST_TRANSACTION_COST: u64 = 5000;
         const TEST_TRANSACTION_COST: u64 = 5000;
-        TransactionState::new(
-            transaction_ttl,
-            Some(packet),
-            compute_unit_price,
-            TEST_TRANSACTION_COST,
-        )
+        TransactionState::new(transaction_ttl, compute_unit_price, TEST_TRANSACTION_COST)
     }
     }
 
 
     #[test]
     #[test]
@@ -373,23 +291,4 @@ mod tests {
         ));
         ));
         assert_eq!(transaction_ttl.max_age, MaxAge::MAX);
         assert_eq!(transaction_ttl.max_age, MaxAge::MAX);
     }
     }
-
-    #[test]
-    fn test_initialize_should_forward() {
-        let meta = packet::Meta::default();
-        assert!(!should_forward_from_meta(&meta));
-
-        let mut meta = packet::Meta::default();
-        meta.flags.set(PacketFlags::FORWARDED, true);
-        assert!(!should_forward_from_meta(&meta));
-
-        let mut meta = packet::Meta::default();
-        meta.set_from_staked_node(true);
-        assert!(should_forward_from_meta(&meta));
-
-        let mut meta = packet::Meta::default();
-        meta.flags.set(PacketFlags::FORWARDED, true);
-        meta.set_from_staked_node(true);
-        assert!(!should_forward_from_meta(&meta));
-    }
 }
 }

+ 22 - 30
core/src/banking_stage/transaction_scheduler/transaction_state_container.rs

@@ -3,10 +3,7 @@ use {
         transaction_priority_id::TransactionPriorityId,
         transaction_priority_id::TransactionPriorityId,
         transaction_state::{SanitizedTransactionTTL, TransactionState},
         transaction_state::{SanitizedTransactionTTL, TransactionState},
     },
     },
-    crate::banking_stage::{
-        immutable_deserialized_packet::ImmutableDeserializedPacket,
-        scheduler_messages::TransactionId,
-    },
+    crate::banking_stage::scheduler_messages::TransactionId,
     agave_transaction_view::resolved_transaction_view::ResolvedTransactionView,
     agave_transaction_view::resolved_transaction_view::ResolvedTransactionView,
     itertools::MinMaxResult,
     itertools::MinMaxResult,
     min_max_heap::MinMaxHeap,
     min_max_heap::MinMaxHeap,
@@ -67,7 +64,7 @@ pub(crate) trait StateContainer<Tx: TransactionWithMeta> {
     /// Panics if the transaction does not exist.
     /// Panics if the transaction does not exist.
     fn get_transaction_ttl(&self, id: TransactionId) -> Option<&SanitizedTransactionTTL<Tx>>;
     fn get_transaction_ttl(&self, id: TransactionId) -> Option<&SanitizedTransactionTTL<Tx>>;
 
 
-    /// Retries a transaction - inserts transaction back into map (but not packet).
+    /// Retries a transaction - inserts transaction back into map.
     /// This transitions the transaction to `Unprocessed` state.
     /// This transitions the transaction to `Unprocessed` state.
     fn retry_transaction(
     fn retry_transaction(
         &mut self,
         &mut self,
@@ -179,19 +176,13 @@ impl<Tx: TransactionWithMeta> TransactionStateContainer<Tx> {
     pub(crate) fn insert_new_transaction(
     pub(crate) fn insert_new_transaction(
         &mut self,
         &mut self,
         transaction_ttl: SanitizedTransactionTTL<Tx>,
         transaction_ttl: SanitizedTransactionTTL<Tx>,
-        packet: Arc<ImmutableDeserializedPacket>,
         priority: u64,
         priority: u64,
         cost: u64,
         cost: u64,
     ) -> bool {
     ) -> bool {
         let priority_id = {
         let priority_id = {
             let entry = self.get_vacant_map_entry();
             let entry = self.get_vacant_map_entry();
             let transaction_id = entry.key();
             let transaction_id = entry.key();
-            entry.insert(TransactionState::new(
-                transaction_ttl,
-                Some(packet),
-                priority,
-                cost,
-            ));
+            entry.insert(TransactionState::new(transaction_ttl, priority, cost));
             TransactionPriorityId::new(priority, transaction_id)
             TransactionPriorityId::new(priority, transaction_id)
         };
         };
 
 
@@ -322,12 +313,12 @@ mod tests {
         super::*,
         super::*,
         crate::banking_stage::scheduler_messages::MaxAge,
         crate::banking_stage::scheduler_messages::MaxAge,
         agave_transaction_view::transaction_view::SanitizedTransactionView,
         agave_transaction_view::transaction_view::SanitizedTransactionView,
+        solana_perf::packet::Packet,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
         solana_sdk::{
         solana_sdk::{
             compute_budget::ComputeBudgetInstruction,
             compute_budget::ComputeBudgetInstruction,
             hash::Hash,
             hash::Hash,
             message::Message,
             message::Message,
-            packet::Packet,
             signature::Keypair,
             signature::Keypair,
             signer::Signer,
             signer::Signer,
             system_instruction,
             system_instruction,
@@ -341,7 +332,6 @@ mod tests {
         priority: u64,
         priority: u64,
     ) -> (
     ) -> (
         SanitizedTransactionTTL<RuntimeTransaction<SanitizedTransaction>>,
         SanitizedTransactionTTL<RuntimeTransaction<SanitizedTransaction>>,
-        Arc<ImmutableDeserializedPacket>,
         u64,
         u64,
         u64,
         u64,
     ) {
     ) {
@@ -356,18 +346,12 @@ mod tests {
             message,
             message,
             Hash::default(),
             Hash::default(),
         ));
         ));
-        let packet = Arc::new(
-            ImmutableDeserializedPacket::new(
-                Packet::from_data(None, tx.to_versioned_transaction()).unwrap(),
-            )
-            .unwrap(),
-        );
         let transaction_ttl = SanitizedTransactionTTL {
         let transaction_ttl = SanitizedTransactionTTL {
             transaction: tx,
             transaction: tx,
             max_age: MaxAge::MAX,
             max_age: MaxAge::MAX,
         };
         };
         const TEST_TRANSACTION_COST: u64 = 5000;
         const TEST_TRANSACTION_COST: u64 = 5000;
-        (transaction_ttl, packet, priority, TEST_TRANSACTION_COST)
+        (transaction_ttl, priority, TEST_TRANSACTION_COST)
     }
     }
 
 
     fn push_to_container(
     fn push_to_container(
@@ -375,8 +359,8 @@ mod tests {
         num: usize,
         num: usize,
     ) {
     ) {
         for priority in 0..num as u64 {
         for priority in 0..num as u64 {
-            let (transaction_ttl, packet, priority, cost) = test_transaction(priority);
-            container.insert_new_transaction(transaction_ttl, packet, priority, cost);
+            let (transaction_ttl, priority, cost) = test_transaction(priority);
+            container.insert_new_transaction(transaction_ttl, priority, cost);
         }
         }
     }
     }
 
 
@@ -446,7 +430,6 @@ mod tests {
                     transaction: view,
                     transaction: view,
                     max_age: MaxAge::MAX,
                     max_age: MaxAge::MAX,
                 },
                 },
-                None,
                 priority,
                 priority,
                 cost,
                 cost,
             ))
             ))
@@ -454,9 +437,12 @@ mod tests {
 
 
         // Push 2 transactions into the queue so buffer is full.
         // Push 2 transactions into the queue so buffer is full.
         for priority in [4, 5] {
         for priority in [4, 5] {
-            let (_transaction_ttl, packet, priority, cost) = test_transaction(priority);
+            let (transaction_ttl, priority, cost) = test_transaction(priority);
+            let packet =
+                Packet::from_data(None, transaction_ttl.transaction.to_versioned_transaction())
+                    .unwrap();
             let id = container
             let id = container
-                .try_insert_map_only_with_data(packet.original_packet().data(..).unwrap(), |data| {
+                .try_insert_map_only_with_data(packet.data(..).unwrap(), |data| {
                     packet_parser(data, priority, cost)
                     packet_parser(data, priority, cost)
                 })
                 })
                 .unwrap();
                 .unwrap();
@@ -470,9 +456,12 @@ mod tests {
         // Push 5 additional packets in. 5 should be dropped.
         // Push 5 additional packets in. 5 should be dropped.
         let mut priority_ids = Vec::with_capacity(5);
         let mut priority_ids = Vec::with_capacity(5);
         for priority in [10, 11, 12, 1, 2] {
         for priority in [10, 11, 12, 1, 2] {
-            let (_transaction_ttl, packet, priority, cost) = test_transaction(priority);
+            let (transaction_ttl, priority, cost) = test_transaction(priority);
+            let packet =
+                Packet::from_data(None, transaction_ttl.transaction.to_versioned_transaction())
+                    .unwrap();
             let id = container
             let id = container
-                .try_insert_map_only_with_data(packet.original_packet().data(..).unwrap(), |data| {
+                .try_insert_map_only_with_data(packet.data(..).unwrap(), |data| {
                     packet_parser(data, priority, cost)
                     packet_parser(data, priority, cost)
                 })
                 })
                 .unwrap();
                 .unwrap();
@@ -488,9 +477,12 @@ mod tests {
         // If we attempt to push additional transactions to the queue, they
         // If we attempt to push additional transactions to the queue, they
         // are rejected regardless of their priority.
         // are rejected regardless of their priority.
         let priority = u64::MAX;
         let priority = u64::MAX;
-        let (_transaction_ttl, packet, priority, cost) = test_transaction(priority);
+        let (transaction_ttl, priority, cost) = test_transaction(priority);
+        let packet =
+            Packet::from_data(None, transaction_ttl.transaction.to_versioned_transaction())
+                .unwrap();
         let id = container
         let id = container
-            .try_insert_map_only_with_data(packet.original_packet().data(..).unwrap(), |data| {
+            .try_insert_map_only_with_data(packet.data(..).unwrap(), |data| {
                 packet_parser(data, priority, cost)
                 packet_parser(data, priority, cost)
             })
             })
             .unwrap();
             .unwrap();

+ 0 - 27
core/src/banking_stage/unprocessed_packet_batches.rs

@@ -15,14 +15,12 @@ use {
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct DeserializedPacket {
 pub struct DeserializedPacket {
     immutable_section: Arc<ImmutableDeserializedPacket>,
     immutable_section: Arc<ImmutableDeserializedPacket>,
-    pub forwarded: bool,
 }
 }
 
 
 impl DeserializedPacket {
 impl DeserializedPacket {
     pub fn from_immutable_section(immutable_section: ImmutableDeserializedPacket) -> Self {
     pub fn from_immutable_section(immutable_section: ImmutableDeserializedPacket) -> Self {
         Self {
         Self {
             immutable_section: Arc::new(immutable_section),
             immutable_section: Arc::new(immutable_section),
-            forwarded: false,
         }
         }
     }
     }
 
 
@@ -31,7 +29,6 @@ impl DeserializedPacket {
 
 
         Ok(Self {
         Ok(Self {
             immutable_section: Arc::new(immutable_section),
             immutable_section: Arc::new(immutable_section),
-            forwarded: false,
         })
         })
     }
     }
 
 
@@ -265,30 +262,6 @@ impl UnprocessedPacketBatches {
     pub fn capacity(&self) -> usize {
     pub fn capacity(&self) -> usize {
         self.packet_priority_queue.capacity()
         self.packet_priority_queue.capacity()
     }
     }
-
-    pub fn is_forwarded(&self, immutable_packet: &ImmutableDeserializedPacket) -> bool {
-        self.message_hash_to_transaction
-            .get(immutable_packet.message_hash())
-            .map_or(true, |p| p.forwarded)
-    }
-
-    pub fn mark_accepted_packets_as_forwarded(
-        &mut self,
-        packets_to_process: &[Arc<ImmutableDeserializedPacket>],
-        accepted_packet_indexes: &[usize],
-    ) {
-        accepted_packet_indexes
-            .iter()
-            .for_each(|accepted_packet_index| {
-                let accepted_packet = packets_to_process[*accepted_packet_index].clone();
-                if let Some(deserialized_packet) = self
-                    .message_hash_to_transaction
-                    .get_mut(accepted_packet.message_hash())
-                {
-                    deserialized_packet.forwarded = true;
-                }
-            });
-    }
 }
 }
 
 
 #[cfg(test)]
 #[cfg(test)]

+ 14 - 543
core/src/banking_stage/unprocessed_transaction_storage.rs

@@ -1,7 +1,6 @@
 use {
 use {
     super::{
     super::{
         consumer::Consumer,
         consumer::Consumer,
-        forward_packet_batches_by_accounts::ForwardPacketBatchesByAccounts,
         immutable_deserialized_packet::ImmutableDeserializedPacket,
         immutable_deserialized_packet::ImmutableDeserializedPacket,
         latest_unprocessed_votes::{
         latest_unprocessed_votes::{
             LatestUnprocessedVotes, LatestValidatorVotePacket, VoteBatchInsertionMetrics,
             LatestUnprocessedVotes, LatestValidatorVotePacket, VoteBatchInsertionMetrics,
@@ -13,19 +12,15 @@ use {
         unprocessed_packet_batches::{
         unprocessed_packet_batches::{
             DeserializedPacket, PacketBatchInsertionMetrics, UnprocessedPacketBatches,
             DeserializedPacket, PacketBatchInsertionMetrics, UnprocessedPacketBatches,
         },
         },
-        BankingStageStats, FilterForwardingResults, ForwardOption,
+        BankingStageStats,
     },
     },
     itertools::Itertools,
     itertools::Itertools,
     min_max_heap::MinMaxHeap,
     min_max_heap::MinMaxHeap,
     solana_accounts_db::account_locks::validate_account_locks,
     solana_accounts_db::account_locks::validate_account_locks,
-    solana_feature_set::FeatureSet,
     solana_measure::measure_us,
     solana_measure::measure_us,
     solana_runtime::bank::Bank,
     solana_runtime::bank::Bank,
     solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
     solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
-    solana_sdk::{
-        clock::FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET, hash::Hash, saturating_add_assign,
-        transaction::SanitizedTransaction,
-    },
+    solana_sdk::{hash::Hash, transaction::SanitizedTransaction},
     solana_svm::transaction_error_metrics::TransactionErrorMetrics,
     solana_svm::transaction_error_metrics::TransactionErrorMetrics,
     std::{
     std::{
         collections::HashMap,
         collections::HashMap,
@@ -316,7 +311,7 @@ impl UnprocessedTransactionStorage {
     }
     }
 
 
     pub fn should_not_process(&self) -> bool {
     pub fn should_not_process(&self) -> bool {
-        // The gossip vote thread does not need to process or forward any votes, that is
+        // The gossip vote thread does not need to process any votes, that is
         // handled by the tpu vote thread
         // handled by the tpu vote thread
         if let Self::VoteStorage(vote_storage) = self {
         if let Self::VoteStorage(vote_storage) = self {
             return matches!(vote_storage.vote_source, VoteSource::Gossip);
             return matches!(vote_storage.vote_source, VoteSource::Gossip);
@@ -332,22 +327,6 @@ impl UnprocessedTransactionStorage {
         }
         }
     }
     }
 
 
-    pub fn forward_option(&self) -> ForwardOption {
-        match self {
-            Self::VoteStorage(vote_storage) => vote_storage.forward_option(),
-            Self::LocalTransactionStorage(transaction_storage) => {
-                transaction_storage.forward_option()
-            }
-        }
-    }
-
-    pub fn clear_forwarded_packets(&mut self) {
-        match self {
-            Self::LocalTransactionStorage(transaction_storage) => transaction_storage.clear(), // Since we set everything as forwarded this is the same
-            Self::VoteStorage(vote_storage) => vote_storage.clear_forwarded_packets(),
-        }
-    }
-
     pub(crate) fn insert_batch(
     pub(crate) fn insert_batch(
         &mut self,
         &mut self,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
@@ -362,25 +341,6 @@ impl UnprocessedTransactionStorage {
         }
         }
     }
     }
 
 
-    pub fn filter_forwardable_packets_and_add_batches(
-        &mut self,
-        bank: Arc<Bank>,
-        forward_packet_batches_by_accounts: &mut ForwardPacketBatchesByAccounts,
-    ) -> FilterForwardingResults {
-        match self {
-            Self::LocalTransactionStorage(transaction_storage) => transaction_storage
-                .filter_forwardable_packets_and_add_batches(
-                    bank,
-                    forward_packet_batches_by_accounts,
-                ),
-            Self::VoteStorage(vote_storage) => vote_storage
-                .filter_forwardable_packets_and_add_batches(
-                    bank,
-                    forward_packet_batches_by_accounts,
-                ),
-        }
-    }
-
     /// The processing function takes a stream of packets ready to process, and returns the indices
     /// The processing function takes a stream of packets ready to process, and returns the indices
     /// of the unprocessed packets that are eligible for retry. A return value of None means that
     /// of the unprocessed packets that are eligible for retry. A return value of None means that
     /// all packets are unprocessed and eligible for retry.
     /// all packets are unprocessed and eligible for retry.
@@ -415,6 +375,13 @@ impl UnprocessedTransactionStorage {
         }
         }
     }
     }
 
 
+    pub(crate) fn clear(&mut self) {
+        match self {
+            Self::LocalTransactionStorage(_) => {}
+            Self::VoteStorage(vote_storage) => vote_storage.clear(),
+        }
+    }
+
     pub(crate) fn cache_epoch_boundary_info(&mut self, bank: &Bank) {
     pub(crate) fn cache_epoch_boundary_info(&mut self, bank: &Bank) {
         match self {
         match self {
             Self::LocalTransactionStorage(_) => (),
             Self::LocalTransactionStorage(_) => (),
@@ -436,17 +403,6 @@ impl VoteStorage {
         MAX_NUM_VOTES_RECEIVE
         MAX_NUM_VOTES_RECEIVE
     }
     }
 
 
-    fn forward_option(&self) -> ForwardOption {
-        match self.vote_source {
-            VoteSource::Tpu => ForwardOption::ForwardTpuVote,
-            VoteSource::Gossip => ForwardOption::NotForward,
-        }
-    }
-
-    fn clear_forwarded_packets(&mut self) {
-        self.latest_unprocessed_votes.clear_forwarded_packets();
-    }
-
     fn insert_batch(
     fn insert_batch(
         &mut self,
         &mut self,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
@@ -467,23 +423,6 @@ impl VoteStorage {
         )
         )
     }
     }
 
 
-    fn filter_forwardable_packets_and_add_batches(
-        &mut self,
-        bank: Arc<Bank>,
-        forward_packet_batches_by_accounts: &mut ForwardPacketBatchesByAccounts,
-    ) -> FilterForwardingResults {
-        if matches!(self.vote_source, VoteSource::Tpu) {
-            let total_forwardable_packets = self
-                .latest_unprocessed_votes
-                .get_and_insert_forwardable_packets(bank, forward_packet_batches_by_accounts);
-            return FilterForwardingResults {
-                total_forwardable_packets,
-                ..FilterForwardingResults::default()
-            };
-        }
-        FilterForwardingResults::default()
-    }
-
     // returns `true` if the end of slot is reached
     // returns `true` if the end of slot is reached
     fn process_packets<F>(
     fn process_packets<F>(
         &mut self,
         &mut self,
@@ -560,6 +499,10 @@ impl VoteStorage {
         scanner.finalize().payload.reached_end_of_slot
         scanner.finalize().payload.reached_end_of_slot
     }
     }
 
 
+    fn clear(&mut self) {
+        self.latest_unprocessed_votes.clear();
+    }
+
     fn cache_epoch_boundary_info(&mut self, bank: &Bank) {
     fn cache_epoch_boundary_info(&mut self, bank: &Bank) {
         if matches!(self.vote_source, VoteSource::Gossip) {
         if matches!(self.vote_source, VoteSource::Gossip) {
             panic!("Gossip vote thread should not be checking epoch boundary");
             panic!("Gossip vote thread should not be checking epoch boundary");
@@ -603,18 +546,6 @@ impl ThreadLocalUnprocessedPackets {
         self.unprocessed_packet_batches.iter_mut()
         self.unprocessed_packet_batches.iter_mut()
     }
     }
 
 
-    fn forward_option(&self) -> ForwardOption {
-        match self.thread_type {
-            ThreadType::Transactions => ForwardOption::ForwardTransaction,
-            ThreadType::Voting(VoteSource::Tpu) => ForwardOption::ForwardTpuVote,
-            ThreadType::Voting(VoteSource::Gossip) => ForwardOption::NotForward,
-        }
-    }
-
-    fn clear(&mut self) {
-        self.unprocessed_packet_batches.clear();
-    }
-
     fn insert_batch(
     fn insert_batch(
         &mut self,
         &mut self,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
         deserialized_packets: Vec<ImmutableDeserializedPacket>,
@@ -626,123 +557,6 @@ impl ThreadLocalUnprocessedPackets {
         )
         )
     }
     }
 
 
-    /// Filter out packets that fail to sanitize, or are no longer valid (could be
-    /// too old, a duplicate of something already processed). Doing this in batches to avoid
-    /// checking bank's blockhash and status cache per transaction which could be bad for performance.
-    /// Added valid and sanitized packets to forwarding queue.
-    fn filter_forwardable_packets_and_add_batches(
-        &mut self,
-        bank: Arc<Bank>,
-        forward_buffer: &mut ForwardPacketBatchesByAccounts,
-    ) -> FilterForwardingResults {
-        let mut total_forwardable_packets: usize = 0;
-        let mut total_packet_conversion_us: u64 = 0;
-        let mut total_filter_packets_us: u64 = 0;
-        let mut total_dropped_packets: usize = 0;
-
-        let mut original_priority_queue = self.take_priority_queue();
-        let original_capacity = original_priority_queue.capacity();
-        let mut new_priority_queue = MinMaxHeap::with_capacity(original_capacity);
-
-        // indicates if `forward_buffer` still accept more packets, see details at
-        // `ForwardPacketBatchesByAccounts.rs`.
-        let mut accepting_packets = true;
-        // batch iterate through self.unprocessed_packet_batches in desc priority order
-        new_priority_queue.extend(
-            original_priority_queue
-                .drain_desc()
-                .chunks(UNPROCESSED_BUFFER_STEP_SIZE)
-                .into_iter()
-                .flat_map(|packets_to_process| {
-                    // Only process packets not yet forwarded
-                    let (forwarded_packets, packets_to_forward) =
-                        self.prepare_packets_to_forward(packets_to_process);
-
-                    [
-                        forwarded_packets,
-                        if accepting_packets {
-                            let (
-                                (sanitized_transactions, transaction_to_packet_indexes),
-                                packet_conversion_us,
-                            ) = measure_us!(self.sanitize_unforwarded_packets(
-                                &packets_to_forward,
-                                &bank,
-                                &mut total_dropped_packets
-                            ));
-                            saturating_add_assign!(
-                                total_packet_conversion_us,
-                                packet_conversion_us
-                            );
-
-                            let (forwardable_transaction_indexes, filter_packets_us) =
-                                measure_us!(Self::filter_invalid_transactions(
-                                    &sanitized_transactions,
-                                    &bank,
-                                    &mut total_dropped_packets
-                                ));
-                            saturating_add_assign!(total_filter_packets_us, filter_packets_us);
-                            saturating_add_assign!(
-                                total_forwardable_packets,
-                                forwardable_transaction_indexes.len()
-                            );
-
-                            let accepted_packet_indexes =
-                                Self::add_filtered_packets_to_forward_buffer(
-                                    forward_buffer,
-                                    &packets_to_forward,
-                                    &sanitized_transactions,
-                                    &transaction_to_packet_indexes,
-                                    &forwardable_transaction_indexes,
-                                    &mut total_dropped_packets,
-                                    &bank.feature_set,
-                                );
-                            accepting_packets = accepted_packet_indexes.len()
-                                == forwardable_transaction_indexes.len();
-
-                            self.unprocessed_packet_batches
-                                .mark_accepted_packets_as_forwarded(
-                                    &packets_to_forward,
-                                    &accepted_packet_indexes,
-                                );
-
-                            Self::collect_retained_packets(
-                                &mut self.unprocessed_packet_batches.message_hash_to_transaction,
-                                &packets_to_forward,
-                                &Self::prepare_filtered_packet_indexes(
-                                    &transaction_to_packet_indexes,
-                                    &forwardable_transaction_indexes,
-                                ),
-                            )
-                        } else {
-                            // skip sanitizing and filtering if not longer able to add more packets for forwarding
-                            saturating_add_assign!(total_dropped_packets, packets_to_forward.len());
-                            packets_to_forward
-                        },
-                    ]
-                    .concat()
-                }),
-        );
-
-        // replace packet priority queue
-        self.unprocessed_packet_batches.packet_priority_queue = new_priority_queue;
-        self.verify_priority_queue(original_capacity);
-
-        // Assert unprocessed queue is still consistent
-        assert_eq!(
-            self.unprocessed_packet_batches.packet_priority_queue.len(),
-            self.unprocessed_packet_batches
-                .message_hash_to_transaction
-                .len()
-        );
-
-        FilterForwardingResults {
-            total_forwardable_packets,
-            total_dropped_packets,
-            total_packet_conversion_us,
-            total_filter_packets_us,
-        }
-    }
-
     /// Take self.unprocessed_packet_batches's priority_queue out, leave empty MinMaxHeap in its place.
     /// Take self.unprocessed_packet_batches's priority_queue out, leave empty MinMaxHeap in its place.
     fn take_priority_queue(&mut self) -> MinMaxHeap<Arc<ImmutableDeserializedPacket>> {
     fn take_priority_queue(&mut self) -> MinMaxHeap<Arc<ImmutableDeserializedPacket>> {
         std::mem::replace(
         std::mem::replace(
@@ -768,105 +582,6 @@ impl ThreadLocalUnprocessedPackets {
         );
         );
     }
     }
 
 
-    /// sanitize un-forwarded packet into SanitizedTransaction for validation and forwarding.
-    fn sanitize_unforwarded_packets(
-        &mut self,
-        packets_to_process: &[Arc<ImmutableDeserializedPacket>],
-        bank: &Bank,
-        total_dropped_packets: &mut usize,
-    ) -> (Vec<RuntimeTransaction<SanitizedTransaction>>, Vec<usize>) {
-        // Get ref of ImmutableDeserializedPacket
-        let deserialized_packets = packets_to_process.iter().map(|p| &**p);
-        let (transactions, transaction_to_packet_indexes): (Vec<_>, Vec<_>) = deserialized_packets
-            .enumerate()
-            .filter_map(|(packet_index, deserialized_packet)| {
-                deserialized_packet
-                    .build_sanitized_transaction(
-                        bank.vote_only_bank(),
-                        bank,
-                        bank.get_reserved_account_keys(),
-                    )
-                    .map(|(transaction, _deactivation_slot)| (transaction, packet_index))
-            })
-            .unzip();
-
-        let filtered_count = packets_to_process.len().saturating_sub(transactions.len());
-        saturating_add_assign!(*total_dropped_packets, filtered_count);
-
-        (transactions, transaction_to_packet_indexes)
-    }
-
-    /// Checks sanitized transactions against bank, returns valid transaction indexes
-    fn filter_invalid_transactions(
-        transactions: &[RuntimeTransaction<SanitizedTransaction>],
-        bank: &Bank,
-        total_dropped_packets: &mut usize,
-    ) -> Vec<usize> {
-        let filter = vec![Ok(()); transactions.len()];
-        let results = bank.check_transactions_with_forwarding_delay(
-            transactions,
-            &filter,
-            FORWARD_TRANSACTIONS_TO_LEADER_AT_SLOT_OFFSET,
-        );
-
-        let filtered_count = transactions.len().saturating_sub(results.len());
-        saturating_add_assign!(*total_dropped_packets, filtered_count);
-
-        results
-            .iter()
-            .enumerate()
-            .filter_map(|(tx_index, result)| result.as_ref().ok().map(|_| tx_index))
-            .collect_vec()
-    }
-
-    fn prepare_filtered_packet_indexes(
-        transaction_to_packet_indexes: &[usize],
-        retained_transaction_indexes: &[usize],
-    ) -> Vec<usize> {
-        retained_transaction_indexes
-            .iter()
-            .map(|tx_index| transaction_to_packet_indexes[*tx_index])
-            .collect_vec()
-    }
-
-    /// try to add filtered forwardable and valid packets to forward buffer;
-    /// returns vector of packet indexes that were accepted for forwarding.
-    fn add_filtered_packets_to_forward_buffer(
-        forward_buffer: &mut ForwardPacketBatchesByAccounts,
-        packets_to_process: &[Arc<ImmutableDeserializedPacket>],
-        transactions: &[RuntimeTransaction<SanitizedTransaction>],
-        transaction_to_packet_indexes: &[usize],
-        forwardable_transaction_indexes: &[usize],
-        total_dropped_packets: &mut usize,
-        feature_set: &FeatureSet,
-    ) -> Vec<usize> {
-        let mut added_packets_count: usize = 0;
-        let mut accepted_packet_indexes = Vec::with_capacity(transaction_to_packet_indexes.len());
-        for forwardable_transaction_index in forwardable_transaction_indexes {
-            let sanitized_transaction = &transactions[*forwardable_transaction_index];
-            let forwardable_packet_index =
-                transaction_to_packet_indexes[*forwardable_transaction_index];
-            let immutable_deserialized_packet =
-                packets_to_process[forwardable_packet_index].clone();
-            if !forward_buffer.try_add_packet(
-                sanitized_transaction,
-                immutable_deserialized_packet,
-                feature_set,
-            ) {
-                break;
-            }
-            accepted_packet_indexes.push(forwardable_packet_index);
-            saturating_add_assign!(added_packets_count, 1);
-        }
-
-        let filtered_count = forwardable_transaction_indexes
-            .len()
-            .saturating_sub(added_packets_count);
-        saturating_add_assign!(*total_dropped_packets, filtered_count);
-
-        accepted_packet_indexes
-    }
-
     fn collect_retained_packets(
     fn collect_retained_packets(
         message_hash_to_transaction: &mut HashMap<Hash, DeserializedPacket>,
         message_hash_to_transaction: &mut HashMap<Hash, DeserializedPacket>,
         packets_to_process: &[Arc<ImmutableDeserializedPacket>],
         packets_to_process: &[Arc<ImmutableDeserializedPacket>],
@@ -959,36 +674,6 @@ impl ThreadLocalUnprocessedPackets {
 
 
         reached_end_of_slot
         reached_end_of_slot
     }
     }
-
-    /// Prepare a chunk of packets for forwarding, filter out already forwarded packets while
-    /// counting tracers.
-    /// Returns Vec of unforwarded packets, and Vec<bool> of same size each indicates corresponding
-    /// packet is tracer packet.
-    fn prepare_packets_to_forward(
-        &self,
-        packets_to_forward: impl Iterator<Item = Arc<ImmutableDeserializedPacket>>,
-    ) -> (
-        Vec<Arc<ImmutableDeserializedPacket>>,
-        Vec<Arc<ImmutableDeserializedPacket>>,
-    ) {
-        let mut forwarded_packets: Vec<Arc<ImmutableDeserializedPacket>> = vec![];
-        let forwardable_packets = packets_to_forward
-            .into_iter()
-            .filter_map(|immutable_deserialized_packet| {
-                if !self
-                    .unprocessed_packet_batches
-                    .is_forwarded(&immutable_deserialized_packet)
-                {
-                    Some(immutable_deserialized_packet)
-                } else {
-                    forwarded_packets.push(immutable_deserialized_packet);
-                    None
-                }
-            })
-            .collect();
-
-        (forwarded_packets, forwardable_packets)
-    }
 }
 }
 
 
 #[cfg(test)]
 #[cfg(test)]
@@ -996,14 +681,12 @@ mod tests {
     use {
     use {
         super::*,
         super::*,
         itertools::iproduct,
         itertools::iproduct,
-        solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo},
         solana_perf::packet::{Packet, PacketFlags},
         solana_perf::packet::{Packet, PacketFlags},
         solana_runtime::genesis_utils,
         solana_runtime::genesis_utils,
         solana_sdk::{
         solana_sdk::{
             hash::Hash,
             hash::Hash,
             signature::{Keypair, Signer},
             signature::{Keypair, Signer},
             system_transaction,
             system_transaction,
-            transaction::Transaction,
         },
         },
         solana_vote::vote_transaction::new_tower_sync_transaction,
         solana_vote::vote_transaction::new_tower_sync_transaction,
         solana_vote_program::vote_state::TowerSync,
         solana_vote_program::vote_state::TowerSync,
@@ -1061,126 +744,6 @@ mod tests {
         assert_eq!(non_retryable_indexes, vec![(0, 1), (4, 5), (6, 8)]);
         assert_eq!(non_retryable_indexes, vec![(0, 1), (4, 5), (6, 8)]);
     }
     }
 
 
-    #[test]
-    fn test_filter_and_forward_with_account_limits() {
-        solana_logger::setup();
-        let GenesisConfigInfo {
-            genesis_config,
-            mint_keypair,
-            ..
-        } = create_genesis_config(10);
-        let (current_bank, _bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
-
-        let simple_transactions: Vec<Transaction> = (0..256)
-            .map(|_id| {
-                // packets are deserialized upon receiving, failed packets will not be
-                // forwarded; Therefore we need to create real packets here.
-                let key1 = Keypair::new();
-                system_transaction::transfer(
-                    &mint_keypair,
-                    &key1.pubkey(),
-                    genesis_config.rent.minimum_balance(0),
-                    genesis_config.hash(),
-                )
-            })
-            .collect_vec();
-
-        let mut packets: Vec<DeserializedPacket> = simple_transactions
-            .iter()
-            .enumerate()
-            .map(|(packets_id, transaction)| {
-                let mut p = Packet::from_data(None, transaction).unwrap();
-                p.meta_mut().port = packets_id as u16;
-                DeserializedPacket::new(p).unwrap()
-            })
-            .collect_vec();
-
-        // all packets are forwarded
-        {
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let mut transaction_storage = UnprocessedTransactionStorage::new_transaction_storage(
-                buffered_packet_batches,
-                ThreadType::Transactions,
-            );
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-
-            let FilterForwardingResults {
-                total_forwardable_packets,
-                ..
-            } = transaction_storage.filter_forwardable_packets_and_add_batches(
-                current_bank.clone(),
-                &mut forward_packet_batches_by_accounts,
-            );
-            assert_eq!(total_forwardable_packets, 256);
-
-            // packets in a batch are forwarded in arbitrary order; verify the ports match after
-            // sorting
-            let expected_ports: Vec<_> = (0..256).collect();
-            let mut forwarded_ports: Vec<_> = forward_packet_batches_by_accounts
-                .iter_batches()
-                .flat_map(|batch| batch.get_forwardable_packets().map(|p| p.meta().port))
-                .collect();
-            forwarded_ports.sort_unstable();
-            assert_eq!(expected_ports, forwarded_ports);
-        }
-
-        // some packets are forwarded
-        {
-            let num_already_forwarded = 16;
-            for packet in &mut packets[0..num_already_forwarded] {
-                packet.forwarded = true;
-            }
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let mut transaction_storage = UnprocessedTransactionStorage::new_transaction_storage(
-                buffered_packet_batches,
-                ThreadType::Transactions,
-            );
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-            let FilterForwardingResults {
-                total_forwardable_packets,
-                ..
-            } = transaction_storage.filter_forwardable_packets_and_add_batches(
-                current_bank.clone(),
-                &mut forward_packet_batches_by_accounts,
-            );
-            assert_eq!(
-                total_forwardable_packets,
-                packets.len() - num_already_forwarded
-            );
-        }
-
-        // some packets are invalid (already processed)
-        {
-            let num_already_processed = 16;
-            for tx in &simple_transactions[0..num_already_processed] {
-                assert_eq!(current_bank.process_transaction(tx), Ok(()));
-            }
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let mut transaction_storage = UnprocessedTransactionStorage::new_transaction_storage(
-                buffered_packet_batches,
-                ThreadType::Transactions,
-            );
-            let mut forward_packet_batches_by_accounts =
-                ForwardPacketBatchesByAccounts::new_with_default_batch_limits();
-            let FilterForwardingResults {
-                total_forwardable_packets,
-                ..
-            } = transaction_storage.filter_forwardable_packets_and_add_batches(
-                current_bank,
-                &mut forward_packet_batches_by_accounts,
-            );
-            assert_eq!(
-                total_forwardable_packets,
-                packets.len() - num_already_processed
-            );
-        }
-    }
-
     #[test]
     #[test]
     fn test_unprocessed_transaction_storage_insert() -> Result<(), Box<dyn Error>> {
     fn test_unprocessed_transaction_storage_insert() -> Result<(), Box<dyn Error>> {
         let keypair = Keypair::new();
         let keypair = Keypair::new();
@@ -1309,96 +872,4 @@ mod tests {
         assert_eq!(1, transaction_storage.len());
         assert_eq!(1, transaction_storage.len());
         Ok(())
         Ok(())
     }
     }
-
-    #[test]
-    fn test_prepare_packets_to_forward() {
-        solana_logger::setup();
-        let GenesisConfigInfo {
-            genesis_config,
-            mint_keypair,
-            ..
-        } = create_genesis_config(10);
-
-        let simple_transactions: Vec<Transaction> = (0..256)
-            .map(|_id| {
-                // packets are deserialized upon receiving, failed packets will not be
-                // forwarded; Therefore we need to create real packets here.
-                let key1 = Keypair::new();
-                system_transaction::transfer(
-                    &mint_keypair,
-                    &key1.pubkey(),
-                    genesis_config.rent.minimum_balance(0),
-                    genesis_config.hash(),
-                )
-            })
-            .collect_vec();
-
-        let mut packets: Vec<DeserializedPacket> = simple_transactions
-            .iter()
-            .enumerate()
-            .map(|(packets_id, transaction)| {
-                let mut p = Packet::from_data(None, transaction).unwrap();
-                p.meta_mut().port = packets_id as u16;
-                DeserializedPacket::new(p).unwrap()
-            })
-            .collect_vec();
-
-        // test preparing buffered packets for forwarding
-        let test_prepareing_buffered_packets_for_forwarding =
-            |buffered_packet_batches: UnprocessedPacketBatches| -> usize {
-                let mut total_packets_to_forward: usize = 0;
-
-                let mut unprocessed_transactions = ThreadLocalUnprocessedPackets {
-                    unprocessed_packet_batches: buffered_packet_batches,
-                    thread_type: ThreadType::Transactions,
-                };
-
-                let mut original_priority_queue = unprocessed_transactions.take_priority_queue();
-                let _ = original_priority_queue
-                    .drain_desc()
-                    .chunks(128usize)
-                    .into_iter()
-                    .flat_map(|packets_to_process| {
-                        let (_, packets_to_forward) =
-                            unprocessed_transactions.prepare_packets_to_forward(packets_to_process);
-                        total_packets_to_forward += packets_to_forward.len();
-                        packets_to_forward
-                    })
-                    .collect::<MinMaxHeap<Arc<ImmutableDeserializedPacket>>>();
-                total_packets_to_forward
-            };
-
-        {
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let total_packets_to_forward =
-                test_prepareing_buffered_packets_for_forwarding(buffered_packet_batches);
-            assert_eq!(total_packets_to_forward, 256);
-        }
-
-        // some packets are forwarded
-        {
-            let num_already_forwarded = 16;
-            for packet in &mut packets[0..num_already_forwarded] {
-                packet.forwarded = true;
-            }
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let total_packets_to_forward =
-                test_prepareing_buffered_packets_for_forwarding(buffered_packet_batches);
-            assert_eq!(total_packets_to_forward, 256 - num_already_forwarded);
-        }
-
-        // all packets are forwarded
-        {
-            for packet in &mut packets {
-                packet.forwarded = true;
-            }
-            let buffered_packet_batches: UnprocessedPacketBatches =
-                UnprocessedPacketBatches::from_iter(packets.clone(), packets.len());
-            let total_packets_to_forward =
-                test_prepareing_buffered_packets_for_forwarding(buffered_packet_batches);
-            assert_eq!(total_packets_to_forward, 0);
-        }
-    }
 }
 }

+ 23 - 7
core/src/sigverify.rs

@@ -13,27 +13,36 @@ use {
         sigverify_stage::{SigVerifier, SigVerifyServiceError},
         sigverify_stage::{SigVerifier, SigVerifyServiceError},
     },
     },
     agave_banking_stage_ingress_types::BankingPacketBatch,
     agave_banking_stage_ingress_types::BankingPacketBatch,
+    crossbeam_channel::Sender,
     solana_perf::{cuda_runtime::PinnedVec, packet::PacketBatch, recycler::Recycler, sigverify},
     solana_perf::{cuda_runtime::PinnedVec, packet::PacketBatch, recycler::Recycler, sigverify},
 };
 };
 
 
 pub struct TransactionSigVerifier {
 pub struct TransactionSigVerifier {
-    packet_sender: BankingPacketSender,
+    banking_stage_sender: BankingPacketSender,
+    forward_stage_sender: Option<Sender<(BankingPacketBatch, bool)>>,
     recycler: Recycler<TxOffset>,
     recycler: Recycler<TxOffset>,
     recycler_out: Recycler<PinnedVec<u8>>,
     recycler_out: Recycler<PinnedVec<u8>>,
     reject_non_vote: bool,
     reject_non_vote: bool,
 }
 }
 
 
 impl TransactionSigVerifier {
 impl TransactionSigVerifier {
-    pub fn new_reject_non_vote(packet_sender: BankingPacketSender) -> Self {
-        let mut new_self = Self::new(packet_sender);
+    pub fn new_reject_non_vote(
+        packet_sender: BankingPacketSender,
+        forward_stage_sender: Option<Sender<(BankingPacketBatch, bool)>>,
+    ) -> Self {
+        let mut new_self = Self::new(packet_sender, forward_stage_sender);
         new_self.reject_non_vote = true;
         new_self.reject_non_vote = true;
         new_self
         new_self
     }
     }
 
 
-    pub fn new(packet_sender: BankingPacketSender) -> Self {
+    pub fn new(
+        banking_stage_sender: BankingPacketSender,
+        forward_stage_sender: Option<Sender<(BankingPacketBatch, bool)>>,
+    ) -> Self {
         init();
         init();
         Self {
         Self {
-            packet_sender,
+            banking_stage_sender,
+            forward_stage_sender,
             recycler: Recycler::warmed(50, 4096),
             recycler: Recycler::warmed(50, 4096),
             recycler_out: Recycler::warmed(50, 4096),
             recycler_out: Recycler::warmed(50, 4096),
             reject_non_vote: false,
             reject_non_vote: false,
@@ -48,8 +57,15 @@ impl SigVerifier for TransactionSigVerifier {
         &mut self,
         &mut self,
         packet_batches: Vec<PacketBatch>,
         packet_batches: Vec<PacketBatch>,
     ) -> Result<(), SigVerifyServiceError<Self::SendType>> {
     ) -> Result<(), SigVerifyServiceError<Self::SendType>> {
-        self.packet_sender
-            .send(BankingPacketBatch::new(packet_batches))?;
+        let banking_packet_batch = BankingPacketBatch::new(packet_batches);
+        if let Some(forward_stage_sender) = &self.forward_stage_sender {
+            self.banking_stage_sender
+                .send(banking_packet_batch.clone())?;
+            let _ = forward_stage_sender.try_send((banking_packet_batch, self.reject_non_vote));
+        } else {
+            self.banking_stage_sender.send(banking_packet_batch)?;
+        }
+
         Ok(())
         Ok(())
     }
     }
 
 

+ 1 - 1
core/src/sigverify_stage.rs

@@ -498,7 +498,7 @@ mod tests {
         trace!("start");
         trace!("start");
         let (packet_s, packet_r) = unbounded();
         let (packet_s, packet_r) = unbounded();
         let (verified_s, verified_r) = BankingTracer::channel_for_test();
         let (verified_s, verified_r) = BankingTracer::channel_for_test();
-        let verifier = TransactionSigVerifier::new(verified_s);
+        let verifier = TransactionSigVerifier::new(verified_s, None);
         let stage = SigVerifyStage::new(packet_r, verifier, "solSigVerTest", "test");
         let stage = SigVerifyStage::new(packet_r, verifier, "solSigVerTest", "test");
 
 
         let now = Instant::now();
         let now = Instant::now();

+ 25 - 6
core/src/tpu.rs

@@ -17,6 +17,7 @@ use {
             VerifiedVoteSender, VoteTracker,
             VerifiedVoteSender, VoteTracker,
         },
         },
         fetch_stage::FetchStage,
         fetch_stage::FetchStage,
+        forwarding_stage::ForwardingStage,
         sigverify::TransactionSigVerifier,
         sigverify::TransactionSigVerifier,
         sigverify_stage::SigVerifyStage,
         sigverify_stage::SigVerifyStage,
         staked_nodes_updater_service::StakedNodesUpdaterService,
         staked_nodes_updater_service::StakedNodesUpdaterService,
@@ -24,13 +25,14 @@ use {
         validator::{BlockProductionMethod, GeneratorConfig, TransactionStructure},
         validator::{BlockProductionMethod, GeneratorConfig, TransactionStructure},
     },
     },
     bytes::Bytes,
     bytes::Bytes,
-    crossbeam_channel::{unbounded, Receiver},
+    crossbeam_channel::{bounded, unbounded, Receiver},
     solana_client::connection_cache::ConnectionCache,
     solana_client::connection_cache::ConnectionCache,
     solana_gossip::cluster_info::ClusterInfo,
     solana_gossip::cluster_info::ClusterInfo,
     solana_ledger::{
     solana_ledger::{
         blockstore::Blockstore, blockstore_processor::TransactionStatusSender,
         blockstore::Blockstore, blockstore_processor::TransactionStatusSender,
         entry_notifier_service::EntryNotifierSender,
         entry_notifier_service::EntryNotifierSender,
     },
     },
+    solana_perf::data_budget::DataBudget,
     solana_poh::poh_recorder::{PohRecorder, WorkingBankEntry},
     solana_poh::poh_recorder::{PohRecorder, WorkingBankEntry},
     solana_rpc::{
     solana_rpc::{
         optimistically_confirmed_bank_tracker::BankNotificationSender,
         optimistically_confirmed_bank_tracker::BankNotificationSender,
@@ -39,6 +41,7 @@ use {
     solana_runtime::{
     solana_runtime::{
         bank_forks::BankForks,
         bank_forks::BankForks,
         prioritization_fee_cache::PrioritizationFeeCache,
         prioritization_fee_cache::PrioritizationFeeCache,
+        root_bank_cache::RootBankCache,
         vote_sender_types::{ReplayVoteReceiver, ReplayVoteSender},
         vote_sender_types::{ReplayVoteReceiver, ReplayVoteSender},
     },
     },
     solana_sdk::{clock::Slot, pubkey::Pubkey, quic::NotifyKeyUpdate, signature::Keypair},
     solana_sdk::{clock::Slot, pubkey::Pubkey, quic::NotifyKeyUpdate, signature::Keypair},
@@ -51,7 +54,7 @@ use {
         collections::HashMap,
         collections::HashMap,
         net::{SocketAddr, UdpSocket},
         net::{SocketAddr, UdpSocket},
         sync::{atomic::AtomicBool, Arc, RwLock},
         sync::{atomic::AtomicBool, Arc, RwLock},
-        thread,
+        thread::{self, JoinHandle},
         time::Duration,
         time::Duration,
     },
     },
     tokio::sync::mpsc::Sender as AsyncSender,
     tokio::sync::mpsc::Sender as AsyncSender,
@@ -72,6 +75,7 @@ pub struct Tpu {
     sigverify_stage: SigVerifyStage,
     sigverify_stage: SigVerifyStage,
     vote_sigverify_stage: SigVerifyStage,
     vote_sigverify_stage: SigVerifyStage,
     banking_stage: BankingStage,
     banking_stage: BankingStage,
+    forwarding_stage: JoinHandle<()>,
     cluster_info_vote_listener: ClusterInfoVoteListener,
     cluster_info_vote_listener: ClusterInfoVoteListener,
     broadcast_stage: BroadcastStage,
     broadcast_stage: BroadcastStage,
     tpu_quic_t: thread::JoinHandle<()>,
     tpu_quic_t: thread::JoinHandle<()>,
@@ -219,13 +223,20 @@ impl Tpu {
         )
         )
         .unwrap();
         .unwrap();
 
 
+        let (forward_stage_sender, forward_stage_receiver) = bounded(1024);
         let sigverify_stage = {
         let sigverify_stage = {
-            let verifier = TransactionSigVerifier::new(non_vote_sender);
+            let verifier = TransactionSigVerifier::new(
+                non_vote_sender,
+                enable_block_production_forwarding.then(|| forward_stage_sender.clone()),
+            );
             SigVerifyStage::new(packet_receiver, verifier, "solSigVerTpu", "tpu-verifier")
             SigVerifyStage::new(packet_receiver, verifier, "solSigVerTpu", "tpu-verifier")
         };
         };
 
 
         let vote_sigverify_stage = {
         let vote_sigverify_stage = {
-            let verifier = TransactionSigVerifier::new_reject_non_vote(tpu_vote_sender);
+            let verifier = TransactionSigVerifier::new_reject_non_vote(
+                tpu_vote_sender,
+                Some(forward_stage_sender),
+            );
             SigVerifyStage::new(
             SigVerifyStage::new(
                 vote_packet_receiver,
                 vote_packet_receiver,
                 verifier,
                 verifier,
@@ -260,10 +271,16 @@ impl Tpu {
             transaction_status_sender,
             transaction_status_sender,
             replay_vote_sender,
             replay_vote_sender,
             log_messages_bytes_limit,
             log_messages_bytes_limit,
-            connection_cache.clone(),
             bank_forks.clone(),
             bank_forks.clone(),
             prioritization_fee_cache,
             prioritization_fee_cache,
-            enable_block_production_forwarding,
+        );
+
+        let forwarding_stage = ForwardingStage::spawn(
+            forward_stage_receiver,
+            connection_cache.clone(),
+            RootBankCache::new(bank_forks.clone()),
+            (cluster_info.clone(), poh_recorder.clone()),
+            DataBudget::default(),
         );
         );
 
 
         let (entry_receiver, tpu_entry_notifier) =
         let (entry_receiver, tpu_entry_notifier) =
@@ -298,6 +315,7 @@ impl Tpu {
                 sigverify_stage,
                 sigverify_stage,
                 vote_sigverify_stage,
                 vote_sigverify_stage,
                 banking_stage,
                 banking_stage,
+                forwarding_stage,
                 cluster_info_vote_listener,
                 cluster_info_vote_listener,
                 broadcast_stage,
                 broadcast_stage,
                 tpu_quic_t,
                 tpu_quic_t,
@@ -318,6 +336,7 @@ impl Tpu {
             self.vote_sigverify_stage.join(),
             self.vote_sigverify_stage.join(),
             self.cluster_info_vote_listener.join(),
             self.cluster_info_vote_listener.join(),
             self.banking_stage.join(),
             self.banking_stage.join(),
+            self.forwarding_stage.join(),
             self.staked_nodes_updater_service.join(),
             self.staked_nodes_updater_service.join(),
             self.tpu_quic_t.join(),
             self.tpu_quic_t.join(),
             self.tpu_forwards_quic_t.join(),
             self.tpu_forwards_quic_t.join(),

+ 24 - 18
docs/art/tpu.bob

@@ -1,19 +1,25 @@
 
 
-                                        .-------------.
-                                        | PoH Service |
-                                        `--------+----`
-                                            ^    |
-             .------------------------------|----|--------------------.
-             | TPU                          |    v                    |
-             |  .-------.  .-----------.  .-+-------.  .-----------.  |  .------------.
- .---------. |  | Fetch |  | SigVerify |  | Banking |  | Broadcast |  |  | Downstream |
- | Clients |--->| Stage |->| Stage     |->| Stage   |->| Stage     |---->| Validators |
- `---------` |  |       |  |           |  |         |  |           |  |  |            |
-             |  `-------`  `-----------`  `----+----`  `-----------`  |  `------------`
-             |                                 |                      |
-             `---------------------------------|----------------------`
-                                               |
-                                               v
-                                            .------.
-                                            | Bank |
-                                            `------`
+                                          .-------------.
+                                          | PoH Service |
+                                          `--------+----`
+                                              ^    |
+             .--------------------------------|----|--------------------.
+             | TPU                            |    v                    |
+             |  .-------.  .-----------.    .-+-------.  .-----------.  |  .------------.
+ .---------. |  | Fetch |  | SigVerify |    | Banking |  | Broadcast |  |  | Downstream |
+ | Clients |--->| Stage |->| Stage     |-+->| Stage   |->| Stage     |---->| Validators |
+ `---------` |  |       |  |           | |  |         |  |           |  |  |            |
+             |  `-------`  `-----------` |  `----+----`  `-----------`  |  `------------`
+             |                           v       |                      |
+             |                  .--------+---.   |                      |
+             |                  | Forwarding |   |                      |
+             |                  | Stage      |   |                      |
+             |                  |            |   |                      |
+             |                  `------------`   |                      |
+             |                                   |                      |
+             `-----------------------------------|----------------------`
+                                                 |
+                                                 v
+                                              .------.
+                                              | Bank |
+                                              `------`

+ 8 - 3
docs/src/validator/tpu.md

@@ -31,9 +31,14 @@ transactions when running into this situation.
 to remove excessive packets before then filtering packets with invalid
 to remove excessive packets before then filtering packets with invalid
 signatures by setting the packet's discard flag.
 signatures by setting the packet's discard flag.
 
 
-* banking stage: decides whether to forward, hold or process packets
-received. Once it detects the node is the block producer it processes
-held packets and newly received packets with a Bank at the tip slot.
+* banking stage: receives and buffers packet when the node is close to
+becoming the leader. Once it detects the node is the block producer it
+processes held packets and newly received packets with a Bank at the tip slot.
+
+* forwarding stage: forwards received packets to a node that is or will soon
+be leader. Sorts packets by priority and forwards them. Non-vote transactions
+are only forwarded if the node has the option enabled (stake overrides) but
+will always forward tpu votes.
 
 
 * broadcast stage: receives the valid transactions formed into Entry's from
 * broadcast stage: receives the valid transactions formed into Entry's from
 banking stage and packages them into shreds to send to network peers through
 banking stage and packages them into shreds to send to network peers through

+ 1 - 1
vortexor/src/vortexor.rs

@@ -96,7 +96,7 @@ impl Vortexor {
         tpu_receiver: Receiver<solana_perf::packet::PacketBatch>,
         tpu_receiver: Receiver<solana_perf::packet::PacketBatch>,
         non_vote_sender: TracedSender,
         non_vote_sender: TracedSender,
     ) -> SigVerifyStage {
     ) -> SigVerifyStage {
-        let verifier = TransactionSigVerifier::new(non_vote_sender);
+        let verifier = TransactionSigVerifier::new(non_vote_sender, None);
         SigVerifyStage::new(
         SigVerifyStage::new(
             tpu_receiver,
             tpu_receiver,
             verifier,
             verifier,