diff --git a/core/src/banking_stage.rs b/core/src/banking_stage.rs index 394e1d5a7..d839954d3 100644 --- a/core/src/banking_stage.rs +++ b/core/src/banking_stage.rs @@ -814,7 +814,7 @@ mod tests { }, solana_streamer::socket::SocketAddrSpace, solana_vote_program::{ - vote_state::VoteStateUpdate, vote_transaction::new_vote_state_update_transaction, + vote_state::TowerSync, vote_transaction::new_tower_sync_transaction, }, std::{ sync::atomic::{AtomicBool, Ordering}, @@ -1382,8 +1382,8 @@ mod tests { // Send a bunch of votes and transfers let tpu_votes = (0..100_usize) .map(|i| { - new_vote_state_update_transaction( - VoteStateUpdate::from(vec![ + new_tower_sync_transaction( + TowerSync::from(vec![ (0, 8), (1, 7), (i as u64 + 10, 6), @@ -1399,12 +1399,12 @@ mod tests { .collect_vec(); let gossip_votes = (0..100_usize) .map(|i| { - new_vote_state_update_transaction( - VoteStateUpdate::from(vec![ - (0, 8), - (1, 7), - (i as u64 + 64 + 5, 6), - (i as u64 + 7, 1), + new_tower_sync_transaction( + TowerSync::from(vec![ + (0, 9), + (1, 8), + (i as u64 + 5, 6), + (i as u64 + 63, 1), ]), Hash::new_unique(), &keypairs[i], diff --git a/core/src/banking_stage/latest_unprocessed_votes.rs b/core/src/banking_stage/latest_unprocessed_votes.rs index 2d2d1a476..6498f4c81 100644 --- a/core/src/banking_stage/latest_unprocessed_votes.rs +++ b/core/src/banking_stage/latest_unprocessed_votes.rs @@ -358,8 +358,8 @@ mod tests { }, solana_sdk::{hash::Hash, signature::Signer, system_transaction::transfer}, solana_vote_program::{ - vote_state::VoteStateUpdate, - vote_transaction::{new_vote_state_update_transaction, new_vote_transaction}, + vote_state::TowerSync, + vote_transaction::{new_tower_sync_transaction, new_vote_transaction}, }, std::{sync::Arc, thread::Builder}, }; @@ -370,9 +370,9 @@ mod tests { keypairs: &ValidatorVoteKeypairs, timestamp: Option, ) -> LatestValidatorVotePacket { - let mut vote = VoteStateUpdate::from(slots); + let mut vote = TowerSync::from(slots); vote.timestamp = timestamp; - let vote_tx = new_vote_state_update_transaction( + let vote_tx = new_tower_sync_transaction( vote, Hash::new_unique(), &keypairs.node_keypair, @@ -435,10 +435,10 @@ mod tests { .meta_mut() .flags .set(PacketFlags::SIMPLE_VOTE_TX, true); - let mut vote_state_update = Packet::from_data( + let mut tower_sync = Packet::from_data( None, - new_vote_state_update_transaction( - VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]), + new_tower_sync_transaction( + TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]), blockhash, &keypairs.node_keypair, &keypairs.vote_keypair, @@ -447,14 +447,14 @@ mod tests { ), ) .unwrap(); - vote_state_update + tower_sync .meta_mut() .flags .set(PacketFlags::SIMPLE_VOTE_TX, true); - let mut vote_state_update_switch = Packet::from_data( + let mut tower_sync_switch = Packet::from_data( None, - new_vote_state_update_transaction( - VoteStateUpdate::from(vec![(0, 3), (1, 2), (3, 1)]), + new_tower_sync_transaction( + TowerSync::from(vec![(0, 3), (1, 2), (3, 1)]), blockhash, &keypairs.node_keypair, &keypairs.vote_keypair, @@ -463,7 +463,7 @@ mod tests { ), ) .unwrap(); - vote_state_update_switch + tower_sync_switch .meta_mut() .flags .set(PacketFlags::SIMPLE_VOTE_TX, true); @@ -480,8 +480,8 @@ mod tests { let packet_batch = PacketBatch::new(vec![ vote, vote_switch, - vote_state_update, - vote_state_update_switch, + tower_sync, + tower_sync_switch, random_transaction, ]); diff --git a/core/src/banking_stage/unprocessed_transaction_storage.rs b/core/src/banking_stage/unprocessed_transaction_storage.rs index fcc68050b..82ba08a39 100644 --- a/core/src/banking_stage/unprocessed_transaction_storage.rs +++ b/core/src/banking_stage/unprocessed_transaction_storage.rs @@ -1000,7 +1000,7 @@ mod tests { transaction::Transaction, }, solana_vote_program::{ - vote_state::VoteStateUpdate, vote_transaction::new_vote_state_update_transaction, + vote_state::TowerSync, vote_transaction::new_tower_sync_transaction, }, std::error::Error, }; @@ -1207,8 +1207,8 @@ mod tests { )?; let mut vote = Packet::from_data( None, - new_vote_state_update_transaction( - VoteStateUpdate::default(), + new_tower_sync_transaction( + TowerSync::default(), Hash::new_unique(), &keypair, &vote_keypair, diff --git a/core/src/cluster_info_vote_listener.rs b/core/src/cluster_info_vote_listener.rs index 257b2c381..422ee6aaa 100644 --- a/core/src/cluster_info_vote_listener.rs +++ b/core/src/cluster_info_vote_listener.rs @@ -915,7 +915,7 @@ mod tests { }, solana_vote::vote_sender_types::ReplayVoteSender, solana_vote_program::{ - vote_state::{Vote, VoteStateUpdate}, + vote_state::{TowerSync, Vote}, vote_transaction, }, std::{ @@ -1837,17 +1837,16 @@ mod tests { let mut new_optimistic_confirmed_slots = vec![]; let validator0_keypairs = &validator_keypairs[0]; - let (vote_pubkey, vote, _, signature) = vote_parser::parse_vote_transaction( - &vote_transaction::new_vote_state_update_transaction( - VoteStateUpdate::from(vec![(1, 3), (2, 2), (6, 1)]), + let (vote_pubkey, vote, _, signature) = + vote_parser::parse_vote_transaction(&vote_transaction::new_tower_sync_transaction( + TowerSync::from(vec![(1, 3), (2, 2), (6, 1)]), Hash::default(), &validator0_keypairs.node_keypair, &validator0_keypairs.vote_keypair, &validator0_keypairs.vote_keypair, None, - ), - ) - .unwrap(); + )) + .unwrap(); ClusterInfoVoteListener::track_new_votes_and_notify_confirmations( vote, @@ -1869,17 +1868,16 @@ mod tests { // Vote on a new slot, only those later than 6 should show up. 4 is skipped. diff.clear(); - let (vote_pubkey, vote, _, signature) = vote_parser::parse_vote_transaction( - &vote_transaction::new_vote_state_update_transaction( - VoteStateUpdate::from(vec![(1, 6), (2, 5), (3, 4), (4, 3), (7, 2), (8, 1)]), + let (vote_pubkey, vote, _, signature) = + vote_parser::parse_vote_transaction(&vote_transaction::new_tower_sync_transaction( + TowerSync::from(vec![(1, 6), (2, 5), (3, 4), (4, 3), (7, 2), (8, 1)]), Hash::default(), &validator0_keypairs.node_keypair, &validator0_keypairs.vote_keypair, &validator0_keypairs.vote_keypair, None, - ), - ) - .unwrap(); + )) + .unwrap(); ClusterInfoVoteListener::track_new_votes_and_notify_confirmations( vote, diff --git a/core/src/verified_vote_packets.rs b/core/src/verified_vote_packets.rs index e4e1ebf9f..1ab56997d 100644 --- a/core/src/verified_vote_packets.rs +++ b/core/src/verified_vote_packets.rs @@ -314,7 +314,7 @@ mod tests { crossbeam_channel::{unbounded, Receiver, Sender}, solana_perf::packet::Packet, solana_sdk::slot_hashes::MAX_ENTRIES, - solana_vote_program::vote_state::{Lockout, Vote, VoteStateUpdate}, + solana_vote_program::vote_state::{Lockout, TowerSync, Vote}, std::collections::VecDeque, }; @@ -616,10 +616,10 @@ mod tests { let (s, r) = unbounded(); let vote_account_key = solana_sdk::pubkey::new_rand(); - // Send three vote state updates that are out of order - let first_vote = VoteStateUpdate::from(vec![(2, 4), (4, 3), (6, 2), (7, 1)]); - let second_vote = VoteStateUpdate::from(vec![(2, 4), (4, 3), (11, 1)]); - let third_vote = VoteStateUpdate::from(vec![(2, 5), (4, 4), (11, 3), (12, 2), (13, 1)]); + // Send three tower syncs that are out of order + let first_vote = TowerSync::from(vec![(2, 4), (4, 3), (6, 2), (7, 1)]); + let second_vote = TowerSync::from(vec![(2, 4), (4, 3), (11, 1)]); + let third_vote = TowerSync::from(vec![(2, 5), (4, 4), (11, 3), (12, 2), (13, 1)]); for vote in [second_vote, first_vote] { s.send(vec![VerifiedVoteMetadata { @@ -664,10 +664,10 @@ mod tests { assert_eq!(13, slot); } - fn send_vote_state_update_and_process( + fn send_tower_sync_and_process( s: &Sender>, r: &Receiver>, - vote: VoteStateUpdate, + vote: TowerSync, vote_account_key: Pubkey, verified_vote_packets: &mut VerifiedVotePackets, ) -> GossipVote { @@ -692,8 +692,8 @@ mod tests { let (s, r) = unbounded(); let vote_account_key = solana_sdk::pubkey::new_rand(); - // Send identical vote state updates with different timestamps - let mut vote = VoteStateUpdate::from(vec![(2, 4), (4, 3), (6, 2), (7, 1)]); + // Send identical tower syncs with different timestamps + let mut vote = TowerSync::from(vec![(2, 4), (4, 3), (6, 2), (7, 1)]); vote.timestamp = Some(5); let mut vote_later_ts = vote.clone(); @@ -710,7 +710,7 @@ mod tests { // Original vote let GossipVote { slot, timestamp, .. - } = send_vote_state_update_and_process( + } = send_tower_sync_and_process( &s, &r, vote.clone(), @@ -723,7 +723,7 @@ mod tests { // Same vote with later timestamp should override let GossipVote { slot, timestamp, .. - } = send_vote_state_update_and_process( + } = send_tower_sync_and_process( &s, &r, vote_later_ts.clone(), @@ -736,7 +736,7 @@ mod tests { // Same vote with earlier timestamp should not override let GossipVote { slot, timestamp, .. - } = send_vote_state_update_and_process( + } = send_tower_sync_and_process( &s, &r, vote_earlier_ts, @@ -749,7 +749,7 @@ mod tests { // Same vote with no timestamp should not override let GossipVote { slot, timestamp, .. - } = send_vote_state_update_and_process( + } = send_tower_sync_and_process( &s, &r, vote_no_ts, @@ -798,10 +798,11 @@ mod tests { Lockout::new_with_confirmation_count(slot, confirmation_count) }) .collect::>(); - let vote = VoteTransaction::from(VoteStateUpdate::new( + let vote = VoteTransaction::from(TowerSync::new( slots, Some(i - 32), Hash::new_unique(), + Hash::new_unique(), )); s.send(vec![VerifiedVoteMetadata { vote_account_key, @@ -858,7 +859,7 @@ mod tests { let vote_account_key = solana_sdk::pubkey::new_rand(); let mut verified_vote_packets = VerifiedVotePackets(HashMap::new()); - let vote = VoteTransaction::from(VoteStateUpdate::from(vec![(42, 1)])); + let vote = VoteTransaction::from(TowerSync::from(vec![(42, 1)])); let hash_42 = vote.hash(); s.send(vec![VerifiedVoteMetadata { vote_account_key, diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index a03d068e0..9e95ef018 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -73,7 +73,7 @@ use { pubkey::Pubkey, signature::{Keypair, Signer}, system_program, system_transaction, - vote::state::VoteStateUpdate, + vote::state::TowerSync, }, solana_streamer::socket::SocketAddrSpace, solana_turbine::broadcast_stage::{ @@ -3915,13 +3915,13 @@ fn run_duplicate_shreds_broadcast_leader(vote_on_duplicate: bool) { .zip(1..) .collect(); vote_slots.reverse(); - let mut vote = VoteStateUpdate::from(vote_slots); + let mut vote = TowerSync::from(vote_slots); let root = AncestorIterator::new_inclusive(latest_vote_slot, &leader_blockstore) .nth(MAX_LOCKOUT_HISTORY); vote.root = root; vote.hash = vote_hash; - let vote_tx = vote_transaction::new_compact_vote_state_update_transaction( + let vote_tx = vote_transaction::new_tower_sync_transaction( vote, leader_vote_tx.message.recent_blockhash, &node_keypair, diff --git a/programs/vote/benches/process_vote.rs b/programs/vote/benches/process_vote.rs index a092056c9..aea812237 100644 --- a/programs/vote/benches/process_vote.rs +++ b/programs/vote/benches/process_vote.rs @@ -17,7 +17,8 @@ use { solana_vote_program::{ vote_instruction::VoteInstruction, vote_state::{ - Vote, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions, MAX_LOCKOUT_HISTORY, + TowerSync, Vote, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions, + MAX_LOCKOUT_HISTORY, }, }, test::Bencher, @@ -172,3 +173,33 @@ fn bench_process_vote_state_update(bencher: &mut Bencher) { instruction_data, ); } + +#[bench] +fn bench_process_tower_sync(bencher: &mut Bencher) { + let (num_initial_votes, slot_hashes, transaction_accounts, instruction_account_metas) = + create_accounts(); + + let num_vote_slots = MAX_LOCKOUT_HISTORY as Slot; + let last_vote_slot = num_initial_votes + .saturating_add(num_vote_slots) + .saturating_sub(1); + let last_vote_hash = slot_hashes + .iter() + .find(|(slot, _hash)| *slot == last_vote_slot) + .unwrap() + .1; + let slots_and_lockouts: Vec<(Slot, u32)> = + ((num_initial_votes.saturating_add(1)..=last_vote_slot).zip((1u32..=31).rev())).collect(); + let mut tower_sync = TowerSync::from(slots_and_lockouts); + tower_sync.root = Some(num_initial_votes); + tower_sync.hash = last_vote_hash; + tower_sync.block_id = Hash::new_unique(); + let instruction_data = bincode::serialize(&VoteInstruction::TowerSync(tower_sync)).unwrap(); + + bench_process_vote_instruction( + bencher, + transaction_accounts, + instruction_account_metas, + instruction_data, + ); +} diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index cbef2ae5a..625eb40fd 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -191,34 +191,6 @@ fn set_vote_account_state( } } -fn check_and_filter_vote_state_update( - vote_state: &VoteState, - vote_state_update: &mut VoteStateUpdate, - slot_hashes: &[(Slot, Hash)], -) -> Result<(), VoteError> { - check_and_filter_proposed_vote_state( - vote_state, - &mut vote_state_update.lockouts, - &mut vote_state_update.root, - vote_state_update.hash, - slot_hashes, - ) -} - -fn check_and_filter_tower_sync( - vote_state: &VoteState, - tower_sync: &mut TowerSync, - slot_hashes: &[(Slot, Hash)], -) -> Result<(), VoteError> { - check_and_filter_proposed_vote_state( - vote_state, - &mut tower_sync.lockouts, - &mut tower_sync.root, - tower_sync.hash, - slot_hashes, - ) -} - /// Checks the proposed vote state with the current and /// slot hashes, making adjustments to the root / filtering /// votes as needed. @@ -685,7 +657,7 @@ pub fn process_new_vote_state( } // For any slots newly added to the new vote state, the vote latency of that slot is not provided by the - // VoteStateUpdate instruction contents, but instead is computed from the actual latency of the VoteStateUpdate + // vote instruction contents, but instead is computed from the actual latency of the vote // instruction. This prevents other validators from manipulating their own vote latencies within their vote states // and forcing the rest of the cluster to accept these possibly fraudulent latency values. If the // timly_vote_credits feature is not enabled then vote latency is set to 0 for new votes. @@ -693,11 +665,11 @@ pub fn process_new_vote_state( // For any slot that is in both the new state and the current state, the vote latency of the new state is taken // from the current state. // - // Thus vote latencies are set here for any newly vote-on slots when a VoteStateUpdate instruction is received. - // They are copied into the new vote state after every VoteStateUpdate for already voted-on slots. + // Thus vote latencies are set here for any newly vote-on slots when a vote instruction is received. + // They are copied into the new vote state after every vote for already voted-on slots. // And when voted-on slots are rooted, the vote latencies stored in the vote state of all the rooted slots is used // to compute credits earned. - // All validators compute the same vote latencies because all process the same VoteStateUpdate instruction at the + // All validators compute the same vote latencies because all process the same vote instruction at the // same slot, and the only time vote latencies are ever computed is at the time that their slot is first voted on; // after that, the latencies are retained unaltered until the slot is rooted. @@ -1181,7 +1153,13 @@ pub fn do_process_vote_state_update( mut vote_state_update: VoteStateUpdate, feature_set: Option<&FeatureSet>, ) -> Result<(), VoteError> { - check_and_filter_vote_state_update(vote_state, &mut vote_state_update, slot_hashes)?; + check_and_filter_proposed_vote_state( + vote_state, + &mut vote_state_update.lockouts, + &mut vote_state_update.root, + vote_state_update.hash, + slot_hashes, + )?; process_new_vote_state( vote_state, vote_state_update @@ -1225,7 +1203,13 @@ fn do_process_tower_sync( mut tower_sync: TowerSync, feature_set: Option<&FeatureSet>, ) -> Result<(), VoteError> { - check_and_filter_tower_sync(vote_state, &mut tower_sync, slot_hashes)?; + check_and_filter_proposed_vote_state( + vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + slot_hashes, + )?; process_new_vote_state( vote_state, tower_sync @@ -3236,14 +3220,26 @@ mod tests { // Test with empty TowerSync, should return EmptySlots error let mut tower_sync = TowerSync::from(vec![]); assert_eq!( - check_and_filter_tower_sync(&empty_vote_state, &mut tower_sync, &empty_slot_hashes,), + check_and_filter_proposed_vote_state( + &empty_vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &empty_slot_hashes + ), Err(VoteError::EmptySlots), ); // Test with non-empty TowerSync, should return SlotsMismatch since nothing exists in SlotHashes let mut tower_sync = TowerSync::from(vec![(0, 1)]); assert_eq!( - check_and_filter_tower_sync(&empty_vote_state, &mut tower_sync, &empty_slot_hashes,), + check_and_filter_proposed_vote_state( + &empty_vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &empty_slot_hashes + ), Err(VoteError::SlotsMismatch), ); } @@ -3258,7 +3254,13 @@ mod tests { // should return error `VoteTooOld` let mut tower_sync = TowerSync::from(vec![(latest_vote, 1)]); assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::VoteTooOld), ); @@ -3269,7 +3271,13 @@ mod tests { let slot_hashes = build_slot_hashes(vec![earliest_slot_in_history]); let mut tower_sync = TowerSync::from(vec![(earliest_slot_in_history - 1, 1)]); assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::VoteTooOld), ); } @@ -3319,7 +3327,14 @@ mod tests { let mut tower_sync = TowerSync::from(proposed_slots_and_lockouts); tower_sync.hash = proposed_hash; tower_sync.root = Some(proposed_root); - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); assert_eq!(tower_sync.root, expected_root); // The proposed root slot should become the biggest slot in the current vote state less than @@ -3484,7 +3499,13 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(2, 2), (1, 3), (vote_slot, 1)]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::SlotsNotOrdered), ); @@ -3492,7 +3513,13 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(2, 2), (2, 2), (vote_slot, 1)]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::SlotsNotOrdered), ); } @@ -3521,7 +3548,14 @@ mod tests { (vote_slot, 3), ]); tower_sync.hash = vote_slot_hash; - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); // Check the earlier slot was filtered out assert_eq!( @@ -3567,7 +3601,14 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(existing_older_than_history_slot, 3), (vote_slot, 2)]); tower_sync.hash = vote_slot_hash; - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); // Check the earlier slot was *NOT* filtered out assert_eq!(tower_sync.lockouts.len(), 2); assert_eq!( @@ -3627,7 +3668,14 @@ mod tests { (vote_slot, 1), ]); tower_sync.hash = vote_slot_hash; - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); assert_eq!(tower_sync.lockouts.len(), 3); assert_eq!( tower_sync @@ -3675,7 +3723,13 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(missing_vote_slot, 2), (vote_slot, 3)]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::SlotsMismatch), ); @@ -3690,7 +3744,13 @@ mod tests { ]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::SlotsMismatch), ); } @@ -3720,7 +3780,13 @@ mod tests { tower_sync.hash = vote_slot_hash; tower_sync.root = Some(new_root); assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::RootOnDifferentFork), ); } @@ -3740,7 +3806,13 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(8, 2), (missing_vote_slot, 3)]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes + ), Err(VoteError::SlotsMismatch), ); } @@ -3763,7 +3835,14 @@ mod tests { .1; let mut tower_sync = TowerSync::from(vec![(2, 4), (4, 3), (6, 2), (vote_slot, 1)]); tower_sync.hash = vote_slot_hash; - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); // Nothing in the update should have been filtered out assert_eq!( @@ -3809,7 +3888,14 @@ mod tests { .1; let mut tower_sync = TowerSync::from(vec![(4, 2), (vote_slot, 1)]); tower_sync.hash = vote_slot_hash; - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes).unwrap(); + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ) + .unwrap(); // Nothing in the update should have been filtered out assert_eq!( @@ -3854,7 +3940,13 @@ mod tests { let mut tower_sync = TowerSync::from(vec![(2, 4), (4, 3), (6, 2), (vote_slot, 1)]); tower_sync.hash = vote_slot_hash; assert_eq!( - check_and_filter_tower_sync(&vote_state, &mut tower_sync, &slot_hashes,), + check_and_filter_proposed_vote_state( + &vote_state, + &mut tower_sync.lockouts, + &mut tower_sync.root, + tower_sync.hash, + &slot_hashes, + ), Err(VoteError::SlotHashMismatch), ); } diff --git a/transaction-status/src/parse_vote.rs b/transaction-status/src/parse_vote.rs index 8416d0f27..7276a43f7 100644 --- a/transaction-status/src/parse_vote.rs +++ b/transaction-status/src/parse_vote.rs @@ -178,7 +178,7 @@ pub fn parse_vote( "root": tower_sync.root, "hash": tower_sync.hash.to_string(), "timestamp": tower_sync.timestamp, - "blockId": tower_sync.block_id, + "blockId": tower_sync.block_id.to_string(), }); Ok(ParsedInstructionEnum { instruction_type: "towersync".to_string(), @@ -196,7 +196,7 @@ pub fn parse_vote( "root": tower_sync.root, "hash": tower_sync.hash.to_string(), "timestamp": tower_sync.timestamp, - "blockId": tower_sync.block_id, + "blockId": tower_sync.block_id.to_string(), }); Ok(ParsedInstructionEnum { instruction_type: "towersyncswitch".to_string(), @@ -292,7 +292,9 @@ mod test { sysvar, vote::{ instruction as vote_instruction, - state::{Vote, VoteAuthorize, VoteInit, VoteStateUpdate, VoteStateVersions}, + state::{ + TowerSync, Vote, VoteAuthorize, VoteInit, VoteStateUpdate, VoteStateVersions, + }, }, }, }; @@ -896,4 +898,93 @@ mod test { message.instructions[0].accounts.pop(); assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err()); } + + #[test] + fn test_parse_tower_sync_ix() { + let tower_sync = TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]); + + let vote_pubkey = Pubkey::new_unique(); + let authorized_voter_pubkey = Pubkey::new_unique(); + let instruction = vote_instruction::tower_sync( + &vote_pubkey, + &authorized_voter_pubkey, + tower_sync.clone(), + ); + let mut message = Message::new(&[instruction], None); + assert_eq!( + parse_vote( + &message.instructions[0], + &AccountKeys::new(&message.account_keys, None) + ) + .unwrap(), + ParsedInstructionEnum { + instruction_type: "towersync".to_string(), + info: json!({ + "voteAccount": vote_pubkey.to_string(), + "voteAuthority": authorized_voter_pubkey.to_string(), + "towerSync": { + "lockouts": tower_sync.lockouts, + "root": None::, + "hash": Hash::default().to_string(), + "timestamp": None::, + "blockId": Hash::default().to_string(), + }, + }), + } + ); + assert!(parse_vote( + &message.instructions[0], + &AccountKeys::new(&message.account_keys[0..1], None) + ) + .is_err()); + let keys = message.account_keys.clone(); + message.instructions[0].accounts.pop(); + assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err()); + } + + #[test] + fn test_parse_tower_sync_switch_ix() { + let tower_sync = TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]); + + let vote_pubkey = Pubkey::new_unique(); + let authorized_voter_pubkey = Pubkey::new_unique(); + let proof_hash = Hash::new_from_array([2; 32]); + let instruction = vote_instruction::tower_sync_switch( + &vote_pubkey, + &authorized_voter_pubkey, + tower_sync.clone(), + proof_hash, + ); + let mut message = Message::new(&[instruction], None); + assert_eq!( + parse_vote( + &message.instructions[0], + &AccountKeys::new(&message.account_keys, None) + ) + .unwrap(), + ParsedInstructionEnum { + instruction_type: "towersyncswitch".to_string(), + info: json!({ + "voteAccount": vote_pubkey.to_string(), + "voteAuthority": authorized_voter_pubkey.to_string(), + "towerSync": { + "lockouts": tower_sync.lockouts, + "root": None::, + "hash": Hash::default().to_string(), + "timestamp": None::, + "blockId": Hash::default().to_string(), + }, + "hash": proof_hash.to_string(), + }), + } + ); + assert!(parse_vote( + &message.instructions[0], + &AccountKeys::new(&message.account_keys[0..1], None) + ) + .is_err()); + let keys = message.account_keys.clone(); + message.instructions[0].accounts.pop(); + assert!(parse_vote(&message.instructions[0], &AccountKeys::new(&keys, None)).is_err()); + } } diff --git a/wen-restart/src/wen_restart.rs b/wen-restart/src/wen_restart.rs index bd283eb7d..7ae4d27f9 100644 --- a/wen-restart/src/wen_restart.rs +++ b/wen-restart/src/wen_restart.rs @@ -705,7 +705,7 @@ mod tests { }, solana_program::{ hash::Hash, - vote::state::{Vote, VoteStateUpdate}, + vote::state::{TowerSync, Vote}, }, solana_runtime::genesis_utils::{ create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, @@ -1077,7 +1077,7 @@ mod tests { prost::DecodeError::new("invalid wire type value: 7") ); remove_file(&test_state.wen_restart_proto_path).unwrap(); - let invalid_last_vote = VoteTransaction::from(VoteStateUpdate::from(vec![(0, 8), (1, 1)])); + let invalid_last_vote = VoteTransaction::from(TowerSync::from(vec![(0, 8), (1, 1)])); assert_eq!( initialize( &test_state.wen_restart_proto_path,