Extract execute_transaction() from the bank
This commit is contained in:
parent
08dc169f94
commit
a7562c9be1
51
src/bank.rs
51
src/bank.rs
|
@ -22,7 +22,7 @@ use poh_service::NUM_TICKS_PER_SECOND;
|
||||||
use program::ProgramError;
|
use program::ProgramError;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use rpc::RpcSignatureStatus;
|
use rpc::RpcSignatureStatus;
|
||||||
use runtime;
|
use runtime::{self, RuntimeError};
|
||||||
use signature::Keypair;
|
use signature::Keypair;
|
||||||
use signature::Signature;
|
use signature::Signature;
|
||||||
use solana_sdk::account::Account;
|
use solana_sdk::account::Account;
|
||||||
|
@ -707,24 +707,6 @@ impl Bank {
|
||||||
}).collect()
|
}).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: 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_executable_accounts(&self, mut program_id: Pubkey) -> Result<Vec<(Pubkey, Account)>> {
|
fn load_executable_accounts(&self, mut program_id: Pubkey) -> Result<Vec<(Pubkey, Account)>> {
|
||||||
if runtime::is_legacy_program(&program_id) {
|
if runtime::is_legacy_program(&program_id) {
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
|
@ -769,31 +751,6 @@ impl Bank {
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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(
|
|
||||||
tx: &Transaction,
|
|
||||||
loaders: &mut [Vec<(Pubkey, Account)>],
|
|
||||||
tx_accounts: &mut [Account],
|
|
||||||
tick_height: u64,
|
|
||||||
) -> Result<()> {
|
|
||||||
for (instruction_index, instruction) in tx.instructions.iter().enumerate() {
|
|
||||||
let ref mut executable_accounts = &mut loaders[instruction.program_ids_index as usize];
|
|
||||||
Self::with_subset(tx_accounts, &instruction.accounts, |program_accounts| {
|
|
||||||
runtime::execute_instruction(
|
|
||||||
tx,
|
|
||||||
instruction_index,
|
|
||||||
executable_accounts,
|
|
||||||
program_accounts,
|
|
||||||
tick_height,
|
|
||||||
).map_err(|err| BankError::ProgramError(instruction_index as u8, err))?;
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn store_accounts(
|
pub fn store_accounts(
|
||||||
&self,
|
&self,
|
||||||
txs: &[Transaction],
|
txs: &[Transaction],
|
||||||
|
@ -903,7 +860,11 @@ impl Bank {
|
||||||
Err(e) => Err(e.clone()),
|
Err(e) => Err(e.clone()),
|
||||||
Ok(ref mut accounts) => {
|
Ok(ref mut accounts) => {
|
||||||
let mut loaders = self.load_loaders(tx)?;
|
let mut loaders = self.load_loaders(tx)?;
|
||||||
Self::execute_transaction(tx, &mut loaders, accounts, tick_height)
|
runtime::execute_transaction(tx, &mut loaders, accounts, tick_height).map_err(
|
||||||
|
|RuntimeError::ProgramError(index, err)| {
|
||||||
|
BankError::ProgramError(index, err)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
let execution_elapsed = now.elapsed();
|
let execution_elapsed = now.elapsed();
|
||||||
|
|
|
@ -139,7 +139,7 @@ pub fn process(
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
accounts: &mut [&mut Account],
|
accounts: &mut [&mut Account],
|
||||||
) -> std::result::Result<(), ProgramError> {
|
) -> 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
|
//TODO the contract needs to provide a "get_balance" introspection call of the userdata
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub enum ProgramError {
|
||||||
ResultWithNegativeTokens,
|
ResultWithNegativeTokens,
|
||||||
|
|
||||||
/// The program returned an error
|
/// The program returned an error
|
||||||
RuntimeError,
|
GenericError,
|
||||||
|
|
||||||
/// Program's instruction token balance does not equal the balance after the instruction
|
/// Program's instruction token balance does not equal the balance after the instruction
|
||||||
UnbalancedInstruction,
|
UnbalancedInstruction,
|
||||||
|
|
|
@ -8,6 +8,13 @@ use system_program;
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
use vote_program;
|
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 {
|
pub fn is_legacy_program(program_id: &Pubkey) -> bool {
|
||||||
system_program::check_id(program_id)
|
system_program::check_id(program_id)
|
||||||
|| budget_program::check_id(program_id)
|
|| budget_program::check_id(program_id)
|
||||||
|
@ -57,7 +64,7 @@ fn process_instruction(
|
||||||
&tx.instructions[instruction_index].userdata,
|
&tx.instructions[instruction_index].userdata,
|
||||||
tick_height,
|
tick_height,
|
||||||
) {
|
) {
|
||||||
return Err(ProgramError::RuntimeError);
|
return Err(ProgramError::GenericError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -86,7 +93,7 @@ fn verify_instruction(
|
||||||
/// This method calls the instruction's program entrypoint method and verifies that the result of
|
/// 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 call does not violate the bank's accounting rules.
|
||||||
/// The accounts are committed back to the bank only if this function returns Ok(_).
|
/// The accounts are committed back to the bank only if this function returns Ok(_).
|
||||||
pub fn execute_instruction(
|
fn execute_instruction(
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
executable_accounts: &mut [(Pubkey, Account)],
|
executable_accounts: &mut [(Pubkey, Account)],
|
||||||
|
@ -122,3 +129,46 @@ pub fn execute_instruction(
|
||||||
}
|
}
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub fn process(
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
accounts: &mut [&mut Account],
|
accounts: &mut [&mut Account],
|
||||||
) -> std::result::Result<(), ProgramError> {
|
) -> 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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -107,7 +107,7 @@ pub fn process(
|
||||||
) -> std::result::Result<(), ProgramError> {
|
) -> std::result::Result<(), ProgramError> {
|
||||||
process_instruction(&tx, instruction_index, accounts).map_err(|err| match err {
|
process_instruction(&tx, instruction_index, accounts).map_err(|err| match err {
|
||||||
Error::ResultWithNegativeTokens => ProgramError::ResultWithNegativeTokens,
|
Error::ResultWithNegativeTokens => ProgramError::ResultWithNegativeTokens,
|
||||||
_ => ProgramError::RuntimeError,
|
_ => ProgramError::GenericError,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ pub fn process(
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
accounts: &mut [&mut Account],
|
accounts: &mut [&mut Account],
|
||||||
) -> std::result::Result<(), ProgramError> {
|
) -> 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 {
|
pub fn get_max_size() -> usize {
|
||||||
|
|
Loading…
Reference in New Issue