diff --git a/src/bank.rs b/src/bank.rs index 41906a0242..197676114d 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -412,7 +412,7 @@ impl Bank { } pub fn verify_transaction( - program_index: usize, + instruction_index: usize, tx_program_id: &Pubkey, pre_program_id: &Pubkey, pre_tokens: i64, @@ -425,14 +425,16 @@ impl Bank { && SystemProgram::check_id(&pre_program_id))) { //TODO, this maybe redundant bpf should be able to guarantee this property - return Err(BankError::ModifiedContractId(program_index as u8)); + return Err(BankError::ModifiedContractId(instruction_index as u8)); } // For accounts unassigned to the contract, the individual balance of each accounts cannot decrease. if *tx_program_id != account.program_id && pre_tokens > account.tokens { - return Err(BankError::ExternalAccountTokenSpend(program_index as u8)); + return Err(BankError::ExternalAccountTokenSpend( + instruction_index as u8, + )); } if account.tokens < 0 { - return Err(BankError::ResultWithNegativeTokens(program_index as u8)); + return Err(BankError::ResultWithNegativeTokens(instruction_index as u8)); } Ok(()) } @@ -484,10 +486,10 @@ impl Bank { fn execute_instruction( &self, tx: &Transaction, - program_index: usize, + instruction_index: usize, program_accounts: &mut [&mut Account], ) -> Result<()> { - let tx_program_id = tx.program_id(program_index); + let tx_program_id = tx.program_id(instruction_index); // TODO: the runtime should be checking read/write access to memory // we are trusting the hard coded contracts not to clobber or allocate let pre_total: i64 = program_accounts.iter().map(|a| a.tokens).sum(); @@ -501,39 +503,45 @@ impl Bank { if SystemProgram::check_id(&tx_program_id) { SystemProgram::process_transaction( &tx, - program_index, + instruction_index, program_accounts, &self.loaded_contracts, ) } else if BudgetState::check_id(&tx_program_id) { - if BudgetState::process_transaction(&tx, program_index, program_accounts).is_err() { - return Err(BankError::ProgramRuntimeError(program_index as u8)); + if BudgetState::process_transaction(&tx, instruction_index, program_accounts).is_err() { + return Err(BankError::ProgramRuntimeError(instruction_index as u8)); } } else if StorageProgram::check_id(&tx_program_id) { - if StorageProgram::process_transaction(&tx, program_index, program_accounts).is_err() { - return Err(BankError::ProgramRuntimeError(program_index as u8)); - } - } else if TicTacToeProgram::check_id(&tx_program_id) { - if TicTacToeProgram::process_transaction(&tx, program_index, program_accounts).is_err() - { - return Err(BankError::ProgramRuntimeError(program_index as u8)); - } - } else if TicTacToeDashboardProgram::check_id(&tx_program_id) { - if TicTacToeDashboardProgram::process_transaction(&tx, program_index, program_accounts) + if StorageProgram::process_transaction(&tx, instruction_index, program_accounts) .is_err() { - return Err(BankError::ProgramRuntimeError(program_index as u8)); + return Err(BankError::ProgramRuntimeError(instruction_index as u8)); } - } else if self.loaded_contract(tx_program_id, tx, program_index, program_accounts) { + } else if TicTacToeProgram::check_id(&tx_program_id) { + if TicTacToeProgram::process_transaction(&tx, instruction_index, program_accounts) + .is_err() + { + return Err(BankError::ProgramRuntimeError(instruction_index as u8)); + } + } else if TicTacToeDashboardProgram::check_id(&tx_program_id) { + if TicTacToeDashboardProgram::process_transaction( + &tx, + instruction_index, + program_accounts, + ).is_err() + { + return Err(BankError::ProgramRuntimeError(instruction_index as u8)); + } + } else if self.loaded_contract(tx_program_id, tx, instruction_index, program_accounts) { } else { - return Err(BankError::UnknownContractId(program_index as u8)); + return Err(BankError::UnknownContractId(instruction_index as u8)); } // Verify the transaction for ((pre_program_id, pre_tokens), post_account) in pre_data.iter().zip(program_accounts.iter()) { Self::verify_transaction( - program_index, + instruction_index, &tx_program_id, pre_program_id, *pre_tokens, @@ -543,7 +551,7 @@ impl Bank { // The total sum of all the tokens in all the pages cannot change. let post_total: i64 = program_accounts.iter().map(|a| a.tokens).sum(); if pre_total != post_total { - Err(BankError::UnbalancedTransaction(program_index as u8)) + Err(BankError::UnbalancedTransaction(instruction_index as u8)) } else { Ok(()) } @@ -552,9 +560,9 @@ impl Bank { /// This method calls each instruction in the transaction over the set of loaded Accounts /// The accounts are committed back to the bank only if every instruction succeeds fn execute_transaction(&self, tx: &Transaction, tx_accounts: &mut [Account]) -> Result<()> { - for (program_index, prog) in tx.instructions.iter().enumerate() { + for (instruction_index, prog) in tx.instructions.iter().enumerate() { Self::with_subset(tx_accounts, &prog.accounts, |program_accounts| { - self.execute_instruction(tx, program_index, program_accounts) + self.execute_instruction(tx, instruction_index, program_accounts) })?; } Ok(()) @@ -1005,12 +1013,12 @@ mod tests { let spend = SystemProgram::Move { tokens: 1 }; let instructions = vec![ Instruction { - program_id: 0, + program_ids_index: 0, userdata: serialize(&spend).unwrap(), accounts: vec![0, 1], }, Instruction { - program_id: 0, + program_ids_index: 0, userdata: serialize(&spend).unwrap(), accounts: vec![0, 2], }, @@ -1045,12 +1053,12 @@ mod tests { let spend = SystemProgram::Move { tokens: 1 }; let instructions = vec![ Instruction { - program_id: 0, + program_ids_index: 0, userdata: serialize(&spend).unwrap(), accounts: vec![0, 1], }, Instruction { - program_id: 0, + program_ids_index: 0, userdata: serialize(&spend).unwrap(), accounts: vec![0, 2], }, diff --git a/src/budget_program.rs b/src/budget_program.rs index bbb92f7abf..92038ffe6e 100644 --- a/src/budget_program.rs +++ b/src/budget_program.rs @@ -48,18 +48,18 @@ impl BudgetState { fn apply_signature( &mut self, tx: &Transaction, - program_index: usize, + instruction_index: usize, account: &mut [&mut Account], ) -> Result<(), BudgetError> { let mut final_payment = None; if let Some(ref mut budget) = self.pending_budget { - let key = tx.key(program_index, 0).unwrap(); + let key = tx.key(instruction_index, 0).unwrap(); budget.apply_witness(&Witness::Signature, key); final_payment = budget.final_payment(); } if let Some(payment) = final_payment { - if Some(&payment.to) != tx.key(program_index, 2) { + if Some(&payment.to) != tx.key(instruction_index, 2) { trace!("destination missing"); return Err(BudgetError::DestinationMissing); } @@ -75,7 +75,7 @@ impl BudgetState { fn apply_timestamp( &mut self, tx: &Transaction, - program_index: usize, + instruction_index: usize, accounts: &mut [&mut Account], dt: DateTime, ) -> Result<(), BudgetError> { @@ -83,13 +83,13 @@ impl BudgetState { let mut final_payment = None; if let Some(ref mut budget) = self.pending_budget { - let key = tx.key(program_index, 0).unwrap(); + let key = tx.key(instruction_index, 0).unwrap(); budget.apply_witness(&Witness::Timestamp(dt), key); final_payment = budget.final_payment(); } if let Some(payment) = final_payment { - if Some(&payment.to) != tx.key(program_index, 2) { + if Some(&payment.to) != tx.key(instruction_index, 2) { trace!("destination missing"); return Err(BudgetError::DestinationMissing); } @@ -133,7 +133,7 @@ impl BudgetState { /// Note: It is safe to apply credits from multiple transactions in parallel. fn apply_credits_to_budget_state( tx: &Transaction, - program_index: usize, + instruction_index: usize, accounts: &mut [&mut Account], instruction: &Instruction, ) -> Result<(), BudgetError> { @@ -166,7 +166,7 @@ impl BudgetState { Err(BudgetError::UninitializedContract) } else { trace!("apply timestamp"); - state.apply_timestamp(tx, program_index, accounts, *dt)?; + state.apply_timestamp(tx, instruction_index, accounts, *dt)?; trace!("apply timestamp committed"); state.serialize(&mut accounts[1].userdata) } @@ -183,7 +183,7 @@ impl BudgetState { Err(BudgetError::UninitializedContract) } else { trace!("apply signature"); - state.apply_signature(tx, program_index, accounts)?; + state.apply_signature(tx, instruction_index, accounts)?; trace!("apply signature committed"); state.serialize(&mut accounts[1].userdata) } @@ -241,18 +241,18 @@ impl BudgetState { /// be spent from this account . pub fn process_transaction( tx: &Transaction, - program_index: usize, + instruction_index: usize, accounts: &mut [&mut Account], ) -> Result<(), BudgetError> { - if let Ok(instruction) = deserialize(tx.userdata(program_index)) { + if let Ok(instruction) = deserialize(tx.userdata(instruction_index)) { trace!("process_transaction: {:?}", instruction); Self::apply_debits_to_budget_state(accounts, &instruction).and_then(|_| { - Self::apply_credits_to_budget_state(tx, program_index, accounts, &instruction) + Self::apply_credits_to_budget_state(tx, instruction_index, accounts, &instruction) }) } else { info!( "Invalid transaction userdata: {:?}", - tx.userdata(program_index) + tx.userdata(instruction_index) ); Err(BudgetError::UserdataDeserializeFailure) } diff --git a/src/budget_transaction.rs b/src/budget_transaction.rs index e3c9df7dd5..ca5de244cb 100644 --- a/src/budget_transaction.rs +++ b/src/budget_transaction.rs @@ -278,7 +278,7 @@ mod tests { let instruction = Instruction::NewContract(Contract { budget, tokens: 0 }); let userdata = serialize(&instruction).unwrap(); let instructions = vec![transaction::Instruction { - program_id: 0, + program_ids_index: 0, userdata, accounts: vec![], }]; @@ -286,7 +286,7 @@ mod tests { account_keys: vec![], last_id: Default::default(), signature: Default::default(), - program_keys: vec![], + program_ids: vec![], instructions, fee: 0, }; diff --git a/src/transaction.rs b/src/transaction.rs index cf43ed3229..08a45af8ca 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -10,13 +10,13 @@ pub const SIGNED_DATA_OFFSET: usize = size_of::(); pub const SIG_OFFSET: usize = 0; pub const PUB_KEY_OFFSET: usize = size_of::() + size_of::(); -/// An instruction to execute a program under `program_id` with the +/// An instruction to execute a program under the `program_id` of `program_ids_index` with the /// specified accounts and userdata #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Instruction { /// The program code that executes this transaction is identified by the program_id. - /// this is an offset into the Transaction::program_keys field - pub program_id: u8, + /// this is an offset into the Transaction::program_ids field + pub program_ids_index: u8, /// Indices into the keys array of which accounts to load pub accounts: Vec, /// Userdata to be stored in the account @@ -26,7 +26,7 @@ pub struct Instruction { /// An atomic transaction #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct Transaction { - /// A digital signature of `keys`, `program_id`, `last_id`, `fee` and `userdata`, signed by `Pubkey`. + /// A digital signature of `account_keys`, `program_ids`, `last_id`, `fee` and `instructions`, signed by `Pubkey`. pub signature: Signature, /// The `Pubkeys` that are executing this transaction userdata. The meaning of each key is @@ -42,8 +42,8 @@ pub struct Transaction { /// The number of tokens paid for processing and storage of this transaction. pub fee: i64, - /// Keys indentifying programs in the instructions vector. - pub program_keys: Vec, + /// Keys identifying programs in the instructions vector. + pub program_ids: Vec, /// Programs that will be executed in sequence and commited in one atomic transaction if all /// succeed. pub instructions: Vec, @@ -58,9 +58,9 @@ impl Transaction { last_id: Hash, fee: i64, ) -> Self { - let program_keys = vec![program_id]; + let program_ids = vec![program_id]; let instructions = vec![Instruction { - program_id: 0, + program_ids_index: 0, userdata, accounts: (0..(transaction_keys.len() as u8 + 1)) .into_iter() @@ -71,7 +71,7 @@ impl Transaction { transaction_keys, last_id, fee, - program_keys, + program_ids, instructions, ) } @@ -81,14 +81,14 @@ impl Transaction { /// instances or token recipient keys. /// * `last_id` - The PoH hash. /// * `fee` - The transaction fee. - /// * `program_keys` - The keys that identify programs used in the `instruction` vector. + /// * `program_ids` - The keys that identify programs used in the `instruction` vector. /// * `instructions` - The programs and their arguments that the transaction will execute atomically pub fn new_with_instructions( from_keypair: &Keypair, keys: &[Pubkey], last_id: Hash, fee: i64, - program_keys: Vec, + program_ids: Vec, instructions: Vec, ) -> Self { let from = from_keypair.pubkey(); @@ -99,23 +99,24 @@ impl Transaction { account_keys, last_id, fee, - program_keys, + program_ids, instructions, }; tx.sign(from_keypair); tx } - pub fn userdata(&self, program_index: usize) -> &[u8] { - &self.instructions[program_index].userdata + pub fn userdata(&self, instruction_index: usize) -> &[u8] { + &self.instructions[instruction_index].userdata } - pub fn key(&self, program_index: usize, kix: usize) -> Option<&Pubkey> { + pub fn key(&self, instruction_index: usize, accounts_index: usize) -> Option<&Pubkey> { self.instructions - .get(program_index) - .and_then(|p| p.accounts.get(kix)) + .get(instruction_index) + .and_then(|instruction| instruction.accounts.get(accounts_index)) .and_then(|ai| self.account_keys.get(*ai as usize)) } - pub fn program_id(&self, program_index: usize) -> &Pubkey { - &self.program_keys[self.instructions[program_index].program_id as usize] + pub fn program_id(&self, instruction_index: usize) -> &Pubkey { + let program_ids_index = self.instructions[instruction_index].program_ids_index; + &self.program_ids[program_ids_index as usize] } /// Get the transaction data to sign. pub fn get_sign_data(&self) -> Vec { @@ -124,11 +125,11 @@ impl Transaction { let last_id_data = serialize(&self.last_id).expect("serialize last_id"); data.extend_from_slice(&last_id_data); - let fee_data = serialize(&self.fee).expect("serialize last_id"); + let fee_data = serialize(&self.fee).expect("serialize fee"); data.extend_from_slice(&fee_data); - let program_keys = serialize(&self.program_keys).expect("serialize program_keys"); - data.extend_from_slice(&program_keys); + let program_ids = serialize(&self.program_ids).expect("serialize program_ids"); + data.extend_from_slice(&program_ids); let instructions = serialize(&self.instructions).expect("serialize instructions"); data.extend_from_slice(&instructions); @@ -151,7 +152,7 @@ impl Transaction { /// Verify that references in the instructions are valid pub fn verify_refs(&self) -> bool { for instruction in &self.instructions { - if (instruction.program_id as usize) >= self.program_keys.len() { + if (instruction.program_ids_index as usize) >= self.program_ids.len() { return false; } for account_index in &instruction.accounts { @@ -192,12 +193,12 @@ mod tests { let prog2 = Keypair::new().pubkey(); let instructions = vec![ Instruction { - program_id: 0, + program_ids_index: 0, userdata: vec![], accounts: vec![0, 1], }, Instruction { - program_id: 1, + program_ids_index: 1, userdata: vec![], accounts: vec![0, 2], }, @@ -224,7 +225,7 @@ mod tests { fn test_refs_invalid_program_id() { let key = Keypair::new(); let instructions = vec![Instruction { - program_id: 1, + program_ids_index: 1, userdata: vec![], accounts: vec![], }]; @@ -242,7 +243,7 @@ mod tests { fn test_refs_invalid_account() { let key = Keypair::new(); let instructions = vec![Instruction { - program_id: 0, + program_ids_index: 0, userdata: vec![], accounts: vec![1], }];