solana-core
Advanced tools
| { | ||
| "git": { | ||
| "sha1": "2717084afeeb7baad4342468c27f528ef617a3cf" | ||
| "sha1": "765ee54adc4f574b1cd4f03a5500bf46c0af0817" | ||
| }, | ||
| "path_in_vcs": "core" | ||
| } |
+66
-66
@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "solana-core" | ||
| version = "3.1.8" | ||
| version = "3.1.9" | ||
| authors = ["Anza Maintainers <maintainers@anza.xyz>"] | ||
@@ -123,31 +123,31 @@ build = false | ||
| [dependencies.agave-banking-stage-ingress-types] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-feature-set] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-scheduler-bindings] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-scheduling-utils] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-snapshots] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-transaction-view] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-verified-packet-receiver] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.agave-votor] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -282,3 +282,3 @@ "agave-unstable-api", | ||
| [dependencies.solana-accounts-db] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -293,11 +293,11 @@ | ||
| [dependencies.solana-bloom] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-builtins-default-costs] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-client] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
@@ -311,7 +311,7 @@ [dependencies.solana-clock] | ||
| [dependencies.solana-compute-budget] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-compute-budget-instruction] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -323,3 +323,3 @@ | ||
| [dependencies.solana-connection-cache] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -329,7 +329,7 @@ default-features = false | ||
| [dependencies.solana-cost-model] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-entry] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -341,3 +341,3 @@ | ||
| [dependencies.solana-fee] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -365,11 +365,11 @@ | ||
| [dependencies.solana-genesis-utils] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-geyser-plugin-manager] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-gossip] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -393,3 +393,3 @@ "agave-unstable-api", | ||
| [dependencies.solana-ledger] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -404,3 +404,3 @@ "agave-unstable-api", | ||
| [dependencies.solana-measure] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -412,3 +412,3 @@ | ||
| [dependencies.solana-metrics] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -420,3 +420,3 @@ | ||
| [dependencies.solana-net-utils] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -437,7 +437,7 @@ "agave-unstable-api", | ||
| [dependencies.solana-perf] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-poh] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -453,3 +453,3 @@ | ||
| [dependencies.solana-quic-client] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -461,3 +461,3 @@ | ||
| [dependencies.solana-rayon-threadlimit] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -469,14 +469,14 @@ | ||
| [dependencies.solana-rpc] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-rpc-client-api] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| [dependencies.solana-runtime] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-runtime-transaction] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -491,3 +491,3 @@ | ||
| [dependencies.solana-send-transaction-service] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -518,15 +518,15 @@ | ||
| [dependencies.solana-streamer] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-svm] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-svm-timings] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-svm-transaction] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -547,7 +547,7 @@ | ||
| [dependencies.solana-tls-utils] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-tpu-client] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -557,3 +557,3 @@ default-features = false | ||
| [dependencies.solana-tpu-client-next] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -568,7 +568,7 @@ | ||
| [dependencies.solana-transaction-status] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-turbine] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -580,7 +580,7 @@ "agave-unstable-api", | ||
| [dependencies.solana-unified-scheduler-logic] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-unified-scheduler-pool] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -592,11 +592,11 @@ | ||
| [dependencies.solana-version] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-vote] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dependencies.solana-vote-program] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -606,3 +606,3 @@ default-features = false | ||
| [dependencies.solana-wen-restart] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
@@ -640,11 +640,11 @@ | ||
| [dev-dependencies.agave-logger] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.agave-reserved-account-keys] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.agave-scheduler-bindings] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -675,7 +675,7 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-bpf-loader-program] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.solana-client] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["dev-context-only-utils"] | ||
@@ -687,7 +687,7 @@ | ||
| [dev-dependencies.solana-compute-budget-program] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.solana-cost-model] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -702,3 +702,3 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-ledger] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -710,3 +710,3 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-net-utils] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -718,3 +718,3 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-poh] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -726,7 +726,7 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-program-binaries] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.solana-program-runtime] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -738,3 +738,3 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-rpc] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -746,7 +746,7 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-system-program] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = ["agave-unstable-api"] | ||
| [dev-dependencies.solana-unified-scheduler-pool] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -758,3 +758,3 @@ "agave-unstable-api", | ||
| [dev-dependencies.solana-vote] | ||
| version = "=3.1.8" | ||
| version = "=3.1.9" | ||
| features = [ | ||
@@ -761,0 +761,0 @@ "agave-unstable-api", |
@@ -12,5 +12,8 @@ use { | ||
| solana_pubkey::Pubkey, | ||
| solana_runtime::{bank::Bank, epoch_stakes::VersionedEpochStakes}, | ||
| solana_runtime::{ | ||
| bank::Bank, | ||
| epoch_stakes::{EpochAuthorizedVoters, VersionedEpochStakes}, | ||
| }, | ||
| solana_sysvar::{self as sysvar, slot_hashes::SlotHashes}, | ||
| std::cmp, | ||
| std::{cmp, sync::Arc}, | ||
| }; | ||
@@ -46,2 +49,7 @@ | ||
| cached_epoch_stakes: VersionedEpochStakes, | ||
| /// Authorized voters for the current epoch. This is separate from | ||
| /// cached_epoch_stakes because stakes are offset by one epoch (we use | ||
| /// epoch E + 1 for stake in epoch E), but authorized voters must | ||
| /// match the epoch of the bank slot | ||
| cached_epoch_authorized_voters: Arc<EpochAuthorizedVoters>, | ||
| deprecate_legacy_vote_ixs: bool, | ||
@@ -53,6 +61,13 @@ current_epoch: Epoch, | ||
| pub fn new(bank: &Bank) -> Self { | ||
| let cached_epoch_stakes = bank.current_epoch_stakes().clone(); | ||
| let cached_epoch_authorized_voters = bank | ||
| .epoch_stakes(bank.epoch()) | ||
| .expect("Current epoch stakes must exist") | ||
| .epoch_authorized_voters() | ||
| .clone(); | ||
| Self { | ||
| latest_vote_per_vote_pubkey: HashMap::default(), | ||
| num_unprocessed_votes: 0, | ||
| cached_epoch_stakes: bank.current_epoch_stakes().clone(), | ||
| cached_epoch_stakes, | ||
| cached_epoch_authorized_voters, | ||
| current_epoch: bank.epoch(), | ||
@@ -74,2 +89,4 @@ deprecate_legacy_vote_ixs: bank | ||
| let epoch_stakes = VersionedEpochStakes::new_for_tests(vote_accounts, 0); | ||
| // Authorized voters don't change in tests so it's fine to use the authorized voters from the "wrong" epoch | ||
| let epoch_authorized_voters = epoch_stakes.epoch_authorized_voters().clone(); | ||
@@ -80,2 +97,3 @@ Self { | ||
| cached_epoch_stakes: epoch_stakes, | ||
| cached_epoch_authorized_voters: epoch_authorized_voters, | ||
| current_epoch: 0, | ||
@@ -179,3 +197,12 @@ deprecate_legacy_vote_ixs: true, | ||
| { | ||
| self.cached_epoch_stakes = bank.current_epoch_stakes().clone(); | ||
| // Stakes are offset by one epoch | ||
| let current_epoch_stakes = bank.current_epoch_stakes().clone(); | ||
| // Authorized voters use the same epoch as the leader bank | ||
| self.cached_epoch_authorized_voters = bank | ||
| .epoch_stakes(bank.epoch()) | ||
| .map(|stakes| stakes.epoch_authorized_voters().clone()) | ||
| // Should be fine to expect as the current epoch must exist in epoch_stakes, | ||
| // will cleanup in a follow up | ||
| .unwrap_or_else(|| current_epoch_stakes.epoch_authorized_voters().clone()); | ||
| self.cached_epoch_stakes = current_epoch_stakes; | ||
| self.current_epoch = bank.epoch(); | ||
@@ -224,4 +251,3 @@ self.deprecate_legacy_vote_ixs = bank | ||
| if self | ||
| .cached_epoch_stakes | ||
| .epoch_authorized_voters() | ||
| .cached_epoch_authorized_voters | ||
| .get(&vote.vote_pubkey()) | ||
@@ -360,2 +386,3 @@ .is_none_or(|authorized| authorized != &vote.authorized_voter_pubkey()) | ||
| solana_hash::Hash, | ||
| solana_keypair::Keypair, | ||
| solana_perf::packet::{BytesPacket, PacketFlags}, | ||
@@ -369,2 +396,37 @@ solana_runtime::genesis_utils::{self, ValidatorVoteKeypairs}, | ||
| /// Create a VoteAccount with a specific authorized voter for the given epoch | ||
| fn vote_account_with_authorized_voter( | ||
| vote_pubkey: &Pubkey, | ||
| authorized_voter: &Pubkey, | ||
| epoch: solana_clock::Epoch, | ||
| ) -> solana_vote::vote_account::VoteAccount { | ||
| use { | ||
| solana_account::AccountSharedData, | ||
| solana_vote_program::vote_state::{VoteInit, VoteStateV4, VoteStateVersions}, | ||
| }; | ||
| let vote_init = VoteInit { | ||
| node_pubkey: Pubkey::new_unique(), | ||
| authorized_voter: *authorized_voter, | ||
| authorized_withdrawer: Pubkey::new_unique(), | ||
| commission: 0, | ||
| }; | ||
| let clock = solana_clock::Clock { | ||
| slot: 0, | ||
| epoch_start_timestamp: 0, | ||
| epoch, | ||
| leader_schedule_epoch: epoch, | ||
| unix_timestamp: 0, | ||
| }; | ||
| let vote_state = VoteStateV4::new(vote_pubkey, &vote_init, &clock); | ||
| let account = AccountSharedData::new_data( | ||
| 1_000_000, | ||
| &VoteStateVersions::new_v4(vote_state), | ||
| &solana_sdk_ids::vote::id(), | ||
| ) | ||
| .unwrap(); | ||
| solana_vote::vote_account::VoteAccount::try_from(account).unwrap() | ||
| } | ||
| pub(crate) fn packet_from_slots( | ||
@@ -404,2 +466,28 @@ slots: Vec<(u64, u32)>, | ||
| /// Create a vote packet with a custom authorized voter keypair | ||
| fn packet_from_slots_with_authorized_voter( | ||
| slots: Vec<(u64, u32)>, | ||
| keypairs: &ValidatorVoteKeypairs, | ||
| authorized_voter: &Keypair, | ||
| timestamp: Option<UnixTimestamp>, | ||
| ) -> BytesPacket { | ||
| let mut vote = TowerSync::from(slots); | ||
| vote.timestamp = timestamp; | ||
| let vote_tx = new_tower_sync_transaction( | ||
| vote, | ||
| Hash::new_unique(), | ||
| &keypairs.node_keypair, | ||
| &keypairs.vote_keypair, | ||
| authorized_voter, | ||
| None, | ||
| ); | ||
| let mut packet = BytesPacket::from_data(None, vote_tx).unwrap(); | ||
| packet | ||
| .meta_mut() | ||
| .flags | ||
| .set(PacketFlags::SIMPLE_VOTE_TX, true); | ||
| packet | ||
| } | ||
| fn to_sanitized_view(packet: BytesPacket) -> SanitizedTransactionView<SharedBytes> { | ||
@@ -674,2 +762,157 @@ SanitizedTransactionView::try_new_sanitized(Arc::new(packet.buffer().to_vec()), false) | ||
| #[test] | ||
| fn test_insert_batch_authorized_voter() { | ||
| // Test that votes are only accepted when signed by the correct authorized voter. | ||
| let keypair = ValidatorVoteKeypairs::new_rand(); | ||
| let unauthorized_keypair = solana_keypair::Keypair::new(); | ||
| let genesis_config = | ||
| genesis_utils::create_genesis_config_with_vote_accounts(100, &[&keypair], vec![200]) | ||
| .genesis_config; | ||
| let (bank, _bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config); | ||
| let mut vote_storage = VoteStorage::new(&bank); | ||
| // Vote signed by the correct authorized voter (vote_keypair) should be accepted | ||
| let correct_vote = packet_from_slots_with_authorized_voter( | ||
| vec![(0, 1)], | ||
| &keypair, | ||
| &keypair.vote_keypair, | ||
| None, | ||
| ); | ||
| vote_storage.insert_batch( | ||
| VoteSource::Tpu, | ||
| std::iter::once(to_sanitized_view(correct_vote)), | ||
| ); | ||
| assert_eq!(1, vote_storage.len()); | ||
| assert_eq!( | ||
| Some(0), | ||
| vote_storage.get_latest_vote_slot(keypair.vote_keypair.pubkey()) | ||
| ); | ||
| // Vote signed by an unauthorized keypair should be filtered out | ||
| let unauthorized_vote = packet_from_slots_with_authorized_voter( | ||
| vec![(1, 1)], | ||
| &keypair, | ||
| &unauthorized_keypair, | ||
| None, | ||
| ); | ||
| vote_storage.insert_batch( | ||
| VoteSource::Tpu, | ||
| std::iter::once(to_sanitized_view(unauthorized_vote)), | ||
| ); | ||
| // Should still be 1 (unauthorized vote was filtered) | ||
| assert_eq!(1, vote_storage.len()); | ||
| // Slot should still be 0 (the authorized vote), not 1 (the unauthorized one) | ||
| assert_eq!( | ||
| Some(0), | ||
| vote_storage.get_latest_vote_slot(keypair.vote_keypair.pubkey()) | ||
| ); | ||
| // Update with a valid vote for a later slot - should succeed | ||
| let correct_vote_2 = packet_from_slots_with_authorized_voter( | ||
| vec![(2, 1)], | ||
| &keypair, | ||
| &keypair.vote_keypair, | ||
| None, | ||
| ); | ||
| vote_storage.insert_batch( | ||
| VoteSource::Tpu, | ||
| std::iter::once(to_sanitized_view(correct_vote_2)), | ||
| ); | ||
| assert_eq!(1, vote_storage.len()); | ||
| assert_eq!( | ||
| Some(2), | ||
| vote_storage.get_latest_vote_slot(keypair.vote_keypair.pubkey()) | ||
| ); | ||
| } | ||
| /// Test that authorized voters are checked against the current epoch, not the next epoch. | ||
| /// This verifies that cache_epoch_boundary_info uses epoch_stakes(bank.epoch()) for | ||
| /// authorized voters, not current_epoch_stakes() which returns epoch E+1. | ||
| #[test] | ||
| fn test_authorized_voter_uses_current_epoch_not_next() { | ||
| let keypair = ValidatorVoteKeypairs::new_rand(); | ||
| let vote_pubkey = keypair.vote_keypair.pubkey(); | ||
| // Create two different authorized voters: one for epoch 1, one for epoch 2 | ||
| let epoch1_authorized_voter_keypair = keypair.node_keypair.insecure_clone(); | ||
| let epoch1_authorized_voter = epoch1_authorized_voter_keypair.pubkey(); | ||
| let epoch2_authorized_voter_keypair = Keypair::new(); | ||
| let epoch2_authorized_voter = epoch2_authorized_voter_keypair.pubkey(); | ||
| // Create vote accounts with different authorized voters for different epochs | ||
| let vote_account_epoch1 = | ||
| vote_account_with_authorized_voter(&vote_pubkey, &epoch1_authorized_voter, 1); | ||
| let vote_account_epoch2 = | ||
| vote_account_with_authorized_voter(&vote_pubkey, &epoch2_authorized_voter, 2); | ||
| // Create epoch stakes for epochs 1 and 2 | ||
| let epoch1_stakes = VersionedEpochStakes::new_for_tests( | ||
| [(vote_pubkey, (100, vote_account_epoch1))] | ||
| .into_iter() | ||
| .collect(), | ||
| 1, // leader_schedule_epoch | ||
| ); | ||
| let epoch2_stakes = VersionedEpochStakes::new_for_tests( | ||
| [(vote_pubkey, (100, vote_account_epoch2))] | ||
| .into_iter() | ||
| .collect(), | ||
| 2, // leader_schedule_epoch | ||
| ); | ||
| // Create a bank in epoch 1 with custom epoch stakes | ||
| let genesis_config = | ||
| genesis_utils::create_genesis_config_with_vote_accounts(100, &[&keypair], vec![200]) | ||
| .genesis_config; | ||
| let bank_0 = Bank::new_for_tests(&genesis_config); | ||
| let mut bank = Bank::new_from_parent( | ||
| Arc::new(bank_0), | ||
| &Pubkey::new_unique(), | ||
| MINIMUM_SLOTS_PER_EPOCH, // This puts us in epoch 1 | ||
| ); | ||
| assert_eq!(bank.epoch(), 1); | ||
| // Set custom epoch stakes: epoch 1 has epoch1_authorized_voter, epoch 2 has epoch2_authorized_voter | ||
| bank.set_epoch_stakes_for_test(1, epoch1_stakes); | ||
| bank.set_epoch_stakes_for_test(2, epoch2_stakes); | ||
| let mut vote_storage = VoteStorage::new(&bank); | ||
| // Vote signed by epoch 1's authorized voter (vote_keypair) should be accepted | ||
| let epoch1_vote = packet_from_slots_with_authorized_voter( | ||
| vec![(MINIMUM_SLOTS_PER_EPOCH, 1)], | ||
| &keypair, | ||
| &epoch1_authorized_voter_keypair, | ||
| None, | ||
| ); | ||
| vote_storage.insert_batch( | ||
| VoteSource::Tpu, | ||
| std::iter::once(to_sanitized_view(epoch1_vote)), | ||
| ); | ||
| assert_eq!( | ||
| 1, | ||
| vote_storage.len(), | ||
| "Vote with epoch 1 authorized voter should be accepted" | ||
| ); | ||
| // Vote signed by epoch 2's authorized voter should be REJECTED | ||
| // If we were incorrectly using current_epoch_stakes() (epoch 2), this would be accepted | ||
| let wrong_epoch_vote = packet_from_slots_with_authorized_voter( | ||
| vec![(MINIMUM_SLOTS_PER_EPOCH + 1, 1)], | ||
| &keypair, | ||
| &epoch2_authorized_voter_keypair, // This won't match epoch 1's authorized voter | ||
| None, | ||
| ); | ||
| vote_storage.insert_batch( | ||
| VoteSource::Tpu, | ||
| std::iter::once(to_sanitized_view(wrong_epoch_vote)), | ||
| ); | ||
| // Should still be 1 - the vote with wrong authorized voter was rejected | ||
| assert_eq!( | ||
| 1, | ||
| vote_storage.len(), | ||
| "Vote with wrong authorized voter should be rejected" | ||
| ); | ||
| } | ||
| #[test] | ||
| fn test_insert_batch_unstaked() { | ||
@@ -676,0 +919,0 @@ let keypair_a = ValidatorVoteKeypairs::new_rand(); |
+17
-6
@@ -5,3 +5,3 @@ //! The `fetch_stage` batches input from a UDP socket and sends it to a channel. | ||
| crate::result::{Error, Result}, | ||
| crossbeam_channel::{unbounded, RecvTimeoutError}, | ||
| crossbeam_channel::{unbounded, RecvTimeoutError, TrySendError}, | ||
| solana_clock::{DEFAULT_TICKS_PER_SLOT, HOLD_TRANSACTIONS_SLOT_OFFSET}, | ||
@@ -128,9 +128,20 @@ solana_metrics::{inc_new_counter_debug, inc_new_counter_info}, | ||
| { | ||
| inc_new_counter_debug!("fetch_stage-honor_forwards", num_packets); | ||
| let mut packets_sent = 0usize; | ||
| let mut packets_dropped = 0usize; | ||
| for packet_batch in packet_batches { | ||
| #[allow(clippy::question_mark)] | ||
| if sendr.send(packet_batch).is_err() { | ||
| return Err(Error::Send); | ||
| } | ||
| let packets_in_batch = packet_batch.len(); | ||
| match sendr.try_send(packet_batch) { | ||
| Ok(()) => { | ||
| packets_sent += packets_in_batch; | ||
| } | ||
| Err(TrySendError::Full(_)) => { | ||
| packets_dropped += packets_in_batch; | ||
| } | ||
| Err(TrySendError::Disconnected(_)) => return Err(Error::Send), | ||
| }; | ||
| } | ||
| inc_new_counter_debug!("fetch_stage-honor_forwards", packets_sent); | ||
| if packets_dropped > 0 { | ||
| inc_new_counter_error!("fetch_stage-dropped_forwards", packets_dropped); | ||
| } | ||
| } else { | ||
@@ -137,0 +148,0 @@ inc_new_counter_info!("fetch_stage-discard_forwards", num_packets); |
@@ -296,3 +296,5 @@ //! The `sigverify_stage` implements the signature verification stage of the TPU. It | ||
| ) -> Result<(), T::SendType> { | ||
| let (mut batches, num_packets, recv_duration) = streamer::recv_packet_batches(recvr)?; | ||
| const SOFT_RECEIVE_CAP: usize = 5_000; | ||
| let (mut batches, num_packets, recv_duration) = | ||
| streamer::recv_packet_batches(recvr, SOFT_RECEIVE_CAP)?; | ||
@@ -299,0 +301,0 @@ let batches_len = batches.len(); |
+5
-1
@@ -105,2 +105,6 @@ //! The `tpu` module implements the Transaction Processing Unit, a | ||
| /// Size of the channel between streamer and TPU sigverify stage. The values have been selected to | ||
| /// be conservative max of obsersed on mnb during high-load events. | ||
| const TPU_CHANNEL_SIZE: usize = 50_000; | ||
| pub struct Tpu { | ||
@@ -180,3 +184,3 @@ fetch_stage: FetchStage, | ||
| let (packet_sender, packet_receiver) = unbounded(); | ||
| let (packet_sender, packet_receiver) = bounded(TPU_CHANNEL_SIZE); | ||
| let (vote_packet_sender, vote_packet_receiver) = unbounded(); | ||
@@ -183,0 +187,0 @@ let (forwarded_packet_sender, forwarded_packet_receiver) = unbounded(); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display