vote account withdraw authority may change the authorized voter

This commit is contained in:
Michael Vines 2022-01-14 17:38:01 -08:00
parent 3bd5a89d6f
commit 65f1e0fcc2
3 changed files with 73 additions and 4 deletions

View File

@ -86,7 +86,14 @@ pub fn process_instruction(
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
invoke_context,
)?;
vote_state::authorize(me, &voter_pubkey, vote_authorize, &signers, &clock)
vote_state::authorize(
me,
&voter_pubkey,
vote_authorize,
&signers,
&clock,
&invoke_context.feature_set,
)
}
VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity(
me,
@ -166,6 +173,7 @@ pub fn process_instruction(
keyed_accounts,
first_instruction_account + 1,
)?)?,
&invoke_context.feature_set,
)
} else {
Err(InstructionError::InvalidInstructionData)

View File

@ -10,7 +10,7 @@ use {
account_utils::State,
clock::{Epoch, Slot, UnixTimestamp},
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
feature_set::{filter_votes_outside_slot_hashes, FeatureSet},
feature_set::{self, filter_votes_outside_slot_hashes, FeatureSet},
hash::Hash,
instruction::InstructionError,
keyed_account::KeyedAccount,
@ -921,21 +921,37 @@ pub fn authorize<S: std::hash::BuildHasher>(
vote_authorize: VoteAuthorize,
signers: &HashSet<Pubkey, S>,
clock: &Clock,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let mut vote_state: VoteState =
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
// current authorized signer must say "yay"
match vote_authorize {
VoteAuthorize::Voter => {
let authorized_withdrawer_signer = if feature_set
.is_active(&feature_set::vote_withdraw_authority_may_change_authorized_voter::id())
{
verify_authorized_signer(&vote_state.authorized_withdrawer, signers).is_ok()
} else {
false
};
vote_state.set_new_authorized_voter(
authorized,
clock.epoch,
clock.leader_schedule_epoch + 1,
|epoch_authorized_voter| verify_authorized_signer(&epoch_authorized_voter, signers),
|epoch_authorized_voter| {
// current authorized withdrawer or authorized voter must say "yay"
if authorized_withdrawer_signer {
Ok(())
} else {
verify_authorized_signer(&epoch_authorized_voter, signers)
}
},
)?;
}
VoteAuthorize::Withdrawer => {
// current authorized withdrawer must say "yay"
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
vote_state.authorized_withdrawer = *authorized;
}
@ -1558,6 +1574,7 @@ mod tests {
leader_schedule_epoch: 2,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
@ -1573,6 +1590,7 @@ mod tests {
leader_schedule_epoch: 2,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));
@ -1588,6 +1606,7 @@ mod tests {
leader_schedule_epoch: 2,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Err(VoteError::TooSoonToReauthorize.into()));
@ -1610,6 +1629,7 @@ mod tests {
leader_schedule_epoch: 4,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));
@ -1628,6 +1648,7 @@ mod tests {
leader_schedule_epoch: 4,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));
@ -1648,6 +1669,7 @@ mod tests {
leader_schedule_epoch: 4,
..Clock::default()
},
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));
@ -1690,6 +1712,39 @@ mod tests {
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));
// verify authorized_withdrawer can authorize a new authorized_voter when
// `feature_set::vote_withdraw_authority_may_change_authorized_voter` is enabled
let keyed_accounts = &[
KeyedAccount::new(&vote_pubkey, false, &vote_account),
KeyedAccount::new(&authorized_withdrawer_pubkey, true, &withdrawer_account),
];
let another_authorized_voter_pubkey = solana_sdk::pubkey::new_rand();
let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
for (feature_set, expected_res) in [
(
FeatureSet::default(),
Err(InstructionError::MissingRequiredSignature),
),
(FeatureSet::all_enabled(), Ok(())),
]
.into_iter()
{
let res = authorize(
&keyed_accounts[0],
&another_authorized_voter_pubkey,
VoteAuthorize::Voter,
&signers,
&Clock {
epoch: 4,
leader_schedule_epoch: 5,
..Clock::default()
},
&feature_set,
);
assert_eq!(res, expected_res)
}
}
#[test]
@ -2189,6 +2244,7 @@ mod tests {
VoteAuthorize::Withdrawer,
&signers,
&Clock::default(),
&FeatureSet::default(),
);
assert_eq!(res, Ok(()));

View File

@ -307,6 +307,10 @@ pub mod update_syscall_base_costs {
solana_sdk::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ");
}
pub mod vote_withdraw_authority_may_change_authorized_voter {
solana_sdk::declare_id!("AVZS3ZsN4gi6Rkx2QUibYuSJG3S6QHib7xCYhG6vGJxU");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -378,6 +382,7 @@ lazy_static! {
(require_rent_exempt_accounts::id(), "require all new transaction accounts with data to be rent-exempt"),
(filter_votes_outside_slot_hashes::id(), "filter vote slots older than the slot hashes history"),
(update_syscall_base_costs::id(), "Update syscall base costs"),
(vote_withdraw_authority_may_change_authorized_voter::id(), "vote account withdraw authority may change the authorized voter #22521"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()