vote account withdraw authority may change the authorized voter
This commit is contained in:
parent
3bd5a89d6f
commit
65f1e0fcc2
|
@ -86,7 +86,14 @@ pub fn process_instruction(
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
||||||
invoke_context,
|
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(
|
VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity(
|
||||||
me,
|
me,
|
||||||
|
@ -166,6 +173,7 @@ pub fn process_instruction(
|
||||||
keyed_accounts,
|
keyed_accounts,
|
||||||
first_instruction_account + 1,
|
first_instruction_account + 1,
|
||||||
)?)?,
|
)?)?,
|
||||||
|
&invoke_context.feature_set,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
|
|
@ -10,7 +10,7 @@ use {
|
||||||
account_utils::State,
|
account_utils::State,
|
||||||
clock::{Epoch, Slot, UnixTimestamp},
|
clock::{Epoch, Slot, UnixTimestamp},
|
||||||
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
|
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,
|
hash::Hash,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
|
@ -921,21 +921,37 @@ pub fn authorize<S: std::hash::BuildHasher>(
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
clock: &Clock,
|
clock: &Clock,
|
||||||
|
feature_set: &FeatureSet,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state: VoteState =
|
let mut vote_state: VoteState =
|
||||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||||
|
|
||||||
// current authorized signer must say "yay"
|
|
||||||
match vote_authorize {
|
match vote_authorize {
|
||||||
VoteAuthorize::Voter => {
|
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(
|
vote_state.set_new_authorized_voter(
|
||||||
authorized,
|
authorized,
|
||||||
clock.epoch,
|
clock.epoch,
|
||||||
clock.leader_schedule_epoch + 1,
|
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 => {
|
VoteAuthorize::Withdrawer => {
|
||||||
|
// current authorized withdrawer must say "yay"
|
||||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
||||||
vote_state.authorized_withdrawer = *authorized;
|
vote_state.authorized_withdrawer = *authorized;
|
||||||
}
|
}
|
||||||
|
@ -1558,6 +1574,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 2,
|
leader_schedule_epoch: 2,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
|
assert_eq!(res, Err(InstructionError::MissingRequiredSignature));
|
||||||
|
|
||||||
|
@ -1573,6 +1590,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 2,
|
leader_schedule_epoch: 2,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
@ -1588,6 +1606,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 2,
|
leader_schedule_epoch: 2,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Err(VoteError::TooSoonToReauthorize.into()));
|
assert_eq!(res, Err(VoteError::TooSoonToReauthorize.into()));
|
||||||
|
|
||||||
|
@ -1610,6 +1629,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 4,
|
leader_schedule_epoch: 4,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
@ -1628,6 +1648,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 4,
|
leader_schedule_epoch: 4,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
@ -1648,6 +1669,7 @@ mod tests {
|
||||||
leader_schedule_epoch: 4,
|
leader_schedule_epoch: 4,
|
||||||
..Clock::default()
|
..Clock::default()
|
||||||
},
|
},
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
@ -1690,6 +1712,39 @@ mod tests {
|
||||||
&FeatureSet::default(),
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
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]
|
#[test]
|
||||||
|
@ -2189,6 +2244,7 @@ mod tests {
|
||||||
VoteAuthorize::Withdrawer,
|
VoteAuthorize::Withdrawer,
|
||||||
&signers,
|
&signers,
|
||||||
&Clock::default(),
|
&Clock::default(),
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,10 @@ pub mod update_syscall_base_costs {
|
||||||
solana_sdk::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ");
|
solana_sdk::declare_id!("2h63t332mGCCsWK2nqqqHhN4U9ayyqhLVFvczznHDoTZ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod vote_withdraw_authority_may_change_authorized_voter {
|
||||||
|
solana_sdk::declare_id!("AVZS3ZsN4gi6Rkx2QUibYuSJG3S6QHib7xCYhG6vGJxU");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
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"),
|
(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"),
|
(filter_votes_outside_slot_hashes::id(), "filter vote slots older than the slot hashes history"),
|
||||||
(update_syscall_base_costs::id(), "Update syscall base costs"),
|
(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 ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
|
Loading…
Reference in New Issue