Add tests for private functions in SVM `account_loader.rs` (#35334)
This commit is contained in:
parent
f340c1c181
commit
8f3e960640
|
@ -271,6 +271,20 @@ impl SanitizedTransaction {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dev-context-only-utils")]
|
||||||
|
pub fn new_for_tests(
|
||||||
|
message: SanitizedMessage,
|
||||||
|
signatures: Vec<Signature>,
|
||||||
|
is_simple_vote_tx: bool,
|
||||||
|
) -> SanitizedTransaction {
|
||||||
|
SanitizedTransaction {
|
||||||
|
message,
|
||||||
|
message_hash: Hash::new_unique(),
|
||||||
|
signatures,
|
||||||
|
is_simple_vote_tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -276,6 +276,7 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
|
||||||
.map(|instruction| {
|
.map(|instruction| {
|
||||||
let mut account_indices = Vec::new();
|
let mut account_indices = Vec::new();
|
||||||
let mut program_index = instruction.program_id_index as usize;
|
let mut program_index = instruction.program_id_index as usize;
|
||||||
|
// This command may never return error, because the transaction is sanitized
|
||||||
let (program_id, program_account) = accounts
|
let (program_id, program_account) = accounts
|
||||||
.get(program_index)
|
.get(program_index)
|
||||||
.ok_or(TransactionError::ProgramAccountNotFound)?;
|
.ok_or(TransactionError::ProgramAccountNotFound)?;
|
||||||
|
@ -452,7 +453,7 @@ pub fn validate_fee_payer(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_instructions_account(message: &SanitizedMessage) -> AccountSharedData {
|
fn construct_instructions_account(message: &SanitizedMessage) -> AccountSharedData {
|
||||||
AccountSharedData::from(Account {
|
AccountSharedData::from(Account {
|
||||||
data: construct_instructions_data(&message.decompile_instructions()),
|
data: construct_instructions_data(&message.decompile_instructions()),
|
||||||
owner: sysvar::id(),
|
owner: sysvar::id(),
|
||||||
|
@ -464,31 +465,38 @@ pub fn construct_instructions_account(message: &SanitizedMessage) -> AccountShar
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
|
crate::transaction_processor::TransactionProcessingCallback,
|
||||||
nonce::state::Versions as NonceVersions,
|
nonce::state::Versions as NonceVersions,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
compute_budget_processor,
|
compute_budget_processor,
|
||||||
|
loaded_programs::LoadedProgram,
|
||||||
prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
|
prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{AccountSharedData, WritableAccount},
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
||||||
bpf_loader_upgradeable,
|
bpf_loader_upgradeable,
|
||||||
compute_budget::ComputeBudgetInstruction,
|
compute_budget::ComputeBudgetInstruction,
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
feature_set::FeatureSet,
|
feature_set::FeatureSet,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::CompiledInstruction,
|
instruction::CompiledInstruction,
|
||||||
message::{Message, SanitizedMessage},
|
message::{
|
||||||
|
v0::{LoadedAddresses, LoadedMessage},
|
||||||
|
LegacyMessage, Message, MessageHeader, SanitizedMessage,
|
||||||
|
},
|
||||||
nonce,
|
nonce,
|
||||||
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
rent_collector::RentCollector,
|
rent_collector::RentCollector,
|
||||||
signature::{Keypair, Signer},
|
signature::{Keypair, Signature, Signer},
|
||||||
system_program, sysvar,
|
system_program, sysvar,
|
||||||
transaction::{Result, Transaction, TransactionError},
|
transaction::{Result, Transaction, TransactionError},
|
||||||
transaction_context::TransactionAccount,
|
transaction_context::TransactionAccount,
|
||||||
},
|
},
|
||||||
std::{convert::TryFrom, sync::Arc},
|
std::{borrow::Cow, convert::TryFrom, sync::Arc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
struct TestCallbacks {
|
struct TestCallbacks {
|
||||||
accounts_map: HashMap<Pubkey, AccountSharedData>,
|
accounts_map: HashMap<Pubkey, AccountSharedData>,
|
||||||
rent_collector: RentCollector,
|
rent_collector: RentCollector,
|
||||||
|
@ -1380,4 +1388,662 @@ mod tests {
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_construct_instructions_account() {
|
||||||
|
let loaded_message = LoadedMessage {
|
||||||
|
message: Cow::Owned(solana_sdk::message::v0::Message::default()),
|
||||||
|
loaded_addresses: Cow::Owned(LoadedAddresses::default()),
|
||||||
|
is_writable_account_cache: vec![false],
|
||||||
|
};
|
||||||
|
let message = SanitizedMessage::V0(loaded_message);
|
||||||
|
let shared_data = construct_instructions_account(&message);
|
||||||
|
let expected = AccountSharedData::from(Account {
|
||||||
|
data: construct_instructions_data(&message.decompile_instructions()),
|
||||||
|
owner: sysvar::id(),
|
||||||
|
..Account::default()
|
||||||
|
});
|
||||||
|
assert_eq!(shared_data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_account_shared_data_from_program() {
|
||||||
|
let key = Keypair::new().pubkey();
|
||||||
|
let other_key = Keypair::new().pubkey();
|
||||||
|
|
||||||
|
let mut accounts: HashMap<Pubkey, (&Pubkey, u64)> = HashMap::new();
|
||||||
|
|
||||||
|
let result = account_shared_data_from_program(&key, &accounts);
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::AccountNotFound));
|
||||||
|
|
||||||
|
accounts.insert(key, (&other_key, 32));
|
||||||
|
|
||||||
|
let result = account_shared_data_from_program(&key, &accounts);
|
||||||
|
let mut expected = AccountSharedData::default();
|
||||||
|
expected.set_owner(other_key);
|
||||||
|
expected.set_executable(true);
|
||||||
|
expected.set_data_from_slice(create_executable_meta(&other_key));
|
||||||
|
|
||||||
|
assert_eq!(result.unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_failure() {
|
||||||
|
let message = Message::default();
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mock_bank = TestCallbacks::default();
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction =
|
||||||
|
SanitizedTransaction::new_for_tests(sanitized_message, vec![], false);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::MissingSignatureForFee));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_fail_to_validate_fee_payer() {
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![Pubkey::new_from_array([0; 32])],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 0,
|
||||||
|
accounts: vec![],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mock_bank = TestCallbacks::default();
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::AccountNotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_native_loader() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key1.pubkey(), native_loader::id()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.insert(native_loader::id(), AccountSharedData::default());
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key1.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap(),
|
||||||
|
LoadedTransaction {
|
||||||
|
accounts: vec![
|
||||||
|
(
|
||||||
|
key1.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key1.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
native_loader::id(),
|
||||||
|
mock_bank.accounts_map[&native_loader::id()].clone()
|
||||||
|
)
|
||||||
|
],
|
||||||
|
program_indices: vec![vec![]],
|
||||||
|
rent: 0,
|
||||||
|
rent_debits: RentDebits::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_account_not_found_but_loaded() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key1.pubkey(), key2.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let mut loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
loaded_programs.replenish(key2.pubkey(), Arc::new(LoadedProgram::default()));
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::AccountNotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_account_no_data() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key1.pubkey(), key2.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0, 1],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_invalid_program_for_execution() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key1.pubkey(), key2.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 0,
|
||||||
|
accounts: vec![0, 1],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.err(),
|
||||||
|
Some(TransactionError::InvalidProgramForExecution)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_native_loader_owner() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key2.pubkey(), key1.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_owner(native_loader::id());
|
||||||
|
account_data.set_executable(true);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key2.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap(),
|
||||||
|
LoadedTransaction {
|
||||||
|
accounts: vec![
|
||||||
|
(
|
||||||
|
key2.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key2.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key1.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key1.pubkey()].clone()
|
||||||
|
),
|
||||||
|
],
|
||||||
|
program_indices: vec![vec![1]],
|
||||||
|
rent: 0,
|
||||||
|
rent_debits: RentDebits::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_account_not_found_after_all_checks() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key2.pubkey(), key1.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key2.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_account_invalid_program_for_execution_last_check() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
let key3 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key2.pubkey(), key1.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
account_data.set_owner(key3.pubkey());
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
|
||||||
|
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.insert(key3.pubkey(), AccountSharedData::default());
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key2.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.err(),
|
||||||
|
Some(TransactionError::InvalidProgramForExecution)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_success_complete() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
let key3 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key2.pubkey(), key1.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
}],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
account_data.set_owner(key3.pubkey());
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
account_data.set_owner(native_loader::id());
|
||||||
|
mock_bank.accounts_map.insert(key3.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key2.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap(),
|
||||||
|
LoadedTransaction {
|
||||||
|
accounts: vec![
|
||||||
|
(
|
||||||
|
key2.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key2.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key1.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key1.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key3.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key3.pubkey()].clone()
|
||||||
|
),
|
||||||
|
],
|
||||||
|
program_indices: vec![vec![2, 1]],
|
||||||
|
rent: 0,
|
||||||
|
rent_debits: RentDebits::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_transaction_accounts_program_builtin_saturating_add() {
|
||||||
|
let key1 = Keypair::new();
|
||||||
|
let key2 = Keypair::new();
|
||||||
|
let key3 = Keypair::new();
|
||||||
|
let key4 = Keypair::new();
|
||||||
|
|
||||||
|
let message = Message {
|
||||||
|
account_keys: vec![key2.pubkey(), key1.pubkey(), key4.pubkey()],
|
||||||
|
header: MessageHeader::default(),
|
||||||
|
instructions: vec![
|
||||||
|
CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![0],
|
||||||
|
data: vec![],
|
||||||
|
},
|
||||||
|
CompiledInstruction {
|
||||||
|
program_id_index: 1,
|
||||||
|
accounts: vec![2],
|
||||||
|
data: vec![],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
recent_blockhash: Hash::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let legacy = LegacyMessage::new(message);
|
||||||
|
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||||
|
let mut mock_bank = TestCallbacks::default();
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
account_data.set_owner(key3.pubkey());
|
||||||
|
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_lamports(200);
|
||||||
|
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_executable(true);
|
||||||
|
account_data.set_owner(native_loader::id());
|
||||||
|
mock_bank.accounts_map.insert(key3.pubkey(), account_data);
|
||||||
|
|
||||||
|
let mut error_counter = TransactionErrorMetrics::default();
|
||||||
|
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||||
|
|
||||||
|
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||||
|
sanitized_message,
|
||||||
|
vec![Signature::new_unique()],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let result = load_transaction_accounts(
|
||||||
|
&mock_bank,
|
||||||
|
&sanitized_transaction,
|
||||||
|
32,
|
||||||
|
&mut error_counter,
|
||||||
|
None,
|
||||||
|
&HashMap::new(),
|
||||||
|
&loaded_programs,
|
||||||
|
);
|
||||||
|
mock_bank
|
||||||
|
.accounts_map
|
||||||
|
.get_mut(&key2.pubkey())
|
||||||
|
.unwrap()
|
||||||
|
.set_lamports(200 - 32);
|
||||||
|
|
||||||
|
let mut account_data = AccountSharedData::default();
|
||||||
|
account_data.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap(),
|
||||||
|
LoadedTransaction {
|
||||||
|
accounts: vec![
|
||||||
|
(
|
||||||
|
key2.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key2.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(
|
||||||
|
key1.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key1.pubkey()].clone()
|
||||||
|
),
|
||||||
|
(key4.pubkey(), account_data),
|
||||||
|
(
|
||||||
|
key3.pubkey(),
|
||||||
|
mock_bank.accounts_map[&key3.pubkey()].clone()
|
||||||
|
),
|
||||||
|
],
|
||||||
|
program_indices: vec![vec![3, 1], vec![3, 1]],
|
||||||
|
rent: 0,
|
||||||
|
rent_debits: RentDebits::default()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue