Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Extract execute_transaction() from the bank #1925

Merged
merged 4 commits into from
Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 17 additions & 44 deletions src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use poh_service::NUM_TICKS_PER_SECOND;
use program::ProgramError;
use rayon::prelude::*;
use rpc::RpcSignatureStatus;
use runtime;
use runtime::{self, RuntimeError};
use signature::Keypair;
use signature::Signature;
use solana_sdk::account::Account;
Expand Down Expand Up @@ -707,24 +707,6 @@ impl Bank {
}).collect()
}

/// Execute a function with a subset of accounts as writable references.
/// Since the subset can point to the same references, in any order there is no way
/// for the borrow checker to track them with regards to the original set.
fn with_subset<F, A>(accounts: &mut [Account], ixes: &[u8], func: F) -> A
where
F: Fn(&mut [&mut Account]) -> A,
{
let mut subset: Vec<&mut Account> = ixes
.iter()
.map(|ix| {
let ptr = &mut accounts[*ix as usize] as *mut Account;
// lifetime of this unsafe is only within the scope of the closure
// there is no way to reorder them without breaking borrow checker rules
unsafe { &mut *ptr }
}).collect();
func(&mut subset)
}

fn load_executable_accounts(&self, mut program_id: Pubkey) -> Result<Vec<(Pubkey, Account)>> {
if runtime::is_legacy_program(&program_id) {
return Ok(vec![]);
Expand Down Expand Up @@ -759,30 +741,14 @@ impl Bank {
Ok(accounts)
}

/// Execute a transaction.
/// 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],
tick_height: u64,
) -> Result<()> {
for (instruction_index, instruction) in tx.instructions.iter().enumerate() {
let program_id = tx.program_id(instruction_index);
Self::with_subset(tx_accounts, &instruction.accounts, |program_accounts| {
let mut executable_accounts = self.load_executable_accounts(*program_id)?;
runtime::execute_instruction(
tx,
instruction_index,
&mut executable_accounts,
program_accounts,
tick_height,
).map_err(|err| BankError::ProgramError(instruction_index as u8, err))?;
Ok(())
})?;
}
Ok(())
/// For each program_id in the transaction, load its loaders.
fn load_loaders(&self, tx: &Transaction) -> Result<Vec<Vec<(Pubkey, Account)>>> {
tx.instructions
.iter()
.map(|ix| {
let program_id = tx.program_ids[ix.program_ids_index as usize];
self.load_executable_accounts(program_id)
garious marked this conversation as resolved.
Show resolved Hide resolved
}).collect()
}

pub fn store_accounts(
Expand Down Expand Up @@ -892,7 +858,14 @@ impl Bank {
.zip(txs.iter())
.map(|(acc, tx)| match acc {
Err(e) => Err(e.clone()),
Ok(ref mut accounts) => self.execute_transaction(tx, accounts, tick_height),
Ok(ref mut accounts) => {
let mut loaders = self.load_loaders(tx)?;
runtime::execute_transaction(tx, &mut loaders, accounts, tick_height).map_err(
|RuntimeError::ProgramError(index, err)| {
BankError::ProgramError(index, err)
},
)
}
}).collect();
let execution_elapsed = now.elapsed();
let now = Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion src/budget_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ pub fn process(
instruction_index: usize,
accounts: &mut [&mut Account],
) -> std::result::Result<(), ProgramError> {
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::RuntimeError)
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::GenericError)
}

//TODO the contract needs to provide a "get_balance" introspection call of the userdata
Expand Down
2 changes: 1 addition & 1 deletion src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub enum ProgramError {
ResultWithNegativeTokens,

/// The program returned an error
RuntimeError,
GenericError,

/// Program's instruction token balance does not equal the balance after the instruction
UnbalancedInstruction,
Expand Down
54 changes: 52 additions & 2 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ use system_program;
use transaction::Transaction;
use vote_program;

/// Reasons the runtime might have rejected a transaction.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum RuntimeError {
/// Executing the instruction at the given index produced an error.
ProgramError(u8, ProgramError),
}

pub fn is_legacy_program(program_id: &Pubkey) -> bool {
system_program::check_id(program_id)
|| budget_program::check_id(program_id)
Expand Down Expand Up @@ -57,7 +64,7 @@ fn process_instruction(
&tx.instructions[instruction_index].userdata,
tick_height,
) {
return Err(ProgramError::RuntimeError);
return Err(ProgramError::GenericError);
}
}
Ok(())
Expand Down Expand Up @@ -86,7 +93,7 @@ fn verify_instruction(
/// This method calls the instruction's program entrypoint method and verifies that the result of
/// the call does not violate the bank's accounting rules.
/// The accounts are committed back to the bank only if this function returns Ok(_).
pub fn execute_instruction(
fn execute_instruction(
tx: &Transaction,
instruction_index: usize,
executable_accounts: &mut [(Pubkey, Account)],
Expand Down Expand Up @@ -122,3 +129,46 @@ pub fn execute_instruction(
}
Ok(())
}

/// Execute a function with a subset of accounts as writable references.
/// Since the subset can point to the same references, in any order there is no way
/// for the borrow checker to track them with regards to the original set.
fn with_subset<F, A>(accounts: &mut [Account], ixes: &[u8], func: F) -> A
where
F: FnOnce(&mut [&mut Account]) -> A,
{
let mut subset: Vec<&mut Account> = ixes
.iter()
.map(|ix| {
let ptr = &mut accounts[*ix as usize] as *mut Account;
// lifetime of this unsafe is only within the scope of the closure
// there is no way to reorder them without breaking borrow checker rules
unsafe { &mut *ptr }
}).collect();
func(&mut subset)
}

/// Execute a transaction.
/// 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
pub fn execute_transaction(
tx: &Transaction,
loaders: &mut [Vec<(Pubkey, Account)>],
tx_accounts: &mut [Account],
tick_height: u64,
) -> Result<(), RuntimeError> {
for (instruction_index, instruction) in tx.instructions.iter().enumerate() {
let executable_accounts = &mut (&mut loaders[instruction.program_ids_index as usize]);
with_subset(tx_accounts, &instruction.accounts, |program_accounts| {
execute_instruction(
tx,
instruction_index,
executable_accounts,
program_accounts,
tick_height,
).map_err(|err| RuntimeError::ProgramError(instruction_index as u8, err))?;
Ok(())
})?;
}
Ok(())
}
2 changes: 1 addition & 1 deletion src/storage_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub fn process(
instruction_index: usize,
accounts: &mut [&mut Account],
) -> std::result::Result<(), ProgramError> {
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::RuntimeError)
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::GenericError)
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/system_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub fn process(
) -> std::result::Result<(), ProgramError> {
process_instruction(&tx, instruction_index, accounts).map_err(|err| match err {
Error::ResultWithNegativeTokens => ProgramError::ResultWithNegativeTokens,
_ => ProgramError::RuntimeError,
_ => ProgramError::GenericError,
})
}

Expand Down
2 changes: 1 addition & 1 deletion src/vote_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub fn process(
instruction_index: usize,
accounts: &mut [&mut Account],
) -> std::result::Result<(), ProgramError> {
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::RuntimeError)
process_instruction(&tx, instruction_index, accounts).map_err(|_| ProgramError::GenericError)
}

pub fn get_max_size() -> usize {
Expand Down