Allow creating an vote program ix where the withdrawer is also the "to" account (#6992)
automerge
This commit is contained in:
parent
c902fd0303
commit
3acd84d9c0
|
@ -7,7 +7,7 @@ use num_derive::{FromPrimitive, ToPrimitive};
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
use solana_sdk::{
|
||||
account::{get_signers, KeyedAccount},
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
instruction::{AccountMeta, Instruction, InstructionError, WithSigner},
|
||||
instruction_processor_utils::{limited_deserialize, next_keyed_account, DecodeError},
|
||||
pubkey::Pubkey,
|
||||
system_instruction,
|
||||
|
@ -175,17 +175,14 @@ pub fn split(
|
|||
std::mem::size_of::<StakeState>() as u64,
|
||||
&id(),
|
||||
),
|
||||
Instruction::new(
|
||||
id(),
|
||||
&StakeInstruction::Split(lamports),
|
||||
metas_with_signer(
|
||||
&[
|
||||
{
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new(*split_stake_pubkey, false),
|
||||
],
|
||||
authorized_pubkey,
|
||||
),
|
||||
),
|
||||
]
|
||||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(id(), &StakeInstruction::Split(lamports), account_metas)
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -220,34 +217,13 @@ pub fn create_stake_account_and_delegate_stake(
|
|||
instructions
|
||||
}
|
||||
|
||||
// for instructions whose authorized signer may already be in account parameters
|
||||
fn metas_with_signer(
|
||||
metas: &[AccountMeta], // parameter metas, in order
|
||||
signer: &Pubkey, // might already appear in parameters
|
||||
) -> Vec<AccountMeta> {
|
||||
let mut metas = metas.to_vec();
|
||||
|
||||
for meta in metas.iter_mut() {
|
||||
if &meta.pubkey == signer {
|
||||
meta.is_signer = true; // found it, we're done
|
||||
return metas;
|
||||
}
|
||||
}
|
||||
|
||||
// signer wasn't in metas, append it after normal parameters
|
||||
metas.push(AccountMeta::new_readonly(*signer, true));
|
||||
|
||||
metas
|
||||
}
|
||||
|
||||
pub fn authorize(
|
||||
stake_pubkey: &Pubkey,
|
||||
authorized_pubkey: &Pubkey,
|
||||
new_authorized_pubkey: &Pubkey,
|
||||
stake_authorize: StakeAuthorize,
|
||||
) -> Instruction {
|
||||
let account_metas =
|
||||
metas_with_signer(&[AccountMeta::new(*stake_pubkey, false)], authorized_pubkey);
|
||||
let account_metas = vec![AccountMeta::new(*stake_pubkey, false)].with_signer(authorized_pubkey);
|
||||
|
||||
Instruction::new(
|
||||
id(),
|
||||
|
@ -272,15 +248,13 @@ pub fn delegate_stake(
|
|||
authorized_pubkey: &Pubkey,
|
||||
vote_pubkey: &Pubkey,
|
||||
) -> Instruction {
|
||||
let account_metas = metas_with_signer(
|
||||
&[
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new_readonly(*vote_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(crate::config::id(), false),
|
||||
],
|
||||
authorized_pubkey,
|
||||
);
|
||||
]
|
||||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(id(), &StakeInstruction::DelegateStake, account_metas)
|
||||
}
|
||||
|
||||
|
@ -290,26 +264,22 @@ pub fn withdraw(
|
|||
to_pubkey: &Pubkey,
|
||||
lamports: u64,
|
||||
) -> Instruction {
|
||||
let account_metas = metas_with_signer(
|
||||
&[
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new(*to_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
AccountMeta::new_readonly(sysvar::stake_history::id(), false),
|
||||
],
|
||||
authorized_pubkey,
|
||||
);
|
||||
]
|
||||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
|
||||
}
|
||||
|
||||
pub fn deactivate_stake(stake_pubkey: &Pubkey, authorized_pubkey: &Pubkey) -> Instruction {
|
||||
let account_metas = metas_with_signer(
|
||||
&[
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*stake_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
],
|
||||
authorized_pubkey,
|
||||
);
|
||||
]
|
||||
.with_signer(authorized_pubkey);
|
||||
Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use serde_derive::{Deserialize, Serialize};
|
|||
use solana_metrics::datapoint_debug;
|
||||
use solana_sdk::{
|
||||
account::{get_signers, KeyedAccount},
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
instruction::{AccountMeta, Instruction, InstructionError, WithSigner},
|
||||
instruction_processor_utils::{limited_deserialize, next_keyed_account, DecodeError},
|
||||
pubkey::Pubkey,
|
||||
system_instruction,
|
||||
|
@ -89,37 +89,13 @@ pub fn create_account(
|
|||
vec![create_ix, init_ix]
|
||||
}
|
||||
|
||||
// for instructions that whose authorized signer may differ from the account's pubkey
|
||||
fn metas_for_authorized_signer(
|
||||
account_pubkey: &Pubkey,
|
||||
authorized_signer: &Pubkey, // currently authorized
|
||||
other_params: &[AccountMeta],
|
||||
) -> Vec<AccountMeta> {
|
||||
let is_own_signer = authorized_signer == account_pubkey;
|
||||
|
||||
// vote account
|
||||
let mut account_metas = vec![AccountMeta::new(*account_pubkey, is_own_signer)];
|
||||
|
||||
for meta in other_params {
|
||||
account_metas.push(meta.clone());
|
||||
}
|
||||
|
||||
// append signer at the end
|
||||
if !is_own_signer {
|
||||
account_metas.push(AccountMeta::new_readonly(*authorized_signer, true))
|
||||
// signer
|
||||
}
|
||||
|
||||
account_metas
|
||||
}
|
||||
|
||||
pub fn authorize(
|
||||
vote_pubkey: &Pubkey,
|
||||
authorized_pubkey: &Pubkey, // currently authorized
|
||||
new_authorized_pubkey: &Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
) -> Instruction {
|
||||
let account_metas = metas_for_authorized_signer(vote_pubkey, authorized_pubkey, &[]);
|
||||
let account_metas = vec![AccountMeta::new(*vote_pubkey, false)].with_signer(authorized_pubkey);
|
||||
|
||||
Instruction::new(
|
||||
id(),
|
||||
|
@ -129,16 +105,12 @@ pub fn authorize(
|
|||
}
|
||||
|
||||
pub fn vote(vote_pubkey: &Pubkey, authorized_voter_pubkey: &Pubkey, vote: Vote) -> Instruction {
|
||||
let account_metas = metas_for_authorized_signer(
|
||||
vote_pubkey,
|
||||
authorized_voter_pubkey,
|
||||
&[
|
||||
// request slot_hashes sysvar account after vote_pubkey
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*vote_pubkey, false),
|
||||
AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
|
||||
// request clock sysvar account after that
|
||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
],
|
||||
);
|
||||
]
|
||||
.with_signer(authorized_voter_pubkey);
|
||||
|
||||
Instruction::new(id(), &VoteInstruction::Vote(vote), account_metas)
|
||||
}
|
||||
|
@ -149,11 +121,11 @@ pub fn withdraw(
|
|||
lamports: u64,
|
||||
to_pubkey: &Pubkey,
|
||||
) -> Instruction {
|
||||
let account_metas = metas_for_authorized_signer(
|
||||
vote_pubkey,
|
||||
withdrawer_pubkey,
|
||||
&[AccountMeta::new(*to_pubkey, false)],
|
||||
);
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(*vote_pubkey, false),
|
||||
AccountMeta::new(*to_pubkey, false),
|
||||
]
|
||||
.with_signer(withdrawer_pubkey);
|
||||
|
||||
Instruction::new(id(), &VoteInstruction::Withdraw(lamports), account_metas)
|
||||
}
|
||||
|
@ -292,20 +264,6 @@ mod tests {
|
|||
assert!(minimum_balance as f64 / 10f64.powf(9.0) < 0.02)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_metas_for_authorized_signer() {
|
||||
let account_pubkey = Pubkey::new_rand();
|
||||
let authorized_signer = Pubkey::new_rand();
|
||||
|
||||
assert_eq!(
|
||||
metas_for_authorized_signer(&account_pubkey, &authorized_signer, &[]).len(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
metas_for_authorized_signer(&account_pubkey, &account_pubkey, &[]).len(),
|
||||
1
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_custom_error_decode() {
|
||||
use num_traits::FromPrimitive;
|
||||
|
|
|
@ -141,6 +141,28 @@ impl AccountMeta {
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait for adding a signer Pubkey to an existing data structure
|
||||
pub trait WithSigner {
|
||||
/// Add a signer Pubkey
|
||||
fn with_signer(self, signer: &Pubkey) -> Self;
|
||||
}
|
||||
|
||||
impl WithSigner for Vec<AccountMeta> {
|
||||
fn with_signer(mut self, signer: &Pubkey) -> Self {
|
||||
for meta in self.iter_mut() {
|
||||
// signer might already appear in parameters
|
||||
if &meta.pubkey == signer {
|
||||
meta.is_signer = true; // found it, we're done
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
// signer wasn't in metas, append it after normal parameters
|
||||
self.push(AccountMeta::new_readonly(*signer, true));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// An instruction to execute a program
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||
pub struct CompiledInstruction {
|
||||
|
@ -168,3 +190,38 @@ impl CompiledInstruction {
|
|||
&program_ids[self.program_id_index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_account_meta_list_with_signer() {
|
||||
let account_pubkey = Pubkey::new_rand();
|
||||
let signer_pubkey = Pubkey::new_rand();
|
||||
|
||||
let account_meta = AccountMeta::new(account_pubkey, false);
|
||||
let signer_account_meta = AccountMeta::new(signer_pubkey, false);
|
||||
|
||||
let metas = vec![].with_signer(&signer_pubkey);
|
||||
assert_eq!(metas.len(), 1);
|
||||
assert!(metas[0].is_signer);
|
||||
|
||||
let metas = vec![account_meta.clone()].with_signer(&signer_pubkey);
|
||||
assert_eq!(metas.len(), 2);
|
||||
assert!(!metas[0].is_signer);
|
||||
assert!(metas[1].is_signer);
|
||||
assert_eq!(metas[1].pubkey, signer_pubkey);
|
||||
|
||||
let metas = vec![signer_account_meta.clone()].with_signer(&signer_pubkey);
|
||||
assert_eq!(metas.len(), 1);
|
||||
assert!(metas[0].is_signer);
|
||||
assert_eq!(metas[0].pubkey, signer_pubkey);
|
||||
|
||||
let metas = vec![account_meta, signer_account_meta].with_signer(&signer_pubkey);
|
||||
assert_eq!(metas.len(), 2);
|
||||
assert!(!metas[0].is_signer);
|
||||
assert!(metas[1].is_signer);
|
||||
assert_eq!(metas[1].pubkey, signer_pubkey);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue