diff --git a/programs/budget_api/src/budget_instruction.rs b/programs/budget_api/src/budget_instruction.rs index 71be56c6dd..7cd6f796c7 100644 --- a/programs/budget_api/src/budget_instruction.rs +++ b/programs/budget_api/src/budget_instruction.rs @@ -3,7 +3,7 @@ use crate::id; use chrono::prelude::{DateTime, Utc}; use serde_derive::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::Instruction; +use solana_sdk::transaction::{AccountMeta, Instruction}; /// A smart contract. #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] @@ -31,9 +31,9 @@ impl BudgetInstruction { pub fn new_initialize_account(contract: &Pubkey, expr: BudgetExpr) -> Instruction { let mut keys = vec![]; if let BudgetExpr::Pay(payment) = &expr { - keys.push((payment.to, false)); + keys.push(AccountMeta(payment.to, false)); } - keys.push((*contract, false)); + keys.push(AccountMeta(*contract, false)); Instruction::new(id(), &BudgetInstruction::InitializeAccount(expr), keys) } @@ -43,17 +43,17 @@ impl BudgetInstruction { to: &Pubkey, dt: DateTime, ) -> Instruction { - let mut keys = vec![(*from, true), (*contract, false)]; + let mut keys = vec![AccountMeta(*from, true), AccountMeta(*contract, false)]; if from != to { - keys.push((*to, false)); + keys.push(AccountMeta(*to, false)); } Instruction::new(id(), &BudgetInstruction::ApplyTimestamp(dt), keys) } pub fn new_apply_signature(from: &Pubkey, contract: &Pubkey, to: &Pubkey) -> Instruction { - let mut keys = vec![(*from, true), (*contract, false)]; + let mut keys = vec![AccountMeta(*from, true), AccountMeta(*contract, false)]; if from != to { - keys.push((*to, false)); + keys.push(AccountMeta(*to, false)); } Instruction::new(id(), &BudgetInstruction::ApplySignature, keys) } diff --git a/programs/config_api/src/config_instruction.rs b/programs/config_api/src/config_instruction.rs index b0feafdcb7..2953bfda79 100644 --- a/programs/config_api/src/config_instruction.rs +++ b/programs/config_api/src/config_instruction.rs @@ -2,7 +2,7 @@ use crate::id; use crate::ConfigState; use solana_sdk::pubkey::Pubkey; use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::transaction::Instruction; +use solana_sdk::transaction::{AccountMeta, Instruction}; pub struct ConfigInstruction {} @@ -28,10 +28,10 @@ impl ConfigInstruction { config_account_pubkey: &Pubkey, data: &T, ) -> Instruction { - Instruction::new( - id(), - data, - vec![(*from_account_pubkey, true), (*config_account_pubkey, true)], - ) + let account_metas = vec![ + AccountMeta(*from_account_pubkey, true), + AccountMeta(*config_account_pubkey, true), + ]; + Instruction::new(id(), data, account_metas) } } diff --git a/programs/rewards_api/src/rewards_instruction.rs b/programs/rewards_api/src/rewards_instruction.rs index f278b96116..6018b3297a 100644 --- a/programs/rewards_api/src/rewards_instruction.rs +++ b/programs/rewards_api/src/rewards_instruction.rs @@ -1,7 +1,7 @@ use crate::id; use serde_derive::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::Instruction; +use solana_sdk::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum RewardsInstruction { @@ -10,10 +10,7 @@ pub enum RewardsInstruction { impl RewardsInstruction { pub fn new_redeem_vote_credits(vote_id: &Pubkey, rewards_id: &Pubkey) -> Instruction { - Instruction::new( - id(), - &RewardsInstruction::RedeemVoteCredits, - vec![(*vote_id, true), (*rewards_id, false)], - ) + let account_metas = vec![AccountMeta(*vote_id, true), AccountMeta(*rewards_id, false)]; + Instruction::new(id(), &RewardsInstruction::RedeemVoteCredits, account_metas) } } diff --git a/programs/vote/tests/vote.rs b/programs/vote/tests/vote.rs index 80ea549489..d313d0e8cf 100644 --- a/programs/vote/tests/vote.rs +++ b/programs/vote/tests/vote.rs @@ -4,7 +4,9 @@ use solana_sdk::hash::hash; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; -use solana_sdk::transaction::{Instruction, InstructionError, Transaction, TransactionError}; +use solana_sdk::transaction::{ + AccountMeta, Instruction, InstructionError, Transaction, TransactionError, +}; use solana_vote_api::vote_instruction::{Vote, VoteInstruction}; use solana_vote_api::vote_state::VoteState; use solana_vote_api::vote_transaction::VoteTransaction; @@ -112,7 +114,7 @@ fn test_vote_via_bank_with_no_signature() { let vote_ix = Instruction::new( solana_vote_api::id(), &VoteInstruction::Vote(Vote::new(0)), - vec![(vote_id, false)], // <--- attack!! No signature. + vec![AccountMeta(vote_id, false)], // <--- attack!! No signature. ); // Sneak in an instruction so that the transaction is signed but diff --git a/programs/vote_api/src/vote_instruction.rs b/programs/vote_api/src/vote_instruction.rs index efccda2597..13c13d5c79 100644 --- a/programs/vote_api/src/vote_instruction.rs +++ b/programs/vote_api/src/vote_instruction.rs @@ -1,7 +1,7 @@ use crate::id; use serde_derive::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; -use solana_sdk::transaction::Instruction; +use solana_sdk::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Default, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Vote { @@ -33,30 +33,31 @@ pub enum VoteInstruction { impl VoteInstruction { pub fn new_clear_credits(vote_id: &Pubkey) -> Instruction { - Instruction::new(id(), &VoteInstruction::ClearCredits, vec![(*vote_id, true)]) + let account_metas = vec![AccountMeta(*vote_id, true)]; + Instruction::new(id(), &VoteInstruction::ClearCredits, account_metas) } pub fn new_delegate_stake(vote_id: &Pubkey, delegate_id: &Pubkey) -> Instruction { + let account_metas = vec![AccountMeta(*vote_id, true)]; Instruction::new( id(), &VoteInstruction::DelegateStake(*delegate_id), - vec![(*vote_id, true)], + account_metas, ) } pub fn new_authorize_voter(vote_id: &Pubkey, authorized_voter_id: &Pubkey) -> Instruction { + let account_metas = vec![AccountMeta(*vote_id, true)]; Instruction::new( id(), &VoteInstruction::AuthorizeVoter(*authorized_voter_id), - vec![(*vote_id, true)], + account_metas, ) } pub fn new_initialize_account(vote_id: &Pubkey) -> Instruction { - Instruction::new( - id(), - &VoteInstruction::InitializeAccount, - vec![(*vote_id, false)], - ) + let account_metas = vec![AccountMeta(*vote_id, false)]; + Instruction::new(id(), &VoteInstruction::InitializeAccount, account_metas) } pub fn new_vote(vote_id: &Pubkey, vote: Vote) -> Instruction { - Instruction::new(id(), &VoteInstruction::Vote(vote), vec![(*vote_id, true)]) + let account_metas = vec![AccountMeta(*vote_id, true)]; + Instruction::new(id(), &VoteInstruction::Vote(vote), account_metas) } } diff --git a/runtime/src/bank_client.rs b/runtime/src/bank_client.rs index 634de975a4..d67c009b95 100644 --- a/runtime/src/bank_client.rs +++ b/runtime/src/bank_client.rs @@ -67,6 +67,7 @@ impl<'a> BankClient<'a> { mod tests { use super::*; use solana_sdk::genesis_block::GenesisBlock; + use solana_sdk::transaction::AccountMeta; #[test] fn test_bank_client_new_with_keypairs() { @@ -81,7 +82,9 @@ mod tests { let bob_pubkey = Keypair::new().pubkey(); let mut move_instruction = SystemInstruction::new_move(&doe_client.pubkey(), &bob_pubkey, 42); - move_instruction.accounts.push((jane_pubkey, true)); + move_instruction + .accounts + .push(AccountMeta(jane_pubkey, true)); doe_client.process_instruction(move_instruction).unwrap(); assert_eq!(bank.get_balance(&bob_pubkey), 42); diff --git a/runtime/src/system_program.rs b/runtime/src/system_program.rs index c8e0042f25..ccaa593fa9 100644 --- a/runtime/src/system_program.rs +++ b/runtime/src/system_program.rs @@ -112,7 +112,7 @@ mod tests { use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::system_instruction::SystemInstruction; use solana_sdk::system_program; - use solana_sdk::transaction::{Instruction, InstructionError, TransactionError}; + use solana_sdk::transaction::{AccountMeta, Instruction, InstructionError, TransactionError}; #[test] fn test_create_system_account() { @@ -291,10 +291,14 @@ mod tests { // Erroneously sign transaction with recipient account key // No signature case is tested by bank `test_zero_signatures()` + let account_metas = vec![ + AccountMeta(alice_pubkey, false), + AccountMeta(mallory_pubkey, true), + ]; let malicious_script = Script::new(vec![Instruction::new( system_program::id(), &SystemInstruction::Move { lamports: 10 }, - vec![(alice_pubkey, false), (mallory_pubkey, true)], + account_metas, )]); assert_eq!( mallory_client.process_script(malicious_script), diff --git a/sdk/src/script.rs b/sdk/src/script.rs index 3a2b524d76..e8ca5c0ccd 100644 --- a/sdk/src/script.rs +++ b/sdk/src/script.rs @@ -2,7 +2,7 @@ use crate::hash::Hash; use crate::pubkey::Pubkey; -use crate::transaction::{CompiledInstruction, Instruction, Transaction}; +use crate::transaction::{AccountMeta, CompiledInstruction, Instruction, Transaction}; use itertools::Itertools; fn position(keys: &[Pubkey], key: &Pubkey) -> u8 { @@ -14,7 +14,12 @@ fn compile_instruction( keys: &[Pubkey], program_ids: &[Pubkey], ) -> CompiledInstruction { - let accounts: Vec<_> = ix.accounts.iter().map(|(k, _)| position(keys, k)).collect(); + let accounts: Vec<_> = ix + .accounts + .iter() + .map(|AccountMeta(k, _)| position(keys, k)) + .collect(); + CompiledInstruction { program_ids_index: position(program_ids, &ix.program_ids_index), data: ix.data.clone(), @@ -55,7 +60,7 @@ impl Script { let mut signed_keys = vec![]; let mut unsigned_keys = vec![]; - for (key, signed) in keys_and_signed.into_iter().unique_by(|x| x.0) { + for AccountMeta(key, signed) in keys_and_signed.into_iter().unique_by(|x| x.0) { if *signed { signed_keys.push(*key); } else { @@ -139,8 +144,8 @@ mod tests { let program_id = Pubkey::default(); let id0 = Pubkey::default(); let keys = Script::new(vec![ - Instruction::new(program_id, &0, vec![(id0, true)]), - Instruction::new(program_id, &0, vec![(id0, true)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]), ]) .keys(); assert_eq!(keys, (vec![id0], vec![])); @@ -151,8 +156,8 @@ mod tests { let program_id = Pubkey::default(); let id0 = Pubkey::default(); let keys = Script::new(vec![ - Instruction::new(program_id, &0, vec![(id0, false)]), - Instruction::new(program_id, &0, vec![(id0, true)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]), ]) .keys(); assert_eq!(keys, (vec![id0], vec![])); @@ -164,8 +169,8 @@ mod tests { let id0 = Keypair::new().pubkey(); let id1 = Pubkey::default(); // Key less than id0 let keys = Script::new(vec![ - Instruction::new(program_id, &0, vec![(id0, false)]), - Instruction::new(program_id, &0, vec![(id1, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id1, false)]), ]) .keys(); assert_eq!(keys, (vec![], vec![id0, id1])); @@ -177,9 +182,9 @@ mod tests { let id0 = Pubkey::default(); let id1 = Keypair::new().pubkey(); let keys = Script::new(vec![ - Instruction::new(program_id, &0, vec![(id0, false)]), - Instruction::new(program_id, &0, vec![(id1, false)]), - Instruction::new(program_id, &0, vec![(id0, true)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id1, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]), ]) .keys(); assert_eq!(keys, (vec![id0], vec![id1])); @@ -191,8 +196,8 @@ mod tests { let id0 = Pubkey::default(); let id1 = Keypair::new().pubkey(); let keys = Script::new(vec![ - Instruction::new(program_id, &0, vec![(id0, false)]), - Instruction::new(program_id, &0, vec![(id1, true)]), + Instruction::new(program_id, &0, vec![AccountMeta(id0, false)]), + Instruction::new(program_id, &0, vec![AccountMeta(id1, true)]), ]) .keys(); assert_eq!(keys, (vec![id1], vec![id0])); @@ -203,10 +208,12 @@ mod tests { fn test_transaction_builder_signed_keys_len() { let program_id = Pubkey::default(); let id0 = Pubkey::default(); - let tx = Script::new(vec![Instruction::new(program_id, &0, vec![(id0, false)])]).compile(); + let ix = Instruction::new(program_id, &0, vec![AccountMeta(id0, false)]); + let tx = Script::new(vec![ix]).compile(); assert_eq!(tx.signatures.capacity(), 0); - let tx = Script::new(vec![Instruction::new(program_id, &0, vec![(id0, true)])]).compile(); + let ix = Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]); + let tx = Script::new(vec![ix]).compile(); assert_eq!(tx.signatures.capacity(), 1); } @@ -218,9 +225,9 @@ mod tests { let keypair1 = Keypair::new(); let id1 = keypair1.pubkey(); let tx = Script::new(vec![ - Instruction::new(program_id0, &0, vec![(id0, false)]), - Instruction::new(program_id1, &0, vec![(id1, true)]), - Instruction::new(program_id0, &0, vec![(id1, false)]), + Instruction::new(program_id0, &0, vec![AccountMeta(id0, false)]), + Instruction::new(program_id1, &0, vec![AccountMeta(id1, true)]), + Instruction::new(program_id0, &0, vec![AccountMeta(id1, false)]), ]) .compile(); assert_eq!(tx.instructions[0], CompiledInstruction::new(0, &0, vec![1])); diff --git a/sdk/src/system_instruction.rs b/sdk/src/system_instruction.rs index 34ba5ed2fa..0518db065a 100644 --- a/sdk/src/system_instruction.rs +++ b/sdk/src/system_instruction.rs @@ -1,6 +1,6 @@ use crate::pubkey::Pubkey; use crate::system_program; -use crate::transaction::Instruction; +use crate::transaction::{AccountMeta, Instruction}; #[derive(Serialize, Debug, Clone, PartialEq)] pub enum SystemError { @@ -46,7 +46,7 @@ impl SystemInstruction { space, program_id: *program_id, }, - vec![(*from_id, true), (*to_id, false)], + vec![AccountMeta(*from_id, true), AccountMeta(*to_id, false)], ) } @@ -54,7 +54,7 @@ impl SystemInstruction { Instruction::new( system_program::id(), &SystemInstruction::Move { lamports }, - vec![(*from_id, true), (*to_id, false)], + vec![AccountMeta(*from_id, true), AccountMeta(*to_id, false)], ) } } diff --git a/sdk/src/transaction.rs b/sdk/src/transaction.rs index 84cc1a3e36..09000007dd 100644 --- a/sdk/src/transaction.rs +++ b/sdk/src/transaction.rs @@ -100,7 +100,11 @@ impl GenericInstruction { } } -pub type Instruction = GenericInstruction; +/// An account's pubkey and a Boolean that is true if an Instruciton +/// requires a Transaction signature corresponding to this key. +pub struct AccountMeta(pub Pubkey, pub bool); + +pub type Instruction = GenericInstruction; pub type CompiledInstruction = GenericInstruction; impl CompiledInstruction { @@ -209,9 +213,9 @@ impl Transaction { recent_blockhash: Hash, fee: u64, ) -> Self { - let mut account_keys = vec![(*from_pubkey, true)]; + let mut account_keys = vec![AccountMeta(*from_pubkey, true)]; for pubkey in transaction_keys { - account_keys.push((*pubkey, false)); + account_keys.push(AccountMeta(*pubkey, false)); } let instruction = Instruction::new(*program_id, data, account_keys); let mut transaction = Self::new(vec![instruction]); @@ -705,8 +709,8 @@ mod tests { let program_id = Pubkey::default(); let keypair0 = Keypair::new(); let id0 = keypair0.pubkey(); - Transaction::new(vec![Instruction::new(program_id, &0, vec![(id0, true)])]) - .sign(&Vec::<&Keypair>::new(), Hash::default()); + let ix = Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]); + Transaction::new(vec![ix]).sign(&Vec::<&Keypair>::new(), Hash::default()); } #[test] @@ -715,12 +719,8 @@ mod tests { let program_id = Pubkey::default(); let keypair0 = Keypair::new(); let wrong_id = Pubkey::default(); - Transaction::new(vec![Instruction::new( - program_id, - &0, - vec![(wrong_id, true)], - )]) - .sign(&[&keypair0], Hash::default()); + let ix = Instruction::new(program_id, &0, vec![AccountMeta(wrong_id, true)]); + Transaction::new(vec![ix]).sign(&[&keypair0], Hash::default()); } #[test] @@ -728,7 +728,8 @@ mod tests { let program_id = Pubkey::default(); let keypair0 = Keypair::new(); let id0 = keypair0.pubkey(); - let mut tx = Transaction::new(vec![Instruction::new(program_id, &0, vec![(id0, true)])]); + let ix = Instruction::new(program_id, &0, vec![AccountMeta(id0, true)]); + let mut tx = Transaction::new(vec![ix]); tx.sign(&[&keypair0], Hash::default()); assert_eq!(tx.instructions[0], CompiledInstruction::new(0, &0, vec![0])); }