vote account withdraw authority may change the authorized voter
This commit is contained in:
@ -409,7 +409,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,
|
||||||
@ -461,6 +468,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,6 +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::{self, FeatureSet},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
keyed_account::KeyedAccount,
|
keyed_account::KeyedAccount,
|
||||||
@ -813,21 +814,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;
|
||||||
}
|
}
|
||||||
@ -1408,6 +1425,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));
|
||||||
|
|
||||||
@ -1423,6 +1441,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(()));
|
||||||
|
|
||||||
@ -1438,6 +1457,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()));
|
||||||
|
|
||||||
@ -1460,6 +1480,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(()));
|
||||||
|
|
||||||
@ -1478,6 +1499,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(()));
|
||||||
|
|
||||||
@ -1498,6 +1520,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(()));
|
||||||
|
|
||||||
@ -1538,6 +1561,39 @@ mod tests {
|
|||||||
&signers,
|
&signers,
|
||||||
);
|
);
|
||||||
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]
|
||||||
@ -2019,6 +2075,7 @@ mod tests {
|
|||||||
VoteAuthorize::Withdrawer,
|
VoteAuthorize::Withdrawer,
|
||||||
&signers,
|
&signers,
|
||||||
&Clock::default(),
|
&Clock::default(),
|
||||||
|
&FeatureSet::default(),
|
||||||
);
|
);
|
||||||
assert_eq!(res, Ok(()));
|
assert_eq!(res, Ok(()));
|
||||||
|
|
||||||
|
@ -287,6 +287,10 @@ pub mod require_rent_exempt_accounts {
|
|||||||
solana_sdk::declare_id!("BkFDxiJQWZXGTZaJQxH7wVEHkAmwCgSEVkrvswFfRJPD");
|
solana_sdk::declare_id!("BkFDxiJQWZXGTZaJQxH7wVEHkAmwCgSEVkrvswFfRJPD");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> = [
|
||||||
@ -353,6 +357,7 @@ lazy_static! {
|
|||||||
(cap_accounts_data_len::id(), "cap the accounts data len"),
|
(cap_accounts_data_len::id(), "cap the accounts data len"),
|
||||||
(max_tx_account_locks::id(), "enforce max number of locked accounts per transaction"),
|
(max_tx_account_locks::id(), "enforce max number of locked accounts per transaction"),
|
||||||
(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"),
|
||||||
|
(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()
|
||||||
|
Reference in New Issue
Block a user