Store versioned transactions in the ledger, disabled by default (#19139)
* Add support for versioned transactions, but disable by default * merge conflicts * trent's feedback * bump Cargo.lock * Fix transaction error encoding * Rename legacy_transaction method * cargo clippy * Clean up casts, int arithmetic, and unused methods * Check for duplicates in sanitized message conversion * fix clippy * fix new test * Fix bpf conditional compilation for message module
This commit is contained in:
@ -31,12 +31,11 @@ use solana_sdk::{
|
||||
fee_calculator::FeeCalculator,
|
||||
genesis_config::ClusterType,
|
||||
hash::Hash,
|
||||
message::Message,
|
||||
message::SanitizedMessage,
|
||||
native_loader, nonce,
|
||||
nonce::NONCED_TX_MARKER_IX_INDEX,
|
||||
pubkey::Pubkey,
|
||||
transaction::Result,
|
||||
transaction::{Transaction, TransactionError},
|
||||
transaction::{Result, SanitizedTransaction, TransactionError},
|
||||
};
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
@ -198,7 +197,7 @@ impl Accounts {
|
||||
}
|
||||
}
|
||||
|
||||
fn construct_instructions_account(message: &Message) -> AccountSharedData {
|
||||
fn construct_instructions_account(message: &SanitizedMessage) -> AccountSharedData {
|
||||
let mut data = message.serialize_instructions();
|
||||
// add room for current instruction index.
|
||||
data.resize(data.len() + 2, 0);
|
||||
@ -211,7 +210,7 @@ impl Accounts {
|
||||
fn load_transaction(
|
||||
&self,
|
||||
ancestors: &Ancestors,
|
||||
tx: &Transaction,
|
||||
tx: &SanitizedTransaction,
|
||||
fee: u64,
|
||||
error_counters: &mut ErrorCounters,
|
||||
rent_collector: &RentCollector,
|
||||
@ -219,19 +218,20 @@ impl Accounts {
|
||||
) -> Result<LoadedTransaction> {
|
||||
// Copy all the accounts
|
||||
let message = tx.message();
|
||||
if tx.signatures.is_empty() && fee != 0 {
|
||||
// NOTE: this check will never fail because `tx` is sanitized
|
||||
if tx.signatures().is_empty() && fee != 0 {
|
||||
Err(TransactionError::MissingSignatureForFee)
|
||||
} else {
|
||||
// There is no way to predict what program will execute without an error
|
||||
// If a fee can pay for execution then the program will be scheduled
|
||||
let mut payer_index = None;
|
||||
let mut tx_rent: TransactionRent = 0;
|
||||
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
||||
let mut account_deps = Vec::with_capacity(message.account_keys.len());
|
||||
let mut accounts = Vec::with_capacity(message.account_keys_len());
|
||||
let mut account_deps = Vec::with_capacity(message.account_keys_len());
|
||||
let mut rent_debits = RentDebits::default();
|
||||
let rent_for_sysvars = feature_set.is_active(&feature_set::rent_for_sysvars::id());
|
||||
|
||||
for (i, key) in message.account_keys.iter().enumerate() {
|
||||
for (i, key) in message.account_keys_iter().enumerate() {
|
||||
let account = if message.is_non_loader_key(i) {
|
||||
if payer_index.is_none() {
|
||||
payer_index = Some(i);
|
||||
@ -296,7 +296,7 @@ impl Accounts {
|
||||
};
|
||||
accounts.push((*key, account));
|
||||
}
|
||||
debug_assert_eq!(accounts.len(), message.account_keys.len());
|
||||
debug_assert_eq!(accounts.len(), message.account_keys_len());
|
||||
// Appends the account_deps at the end of the accounts,
|
||||
// this way they can be accessed in a uniform way.
|
||||
// At places where only the accounts are needed,
|
||||
@ -336,19 +336,9 @@ impl Accounts {
|
||||
|
||||
let message = tx.message();
|
||||
let loaders = message
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|ix| {
|
||||
if message.account_keys.len() <= ix.program_id_index as usize {
|
||||
error_counters.account_not_found += 1;
|
||||
return Err(TransactionError::AccountNotFound);
|
||||
}
|
||||
let program_id = message.account_keys[ix.program_id_index as usize];
|
||||
self.load_executable_accounts(
|
||||
ancestors,
|
||||
&program_id,
|
||||
error_counters,
|
||||
)
|
||||
.program_instructions_iter()
|
||||
.map(|(program_id, _ix)| {
|
||||
self.load_executable_accounts(ancestors, program_id, error_counters)
|
||||
})
|
||||
.collect::<Result<TransactionLoaders>>()?;
|
||||
Ok(LoadedTransaction {
|
||||
@ -434,17 +424,18 @@ impl Accounts {
|
||||
Ok(accounts)
|
||||
}
|
||||
|
||||
pub fn load_accounts<'a>(
|
||||
pub fn load_accounts(
|
||||
&self,
|
||||
ancestors: &Ancestors,
|
||||
txs: impl Iterator<Item = &'a Transaction>,
|
||||
txs: &[SanitizedTransaction],
|
||||
lock_results: Vec<TransactionCheckResult>,
|
||||
hash_queue: &BlockhashQueue,
|
||||
error_counters: &mut ErrorCounters,
|
||||
rent_collector: &RentCollector,
|
||||
feature_set: &FeatureSet,
|
||||
) -> Vec<TransactionLoadResult> {
|
||||
txs.zip(lock_results)
|
||||
txs.iter()
|
||||
.zip(lock_results)
|
||||
.map(|etx| match etx {
|
||||
(tx, (Ok(()), nonce_rollback)) => {
|
||||
let fee_calculator = nonce_rollback
|
||||
@ -453,12 +444,11 @@ impl Accounts {
|
||||
.unwrap_or_else(|| {
|
||||
#[allow(deprecated)]
|
||||
hash_queue
|
||||
.get_fee_calculator(&tx.message().recent_blockhash)
|
||||
.get_fee_calculator(tx.message().recent_blockhash())
|
||||
.cloned()
|
||||
});
|
||||
let fee = if let Some(fee_calculator) = fee_calculator {
|
||||
#[allow(deprecated)]
|
||||
fee_calculator.calculate_fee(tx.message())
|
||||
tx.message().calculate_fee(&fee_calculator)
|
||||
} else {
|
||||
return (Err(TransactionError::BlockhashNotFound), None);
|
||||
};
|
||||
@ -879,15 +869,14 @@ impl Accounts {
|
||||
/// same time
|
||||
#[must_use]
|
||||
#[allow(clippy::needless_collect)]
|
||||
pub fn lock_accounts<'a>(&self, txs: impl Iterator<Item = &'a Transaction>) -> Vec<Result<()>> {
|
||||
let keys: Vec<_> = txs
|
||||
.map(|tx| tx.message().get_account_keys_by_lock_type())
|
||||
.collect();
|
||||
pub fn lock_accounts<'a>(
|
||||
&self,
|
||||
txs: impl Iterator<Item = &'a SanitizedTransaction>,
|
||||
) -> Vec<Result<()>> {
|
||||
let keys: Vec<_> = txs.map(|tx| tx.get_account_locks()).collect();
|
||||
let mut account_locks = &mut self.account_locks.lock().unwrap();
|
||||
keys.into_iter()
|
||||
.map(|(writable_keys, readonly_keys)| {
|
||||
self.lock_account(&mut account_locks, writable_keys, readonly_keys)
|
||||
})
|
||||
.map(|keys| self.lock_account(&mut account_locks, keys.writable, keys.readonly))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -895,7 +884,7 @@ impl Accounts {
|
||||
#[allow(clippy::needless_collect)]
|
||||
pub fn unlock_accounts<'a>(
|
||||
&self,
|
||||
txs: impl Iterator<Item = &'a Transaction>,
|
||||
txs: impl Iterator<Item = &'a SanitizedTransaction>,
|
||||
results: &[Result<()>],
|
||||
) {
|
||||
let keys: Vec<_> = txs
|
||||
@ -904,13 +893,13 @@ impl Accounts {
|
||||
Err(TransactionError::AccountInUse) => None,
|
||||
Err(TransactionError::SanitizeFailure) => None,
|
||||
Err(TransactionError::AccountLoadedTwice) => None,
|
||||
_ => Some(tx.message.get_account_keys_by_lock_type()),
|
||||
_ => Some(tx.get_account_locks()),
|
||||
})
|
||||
.collect();
|
||||
let mut account_locks = self.account_locks.lock().unwrap();
|
||||
debug!("bank unlock accounts");
|
||||
keys.into_iter().for_each(|(writable_keys, readonly_keys)| {
|
||||
self.unlock_account(&mut account_locks, writable_keys, readonly_keys);
|
||||
keys.into_iter().for_each(|keys| {
|
||||
self.unlock_account(&mut account_locks, keys.writable, keys.readonly);
|
||||
});
|
||||
}
|
||||
|
||||
@ -920,7 +909,7 @@ impl Accounts {
|
||||
pub fn store_cached<'a>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
txs: impl Iterator<Item = &'a Transaction>,
|
||||
txs: &'a [SanitizedTransaction],
|
||||
res: &'a [TransactionExecutionResult],
|
||||
loaded: &'a mut [TransactionLoadResult],
|
||||
rent_collector: &RentCollector,
|
||||
@ -954,7 +943,7 @@ impl Accounts {
|
||||
|
||||
fn collect_accounts_to_store<'a>(
|
||||
&self,
|
||||
txs: impl Iterator<Item = &'a Transaction>,
|
||||
txs: &'a [SanitizedTransaction],
|
||||
res: &'a [TransactionExecutionResult],
|
||||
loaded: &'a mut [TransactionLoadResult],
|
||||
rent_collector: &RentCollector,
|
||||
@ -991,10 +980,10 @@ impl Accounts {
|
||||
(Err(_), _nonce_rollback) => continue,
|
||||
};
|
||||
|
||||
let message = &tx.message();
|
||||
let message = tx.message();
|
||||
let loaded_transaction = raccs.as_mut().unwrap();
|
||||
let mut fee_payer_index = None;
|
||||
for (i, (key, account)) in (0..message.account_keys.len())
|
||||
for (i, (key, account)) in (0..message.account_keys_len())
|
||||
.zip(loaded_transaction.accounts.iter_mut())
|
||||
.filter(|(i, _account)| message.is_non_loader_key(*i))
|
||||
{
|
||||
@ -1131,14 +1120,25 @@ mod tests {
|
||||
message::Message,
|
||||
nonce, nonce_account,
|
||||
rent::Rent,
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
signature::{keypair_from_seed, signers::Signers, Keypair, Signer},
|
||||
system_instruction, system_program,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
sync::atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
{thread, time},
|
||||
};
|
||||
|
||||
fn new_sanitized_tx<T: Signers>(
|
||||
from_keypairs: &T,
|
||||
message: Message,
|
||||
recent_blockhash: Hash,
|
||||
) -> SanitizedTransaction {
|
||||
SanitizedTransaction::try_from(Transaction::new(from_keypairs, message, recent_blockhash))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn load_accounts_with_fee_and_rent(
|
||||
tx: Transaction,
|
||||
ka: &[(Pubkey, AccountSharedData)],
|
||||
@ -1160,9 +1160,10 @@ mod tests {
|
||||
}
|
||||
|
||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||
let sanitized_tx = SanitizedTransaction::try_from(tx).unwrap();
|
||||
accounts.load_accounts(
|
||||
&ancestors,
|
||||
[tx].iter(),
|
||||
&[sanitized_tx],
|
||||
vec![(Ok(()), None)],
|
||||
&hash_queue,
|
||||
error_counters,
|
||||
@ -1190,30 +1191,6 @@ mod tests {
|
||||
load_accounts_with_fee(tx, ka, &fee_calculator, error_counters)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_accounts_no_key() {
|
||||
let accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let instructions = vec![CompiledInstruction::new(0, &(), vec![0])];
|
||||
let tx = Transaction::new_with_compiled_instructions::<[&Keypair; 0]>(
|
||||
&[],
|
||||
&[],
|
||||
Hash::default(),
|
||||
vec![native_loader::id()],
|
||||
instructions,
|
||||
);
|
||||
|
||||
let loaded_accounts = load_accounts(tx, &accounts, &mut error_counters);
|
||||
|
||||
assert_eq!(error_counters.account_not_found, 1);
|
||||
assert_eq!(loaded_accounts.len(), 1);
|
||||
assert_eq!(
|
||||
loaded_accounts[0],
|
||||
(Err(TransactionError::AccountNotFound), None,)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_accounts_no_account_0_exists() {
|
||||
let accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
@ -1522,41 +1499,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_accounts_bad_program_id() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
let key0 = keypair.pubkey();
|
||||
let key1 = Pubkey::new(&[5u8; 32]);
|
||||
|
||||
let account = AccountSharedData::new(1, 0, &Pubkey::default());
|
||||
accounts.push((key0, account));
|
||||
|
||||
let mut account = AccountSharedData::new(40, 1, &native_loader::id());
|
||||
account.set_executable(true);
|
||||
accounts.push((key1, account));
|
||||
|
||||
let instructions = vec![CompiledInstruction::new(0, &(), vec![0])];
|
||||
let tx = Transaction::new_with_compiled_instructions(
|
||||
&[&keypair],
|
||||
&[],
|
||||
Hash::default(),
|
||||
vec![key1],
|
||||
instructions,
|
||||
);
|
||||
|
||||
let loaded_accounts = load_accounts(tx, &accounts, &mut error_counters);
|
||||
|
||||
assert_eq!(error_counters.invalid_program_for_execution, 1);
|
||||
assert_eq!(loaded_accounts.len(), 1);
|
||||
assert_eq!(
|
||||
loaded_accounts[0],
|
||||
(Err(TransactionError::InvalidProgramForExecution), None,)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_accounts_bad_owner() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
@ -1784,7 +1726,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let tx = Transaction::new(&[&keypair0], message, Hash::default());
|
||||
let tx = new_sanitized_tx(&[&keypair0], message, Hash::default());
|
||||
let results0 = accounts.lock_accounts([tx.clone()].iter());
|
||||
|
||||
assert!(results0[0].is_ok());
|
||||
@ -1808,7 +1750,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let tx0 = Transaction::new(&[&keypair2], message, Hash::default());
|
||||
let tx0 = new_sanitized_tx(&[&keypair2], message, Hash::default());
|
||||
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
|
||||
let message = Message::new_with_compiled_instructions(
|
||||
1,
|
||||
@ -1818,7 +1760,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let tx1 = Transaction::new(&[&keypair1], message, Hash::default());
|
||||
let tx1 = new_sanitized_tx(&[&keypair1], message, Hash::default());
|
||||
let txs = vec![tx0, tx1];
|
||||
let results1 = accounts.lock_accounts(txs.iter());
|
||||
|
||||
@ -1846,7 +1788,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let tx = Transaction::new(&[&keypair1], message, Hash::default());
|
||||
let tx = new_sanitized_tx(&[&keypair1], message, Hash::default());
|
||||
let results2 = accounts.lock_accounts([tx].iter());
|
||||
assert!(results2[0].is_ok()); // Now keypair1 account can be locked as writable
|
||||
|
||||
@ -1895,7 +1837,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let readonly_tx = Transaction::new(&[&keypair0], readonly_message, Hash::default());
|
||||
let readonly_tx = new_sanitized_tx(&[&keypair0], readonly_message, Hash::default());
|
||||
|
||||
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
|
||||
let writable_message = Message::new_with_compiled_instructions(
|
||||
@ -1906,7 +1848,7 @@ mod tests {
|
||||
Hash::default(),
|
||||
instructions,
|
||||
);
|
||||
let writable_tx = Transaction::new(&[&keypair1], writable_message, Hash::default());
|
||||
let writable_tx = new_sanitized_tx(&[&keypair1], writable_message, Hash::default());
|
||||
|
||||
let counter_clone = counter.clone();
|
||||
let accounts_clone = accounts_arc.clone();
|
||||
@ -1967,7 +1909,7 @@ mod tests {
|
||||
(message.account_keys[0], account0),
|
||||
(message.account_keys[1], account2.clone()),
|
||||
];
|
||||
let tx0 = Transaction::new(&[&keypair0], message, Hash::default());
|
||||
let tx0 = new_sanitized_tx(&[&keypair0], message, Hash::default());
|
||||
|
||||
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
|
||||
let message = Message::new_with_compiled_instructions(
|
||||
@ -1982,7 +1924,7 @@ mod tests {
|
||||
(message.account_keys[0], account1),
|
||||
(message.account_keys[1], account2),
|
||||
];
|
||||
let tx1 = Transaction::new(&[&keypair1], message, Hash::default());
|
||||
let tx1 = new_sanitized_tx(&[&keypair1], message, Hash::default());
|
||||
|
||||
let loaders = vec![(Ok(()), None), (Ok(()), None)];
|
||||
|
||||
@ -2026,9 +1968,9 @@ mod tests {
|
||||
.unwrap()
|
||||
.insert_new_readonly(&pubkey);
|
||||
}
|
||||
let txs = &[tx0, tx1];
|
||||
let txs = vec![tx0, tx1];
|
||||
let collected_accounts = accounts.collect_accounts_to_store(
|
||||
txs.iter(),
|
||||
&txs,
|
||||
&loaders,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
@ -2087,16 +2029,17 @@ mod tests {
|
||||
}
|
||||
|
||||
fn load_accounts_no_store(accounts: &Accounts, tx: Transaction) -> Vec<TransactionLoadResult> {
|
||||
let tx = SanitizedTransaction::try_from(tx).unwrap();
|
||||
let rent_collector = RentCollector::default();
|
||||
let fee_calculator = FeeCalculator::new(10);
|
||||
let mut hash_queue = BlockhashQueue::new(100);
|
||||
hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator);
|
||||
hash_queue.register_hash(tx.message().recent_blockhash(), &fee_calculator);
|
||||
|
||||
let ancestors = vec![(0, 0)].into_iter().collect();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
accounts.load_accounts(
|
||||
&ancestors,
|
||||
[tx].iter(),
|
||||
&[tx],
|
||||
vec![(Ok(()), None)],
|
||||
&hash_queue,
|
||||
&mut error_counters,
|
||||
@ -2357,7 +2300,7 @@ mod tests {
|
||||
(message.account_keys[3], to_account),
|
||||
(message.account_keys[4], recent_blockhashes_sysvar_account),
|
||||
];
|
||||
let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash);
|
||||
let tx = new_sanitized_tx(&[&nonce_authority, &from], message, blockhash);
|
||||
|
||||
let nonce_state =
|
||||
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
|
||||
@ -2404,9 +2347,9 @@ mod tests {
|
||||
false,
|
||||
AccountShrinkThreshold::default(),
|
||||
);
|
||||
let txs = &[tx];
|
||||
let txs = vec![tx];
|
||||
let collected_accounts = accounts.collect_accounts_to_store(
|
||||
txs.iter(),
|
||||
&txs,
|
||||
&loaders,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
@ -2475,7 +2418,7 @@ mod tests {
|
||||
(message.account_keys[3], to_account),
|
||||
(message.account_keys[4], recent_blockhashes_sysvar_account),
|
||||
];
|
||||
let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash);
|
||||
let tx = new_sanitized_tx(&[&nonce_authority, &from], message, blockhash);
|
||||
|
||||
let nonce_state =
|
||||
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
|
||||
@ -2521,9 +2464,9 @@ mod tests {
|
||||
false,
|
||||
AccountShrinkThreshold::default(),
|
||||
);
|
||||
let txs = &[tx];
|
||||
let txs = vec![tx];
|
||||
let collected_accounts = accounts.collect_accounts_to_store(
|
||||
txs.iter(),
|
||||
&txs,
|
||||
&loaders,
|
||||
loaded.as_mut_slice(),
|
||||
&rent_collector,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ use solana_sdk::{
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
hash::Hash,
|
||||
instruction::Instruction,
|
||||
message::Message,
|
||||
message::{Message, SanitizedMessage},
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signature, Signer},
|
||||
signers::Signers,
|
||||
@ -16,6 +16,7 @@ use solana_sdk::{
|
||||
transport::{Result, TransportError},
|
||||
};
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
io,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
@ -303,8 +304,9 @@ impl SyncClient for BankClient {
|
||||
}
|
||||
|
||||
fn get_fee_for_message(&self, blockhash: &Hash, message: &Message) -> Result<u64> {
|
||||
self.bank
|
||||
.get_fee_for_message(blockhash, message)
|
||||
SanitizedMessage::try_from(message.clone())
|
||||
.ok()
|
||||
.and_then(|message| self.bank.get_fee_for_message(blockhash, &message))
|
||||
.ok_or_else(|| {
|
||||
TransportError::IoError(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
genesis_utils::{self, GenesisConfigInfo, ValidatorVoteKeypairs},
|
||||
vote_sender_types::ReplayVoteSender,
|
||||
};
|
||||
use solana_sdk::{pubkey::Pubkey, sanitized_transaction::SanitizedTransaction, signature::Signer};
|
||||
use solana_sdk::{pubkey::Pubkey, signature::Signer, transaction::SanitizedTransaction};
|
||||
use solana_vote_program::vote_transaction;
|
||||
|
||||
pub fn setup_bank_and_vote_pubkeys_for_tests(
|
||||
@ -44,8 +44,8 @@ pub fn find_and_send_votes(
|
||||
assert!(execution_results[old_account.transaction_result_index]
|
||||
.0
|
||||
.is_ok());
|
||||
let transaction = &sanitized_txs[old_account.transaction_index];
|
||||
if let Some(parsed_vote) = vote_transaction::parse_vote_transaction(transaction) {
|
||||
let tx = &sanitized_txs[old_account.transaction_index];
|
||||
if let Some(parsed_vote) = vote_transaction::parse_sanitized_vote_transaction(tx) {
|
||||
if parsed_vote.1.slots.last().is_some() {
|
||||
let _ = vote_sender.send(parsed_vote);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use solana_sdk::{
|
||||
instruction::{CompiledInstruction, Instruction},
|
||||
message::Message,
|
||||
message::SanitizedMessage,
|
||||
};
|
||||
|
||||
/// Records and compiles cross-program invoked instructions
|
||||
@ -12,11 +12,14 @@ pub struct InstructionRecorder {
|
||||
}
|
||||
|
||||
impl InstructionRecorder {
|
||||
pub fn compile_instructions(&self, message: &Message) -> Vec<CompiledInstruction> {
|
||||
pub fn compile_instructions(
|
||||
&self,
|
||||
message: &SanitizedMessage,
|
||||
) -> Option<Vec<CompiledInstruction>> {
|
||||
self.inner
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|ix| message.compile_instruction(ix))
|
||||
.map(|ix| message.try_compile_instruction(ix))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -1837,8 +1837,9 @@ mod tests {
|
||||
genesis_config::create_genesis_config,
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
transaction::SanitizedTransaction,
|
||||
};
|
||||
use std::mem::size_of;
|
||||
use std::{convert::TryFrom, mem::size_of};
|
||||
|
||||
#[test]
|
||||
fn test_serialize_snapshot_data_file_under_limit() {
|
||||
@ -2910,12 +2911,13 @@ mod tests {
|
||||
|
||||
let slot = slot + 1;
|
||||
let bank2 = Arc::new(Bank::new_from_parent(&bank1, &collector, slot));
|
||||
let tx = system_transaction::transfer(
|
||||
let tx = SanitizedTransaction::try_from(system_transaction::transfer(
|
||||
&key1,
|
||||
&key2.pubkey(),
|
||||
lamports_to_transfer,
|
||||
bank2.last_blockhash(),
|
||||
);
|
||||
))
|
||||
.unwrap();
|
||||
let fee = bank2
|
||||
.get_fee_for_message(&bank2.last_blockhash(), tx.message())
|
||||
.unwrap();
|
||||
|
@ -1,16 +1,14 @@
|
||||
use crate::bank::Bank;
|
||||
use solana_sdk::{
|
||||
sanitized_transaction::SanitizedTransaction,
|
||||
transaction::{Result, Transaction},
|
||||
use {
|
||||
crate::bank::Bank,
|
||||
solana_sdk::transaction::{Result, SanitizedTransaction},
|
||||
std::borrow::Cow,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
|
||||
// Represents the results of trying to lock a set of accounts
|
||||
pub struct TransactionBatch<'a, 'b> {
|
||||
lock_results: Vec<Result<()>>,
|
||||
bank: &'a Bank,
|
||||
sanitized_txs: Cow<'b, [SanitizedTransaction<'b>]>,
|
||||
sanitized_txs: Cow<'b, [SanitizedTransaction]>,
|
||||
pub(crate) needs_unlock: bool,
|
||||
}
|
||||
|
||||
@ -18,7 +16,7 @@ impl<'a, 'b> TransactionBatch<'a, 'b> {
|
||||
pub fn new(
|
||||
lock_results: Vec<Result<()>>,
|
||||
bank: &'a Bank,
|
||||
sanitized_txs: Cow<'b, [SanitizedTransaction<'b>]>,
|
||||
sanitized_txs: Cow<'b, [SanitizedTransaction]>,
|
||||
) -> Self {
|
||||
assert_eq!(lock_results.len(), sanitized_txs.len());
|
||||
Self {
|
||||
@ -37,10 +35,6 @@ impl<'a, 'b> TransactionBatch<'a, 'b> {
|
||||
&self.sanitized_txs
|
||||
}
|
||||
|
||||
pub fn transactions_iter(&self) -> impl Iterator<Item = &Transaction> {
|
||||
self.sanitized_txs.iter().map(Deref::deref)
|
||||
}
|
||||
|
||||
pub fn bank(&self) -> &Bank {
|
||||
self.bank
|
||||
}
|
||||
@ -58,38 +52,33 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo};
|
||||
use solana_sdk::{signature::Keypair, system_transaction};
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[test]
|
||||
fn test_transaction_batch() {
|
||||
let (bank, txs) = setup();
|
||||
|
||||
// Test getting locked accounts
|
||||
let batch = bank.prepare_batch(txs.iter()).unwrap();
|
||||
let batch = bank.prepare_sanitized_batch(&txs);
|
||||
|
||||
// Grab locks
|
||||
assert!(batch.lock_results().iter().all(|x| x.is_ok()));
|
||||
|
||||
// Trying to grab locks again should fail
|
||||
let batch2 = bank.prepare_batch(txs.iter()).unwrap();
|
||||
let batch2 = bank.prepare_sanitized_batch(&txs);
|
||||
assert!(batch2.lock_results().iter().all(|x| x.is_err()));
|
||||
|
||||
// Drop the first set of locks
|
||||
drop(batch);
|
||||
|
||||
// Now grabbing locks should work again
|
||||
let batch2 = bank.prepare_batch(txs.iter()).unwrap();
|
||||
let batch2 = bank.prepare_sanitized_batch(&txs);
|
||||
assert!(batch2.lock_results().iter().all(|x| x.is_ok()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simulation_batch() {
|
||||
let (bank, txs) = setup();
|
||||
let txs = txs
|
||||
.into_iter()
|
||||
.map(SanitizedTransaction::try_from)
|
||||
.collect::<Result<Vec<_>>>()
|
||||
.unwrap();
|
||||
|
||||
// Prepare batch without locks
|
||||
let batch = bank.prepare_simulation_batch(txs[0].clone());
|
||||
@ -104,7 +93,7 @@ mod tests {
|
||||
assert!(batch3.lock_results().iter().all(|x| x.is_ok()));
|
||||
}
|
||||
|
||||
fn setup() -> (Bank, Vec<Transaction>) {
|
||||
fn setup() -> (Bank, Vec<SanitizedTransaction>) {
|
||||
let dummy_leader_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
@ -118,8 +107,12 @@ mod tests {
|
||||
let pubkey2 = solana_sdk::pubkey::new_rand();
|
||||
|
||||
let txs = vec![
|
||||
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash()),
|
||||
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()),
|
||||
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash())
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash())
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
];
|
||||
|
||||
(bank, txs)
|
||||
|
Reference in New Issue
Block a user