vote: update benches and tests to TowerSync (#725)

This commit is contained in:
Ashwin Sekar 2024-04-11 22:15:02 -07:00 committed by GitHub
parent 4f7e45bb24
commit 499d36e354
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 327 additions and 114 deletions

View File

@ -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],

View File

@ -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<UnixTimestamp>,
) -> 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,
]);

View File

@ -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,

View File

@ -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,

View File

@ -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<Vec<VerifiedVoteMetadata>>,
r: &Receiver<Vec<VerifiedVoteMetadata>>,
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::<VecDeque<Lockout>>();
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,

View File

@ -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,

View File

@ -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,
);
}

View File

@ -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),
);
}

View File

@ -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::<u64>,
"hash": Hash::default().to_string(),
"timestamp": None::<u64>,
"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::<u64>,
"hash": Hash::default().to_string(),
"timestamp": None::<u64>,
"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());
}
}

View File

@ -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,