Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions core/benches/banking_stage.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#![allow(clippy::arithmetic_side_effects)]
#![feature(test)]

use solana_core::validator::BlockProductionMethod;
use {
solana_core::validator::BlockProductionMethod,
solana_vote_program::{vote_state::TowerSync, vote_transaction::new_tower_sync_transaction},
};

extern crate test;

Expand Down Expand Up @@ -50,9 +53,6 @@ use {
transaction::{Transaction, VersionedTransaction},
},
solana_streamer::socket::SocketAddrSpace,
solana_vote_program::{
vote_state::VoteStateUpdate, vote_transaction::new_vote_state_update_transaction,
},
std::{
iter::repeat_with,
sync::{atomic::Ordering, Arc},
Expand Down Expand Up @@ -169,11 +169,11 @@ fn make_vote_txs(txes: usize) -> Vec<Transaction> {
.map(|i| {
// Quarter of the votes should be filtered out
let vote = if i % 4 == 0 {
VoteStateUpdate::from(vec![(2, 1)])
TowerSync::from(vec![(2, 1)])
} else {
VoteStateUpdate::from(vec![(i as u64, 1)])
TowerSync::from(vec![(i as u64, 1)])
};
new_vote_state_update_transaction(
new_tower_sync_transaction(
vote,
Hash::new_unique(),
&keypairs[i % num_voters],
Expand Down
78 changes: 50 additions & 28 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::replay_stage::DUPLICATE_THRESHOLD;
use {crate::replay_stage::DUPLICATE_THRESHOLD, solana_sdk::feature_set};

pub mod fork_choice;
pub mod heaviest_subtree_fork_choice;
Expand Down Expand Up @@ -35,8 +35,8 @@ use {
vote_instruction,
vote_state::{
process_slot_vote_unchecked, process_vote_unchecked, BlockTimestamp, LandedVote,
Lockout, Vote, VoteState, VoteState1_14_11, VoteStateUpdate, VoteStateVersions,
VoteTransaction, MAX_LOCKOUT_HISTORY,
Lockout, TowerSync, Vote, VoteState, VoteState1_14_11, VoteStateUpdate,
VoteStateVersions, VoteTransaction, MAX_LOCKOUT_HISTORY,
},
},
std::{
Expand Down Expand Up @@ -267,7 +267,7 @@ impl Default for Tower {
threshold_depth: VOTE_THRESHOLD_DEPTH,
threshold_size: VOTE_THRESHOLD_SIZE,
vote_state: VoteState::default(),
last_vote: VoteTransaction::from(VoteStateUpdate::default()),
last_vote: VoteTransaction::from(TowerSync::default()),
last_timestamp: BlockTimestamp::default(),
last_vote_tx_blockhash: BlockhashStatus::default(),
stray_restored_slot: Option::default(),
Expand Down Expand Up @@ -310,7 +310,7 @@ impl Tower {
let mut rng = rand::thread_rng();
let root_slot = rng.gen();
let vote_state = VoteState::new_rand_for_tests(node_pubkey, root_slot);
let last_vote = VoteStateUpdate::from(
let last_vote = TowerSync::from(
vote_state
.votes
.iter()
Expand All @@ -320,7 +320,7 @@ impl Tower {
Self {
node_pubkey,
vote_state,
last_vote: VoteTransaction::CompactVoteStateUpdate(last_vote),
last_vote: VoteTransaction::from(last_vote),
..Tower::default()
}
}
Expand Down Expand Up @@ -590,21 +590,43 @@ impl Tower {
pub fn record_bank_vote(&mut self, bank: &Bank) -> Option<Slot> {
// Returns the new root if one is made after applying a vote for the given bank to
// `self.vote_state`
self.record_bank_vote_and_update_lockouts(bank.slot(), bank.hash())
self.record_bank_vote_and_update_lockouts(
bank.slot(),
bank.hash(),
bank.feature_set
.is_active(&feature_set::enable_tower_sync_ix::id()),
)
}

/// If we've recently updated the vote state by applying a new vote
/// or syncing from a bank, generate the proper last_vote.
pub(crate) fn update_last_vote_from_vote_state(&mut self, vote_hash: Hash) {
let mut new_vote = VoteTransaction::from(VoteStateUpdate::new(
self.vote_state
.votes
.iter()
.map(|vote| vote.lockout)
.collect(),
self.vote_state.root_slot,
vote_hash,
));
pub(crate) fn update_last_vote_from_vote_state(
&mut self,
vote_hash: Hash,
enable_tower_sync_ix: bool,
) {
let mut new_vote = if enable_tower_sync_ix {
VoteTransaction::from(TowerSync::new(
self.vote_state
.votes
.iter()
.map(|vote| vote.lockout)
.collect(),
self.vote_state.root_slot,
vote_hash,
Hash::default(), // TODO: block_id will fill in upcoming pr
))
} else {
VoteTransaction::from(VoteStateUpdate::new(
self.vote_state
.votes
.iter()
.map(|vote| vote.lockout)
.collect(),
self.vote_state.root_slot,
vote_hash,
))
};

new_vote.set_timestamp(self.maybe_timestamp(self.last_voted_slot().unwrap_or_default()));
self.last_vote = new_vote;
Expand All @@ -614,6 +636,7 @@ impl Tower {
&mut self,
vote_slot: Slot,
vote_hash: Hash,
enable_tower_sync_ix: bool,
) -> Option<Slot> {
trace!("{} record_vote for {}", self.node_pubkey, vote_slot);
let old_root = self.root();
Expand All @@ -626,7 +649,7 @@ impl Tower {
vote_slot, vote_hash, result
);
}
self.update_last_vote_from_vote_state(vote_hash);
self.update_last_vote_from_vote_state(vote_hash, enable_tower_sync_ix);

let new_root = self.root();

Expand All @@ -644,7 +667,7 @@ impl Tower {

#[cfg(feature = "dev-context-only-utils")]
pub fn record_vote(&mut self, slot: Slot, hash: Hash) -> Option<Slot> {
self.record_bank_vote_and_update_lockouts(slot, hash)
self.record_bank_vote_and_update_lockouts(slot, hash, true)
}

/// Used for tests
Expand Down Expand Up @@ -1271,8 +1294,9 @@ impl Tower {
assert!(
self.last_vote == VoteTransaction::from(VoteStateUpdate::default())
&& self.vote_state.votes.is_empty()
|| self.last_vote != VoteTransaction::from(VoteStateUpdate::default())
&& !self.vote_state.votes.is_empty(),
|| self.last_vote == VoteTransaction::from(TowerSync::default())
&& self.vote_state.votes.is_empty()
|| !self.vote_state.votes.is_empty(),
"last vote: {:?} vote_state.votes: {:?}",
self.last_vote,
self.vote_state.votes
Expand Down Expand Up @@ -2734,10 +2758,11 @@ pub mod test {
} else {
vec![]
};
let mut expected = VoteStateUpdate::new(
let mut expected = TowerSync::new(
VecDeque::from(slots),
if num_votes > 0 { Some(0) } else { None },
Hash::default(),
Hash::default(),
);
for i in 0..num_votes {
tower.record_vote(i as u64, Hash::default());
Expand Down Expand Up @@ -2789,26 +2814,23 @@ pub mod test {
assert_eq!(tower.last_timestamp.timestamp, 0);

// Tower has vote no timestamp, but is greater than heaviest_bank
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (6, 1)]));
tower.last_vote = VoteTransaction::from(TowerSync::from(vec![(0, 3), (1, 2), (6, 1)]));
assert_eq!(tower.last_vote.timestamp(), None);
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), None);
assert_eq!(tower.last_timestamp.slot, 0);
assert_eq!(tower.last_timestamp.timestamp, 0);

// Tower has vote with no timestamp
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]));
tower.last_vote = VoteTransaction::from(TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]));
assert_eq!(tower.last_vote.timestamp(), None);
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), Some(1));
assert_eq!(tower.last_timestamp.slot, 2);
assert_eq!(tower.last_timestamp.timestamp, 1);

// Vote has timestamp
tower.last_vote =
VoteTransaction::from(VoteStateUpdate::from(vec![(0, 3), (1, 2), (2, 1)]));
tower.last_vote = VoteTransaction::from(TowerSync::from(vec![(0, 3), (1, 2), (2, 1)]));
tower.refresh_last_vote_timestamp(5);
assert_eq!(tower.last_vote.timestamp(), Some(2));
assert_eq!(tower.last_timestamp.slot, 2);
Expand Down
2 changes: 2 additions & 0 deletions core/src/replay_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3390,6 +3390,8 @@ impl ReplayStage {
progress
.get_hash(last_voted_slot)
.expect("Must exist for us to have frozen descendant"),
bank.feature_set
.is_active(&feature_set::enable_tower_sync_ix::id()),
);
// Since we are updating our tower we need to update associated caches for previously computed
// slots as well.
Expand Down
4 changes: 2 additions & 2 deletions core/src/verified_vote_packets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use {
slot_hashes::SlotHashes,
sysvar,
},
solana_vote::vote_transaction::{VoteTransaction, VoteTransaction::VoteStateUpdate},
solana_vote::vote_transaction::VoteTransaction,
std::{
collections::{BTreeMap, HashMap, HashSet},
sync::Arc,
Expand Down Expand Up @@ -231,7 +231,7 @@ impl VerifiedVotePackets {
let timestamp = vote.timestamp();

match vote {
VoteStateUpdate(_) => {
VoteTransaction::VoteStateUpdate(_) | VoteTransaction::TowerSync(_) => {
let (latest_gossip_slot, latest_timestamp) =
self.0.get(&vote_account_key).map_or((0, None), |vote| {
(vote.get_latest_gossip_slot(), vote.get_latest_timestamp())
Expand Down
49 changes: 42 additions & 7 deletions programs/vote/src/vote_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,25 @@ declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context|
&invoke_context.feature_set,
)
}
VoteInstruction::TowerSync(_tower_sync)
| VoteInstruction::TowerSyncSwitch(_tower_sync, _) => {
VoteInstruction::TowerSync(tower_sync)
| VoteInstruction::TowerSyncSwitch(tower_sync, _) => {
if !invoke_context
.feature_set
.is_active(&feature_set::enable_tower_sync_ix::id())
{
return Err(InstructionError::InvalidInstructionData);
}
// TODO: will fill in future PR
return Err(InstructionError::InvalidInstructionData);
let sysvar_cache = invoke_context.get_sysvar_cache();
let slot_hashes = sysvar_cache.get_slot_hashes()?;
let clock = sysvar_cache.get_clock()?;
vote_state::process_tower_sync(
&mut me,
slot_hashes.slot_hashes(),
&clock,
tower_sync,
&signers,
&invoke_context.feature_set,
)
}
VoteInstruction::Withdraw(lamports) => {
instruction_context.check_number_of_instruction_accounts(2)?;
Expand Down Expand Up @@ -257,7 +266,7 @@ mod tests {
vote_switch, withdraw, CreateVoteAccountConfig, VoteInstruction,
},
vote_state::{
self, Lockout, Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs,
self, Lockout, TowerSync, Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs,
VoteAuthorizeWithSeedArgs, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions,
},
},
Expand All @@ -274,6 +283,7 @@ mod tests {
self, clock::Clock, epoch_schedule::EpochSchedule, rent::Rent,
slot_hashes::SlotHashes,
},
vote::instruction::{tower_sync, tower_sync_switch},
},
std::{collections::HashSet, str::FromStr},
};
Expand Down Expand Up @@ -490,11 +500,12 @@ mod tests {
(vote_pubkey, vote_account_with_epoch_credits)
}

/// Returns Vec of serialized VoteInstruction and flag indicating if it is a vote state update
/// Returns Vec of serialized VoteInstruction and flag indicating if it is a vote state proposal
/// variant, along with the original vote
fn create_serialized_votes() -> (Vote, Vec<(Vec<u8>, bool)>) {
let vote = Vote::new(vec![1], Hash::default());
let vote_state_update = VoteStateUpdate::from(vec![(1, 1)]);
let tower_sync = TowerSync::from(vec![(1, 1)]);
(
vote.clone(),
vec![
Expand All @@ -508,6 +519,10 @@ mod tests {
serialize(&VoteInstruction::CompactUpdateVoteState(vote_state_update)).unwrap(),
true,
),
(
serialize(&VoteInstruction::TowerSync(tower_sync)).unwrap(),
true,
),
],
)
}
Expand Down Expand Up @@ -1742,6 +1757,14 @@ mod tests {
),
Err(InstructionError::InvalidAccountOwner),
);
process_instruction_as_one_arg(
&tower_sync(
&invalid_vote_state_pubkey(),
&Pubkey::default(),
TowerSync::default(),
),
Err(InstructionError::InvalidAccountOwner),
);
}

#[test]
Expand Down Expand Up @@ -1904,7 +1927,6 @@ mod tests {
),
Err(InstructionError::InvalidAccountData),
);

process_instruction_as_one_arg(
&compact_update_vote_state_switch(
&Pubkey::default(),
Expand All @@ -1914,6 +1936,19 @@ mod tests {
),
Err(InstructionError::InvalidAccountData),
);
process_instruction_as_one_arg(
&tower_sync(&Pubkey::default(), &Pubkey::default(), TowerSync::default()),
Err(InstructionError::InvalidAccountData),
);
process_instruction_as_one_arg(
&tower_sync_switch(
&Pubkey::default(),
&Pubkey::default(),
TowerSync::default(),
Hash::default(),
),
Err(InstructionError::InvalidAccountData),
);

process_instruction_as_one_arg(
&update_validator_identity(
Expand Down
Loading