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
2 changes: 2 additions & 0 deletions programs/vote/src/vote_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,8 @@ mod tests {
);
let vote_state = VoteStateV3::deserialize(accounts[0].data()).unwrap();
assert_eq!(vote_state.node_pubkey, node_pubkey);
// TODO: When the feature gate for vote state v4 is added, check the
// block revenue collector here for the v4 target.
}

#[test]
Expand Down
17 changes: 17 additions & 0 deletions programs/vote/src/vote_state/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub trait VoteStateHandle {

fn set_node_pubkey(&mut self, node_pubkey: Pubkey);

fn set_block_revenue_collector(&mut self, collector: Pubkey);

fn votes(&self) -> &VecDeque<LandedVote>;

fn votes_mut(&mut self) -> &mut VecDeque<LandedVote>;
Expand Down Expand Up @@ -353,6 +355,10 @@ impl VoteStateHandle for VoteStateV3 {
self.node_pubkey = node_pubkey;
}

fn set_block_revenue_collector(&mut self, _collector: Pubkey) {
// No-op for v3: field does not exist.
}

Comment on lines +358 to +361
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this looks weird, but I intentionally didn't tuck the syncing into VoteStateV4::set_node_pubkey because:

  • We will clean up impl VoteStateHandle for VoteStateV3 once the feature is active and the target version is always v4
  • We will need to decouple the setting of block revenue collector anyway

fn votes(&self) -> &VecDeque<LandedVote> {
&self.votes
}
Expand Down Expand Up @@ -516,6 +522,10 @@ impl VoteStateHandle for VoteStateV4 {
self.node_pubkey = node_pubkey;
}

fn set_block_revenue_collector(&mut self, collector: Pubkey) {
self.block_revenue_collector = collector;
}

fn votes(&self) -> &VecDeque<LandedVote> {
&self.votes
}
Expand Down Expand Up @@ -749,6 +759,13 @@ impl VoteStateHandle for VoteStateHandler {
}
}

fn set_block_revenue_collector(&mut self, collector: Pubkey) {
match &mut self.target_state {
TargetVoteState::V3(v3) => v3.set_block_revenue_collector(collector),
TargetVoteState::V4(v4) => v4.set_block_revenue_collector(collector),
}
}

fn votes(&self) -> &VecDeque<LandedVote> {
match &self.target_state {
TargetVoteState::V3(v3) => v3.votes(),
Expand Down
76 changes: 76 additions & 0 deletions programs/vote/src/vote_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,9 @@ pub fn update_validator_identity<S: std::hash::BuildHasher>(
verify_authorized_signer(node_pubkey, signers)?;

vote_state.set_node_pubkey(*node_pubkey);
// Keep block_revenue_collector in sync with node_pubkey until SIMD-0232
// is implemented.
vote_state.set_block_revenue_collector(*node_pubkey);

vote_state.set_vote_account_state(vote_account)
}
Expand Down Expand Up @@ -3658,4 +3661,77 @@ mod tests {
inflation_rewards_commission_bps
);
}

#[test]
fn test_update_validator_identity_syncs_block_revenue_collector() {
let vote_state =
vote_state_new_for_test(&solana_pubkey::new_rand(), VoteStateTargetVersion::V4);
let node_pubkey = *vote_state.node_pubkey();
let withdrawer_pubkey = *vote_state.authorized_withdrawer();

let serialized = vote_state.serialize();
let serialized_len = serialized.len();
let rent = Rent::default();
let lamports = rent.minimum_balance(serialized_len);
let mut vote_account = AccountSharedData::new(lamports, serialized_len, &id());
vote_account.set_data_from_slice(&serialized);

let processor_account = AccountSharedData::new(0, 0, &solana_sdk_ids::native_loader::id());
let mut transaction_context = TransactionContext::new(
vec![(id(), processor_account), (node_pubkey, vote_account)],
rent,
0,
0,
);
transaction_context
.configure_next_instruction_for_tests(
0,
vec![InstructionAccount::new(1, false, true)],
vec![],
)
.unwrap();
let instruction_context = transaction_context.get_next_instruction_context().unwrap();
let mut borrowed_account = instruction_context
.try_borrow_instruction_account(0)
.unwrap();

let new_node_pubkey = solana_pubkey::new_rand();
let signers: HashSet<Pubkey> = vec![withdrawer_pubkey, new_node_pubkey]
.into_iter()
.collect();

update_validator_identity(
&mut borrowed_account,
VoteStateTargetVersion::V4,
&new_node_pubkey,
&signers,
)
.unwrap();

// Both `node_pubkey` and `block_revenue_collector` should be set to
// the new node pubkey.
let vote_state =
VoteStateV4::deserialize(borrowed_account.get_data(), &new_node_pubkey).unwrap();
assert_eq!(vote_state.node_pubkey, new_node_pubkey);
assert_eq!(vote_state.block_revenue_collector, new_node_pubkey);

// Run it again.
let new_node_pubkey = solana_pubkey::new_rand();
let signers: HashSet<Pubkey> = vec![withdrawer_pubkey, new_node_pubkey]
.into_iter()
.collect();

update_validator_identity(
&mut borrowed_account,
VoteStateTargetVersion::V4,
&new_node_pubkey,
&signers,
)
.unwrap();

let vote_state =
VoteStateV4::deserialize(borrowed_account.get_data(), &new_node_pubkey).unwrap();
assert_eq!(vote_state.node_pubkey, new_node_pubkey);
assert_eq!(vote_state.block_revenue_collector, new_node_pubkey);
}
}
Loading