Use reserved account keys list to restrict tx write locks (#541)
* Plumb through reserved account keys set * Plumb through tests
This commit is contained in:
parent
cb13b39118
commit
09241ae9c3
|
@ -178,6 +178,7 @@ fn simulate_transaction(
|
|||
MessageHash::Compute,
|
||||
Some(false), // is_simple_vote_tx
|
||||
bank,
|
||||
bank.get_reserved_account_keys(),
|
||||
) {
|
||||
Err(err) => {
|
||||
return BanksTransactionResultWithSimulation {
|
||||
|
@ -332,6 +333,7 @@ impl Banks for BanksServer {
|
|||
MessageHash::Compute,
|
||||
Some(false), // is_simple_vote_tx
|
||||
bank.as_ref(),
|
||||
bank.get_reserved_account_keys(),
|
||||
) {
|
||||
Ok(tx) => tx,
|
||||
Err(err) => return Some(Err(err)),
|
||||
|
@ -417,7 +419,9 @@ impl Banks for BanksServer {
|
|||
commitment: CommitmentLevel,
|
||||
) -> Option<u64> {
|
||||
let bank = self.bank(commitment);
|
||||
let sanitized_message = SanitizedMessage::try_from_legacy_message(message).ok()?;
|
||||
let sanitized_message =
|
||||
SanitizedMessage::try_from_legacy_message(message, bank.get_reserved_account_keys())
|
||||
.ok()?;
|
||||
bank.get_fee_for_message(&sanitized_message)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -868,6 +868,7 @@ mod tests {
|
|||
nonce_account::verify_nonce_account,
|
||||
poh_config::PohConfig,
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::Keypair,
|
||||
signer::Signer,
|
||||
system_instruction, system_program, system_transaction,
|
||||
|
@ -2026,6 +2027,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(false),
|
||||
bank.as_ref(),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use {
|
|||
feature_set,
|
||||
hash::Hash,
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
sanitize::SanitizeError,
|
||||
saturating_add_assign,
|
||||
short_vec::decode_shortu16_len,
|
||||
|
@ -15,7 +16,7 @@ use {
|
|||
VersionedTransaction,
|
||||
},
|
||||
},
|
||||
std::{cmp::Ordering, mem::size_of, sync::Arc},
|
||||
std::{cmp::Ordering, collections::HashSet, mem::size_of, sync::Arc},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
@ -123,6 +124,7 @@ impl ImmutableDeserializedPacket {
|
|||
feature_set: &Arc<feature_set::FeatureSet>,
|
||||
votes_only: bool,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Option<SanitizedTransaction> {
|
||||
if votes_only && !self.is_simple_vote() {
|
||||
return None;
|
||||
|
@ -132,6 +134,7 @@ impl ImmutableDeserializedPacket {
|
|||
*self.message_hash(),
|
||||
self.is_simple_vote(),
|
||||
address_loader,
|
||||
reserved_account_keys,
|
||||
)
|
||||
.ok()?;
|
||||
tx.verify_precompiles(feature_set).ok()?;
|
||||
|
|
|
@ -283,6 +283,7 @@ impl LatestUnprocessedVotes {
|
|||
&bank.feature_set,
|
||||
bank.vote_only_bank(),
|
||||
bank.as_ref(),
|
||||
bank.get_reserved_account_keys(),
|
||||
)
|
||||
{
|
||||
if forward_packet_batches_by_accounts.try_add_packet(
|
||||
|
|
|
@ -138,6 +138,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(false),
|
||||
bank,
|
||||
bank.get_reserved_account_keys(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
@ -381,7 +381,12 @@ impl SchedulerController {
|
|||
let (transactions, fee_budget_limits_vec): (Vec<_>, Vec<_>) = chunk
|
||||
.iter()
|
||||
.filter_map(|packet| {
|
||||
packet.build_sanitized_transaction(feature_set, vote_only, bank.as_ref())
|
||||
packet.build_sanitized_transaction(
|
||||
feature_set,
|
||||
vote_only,
|
||||
bank.as_ref(),
|
||||
bank.get_reserved_account_keys(),
|
||||
)
|
||||
})
|
||||
.inspect(|_| saturating_add_assign!(post_sanitization_count, 1))
|
||||
.filter(|tx| {
|
||||
|
|
|
@ -310,6 +310,7 @@ mod tests {
|
|||
solana_sdk::{
|
||||
compute_budget::ComputeBudgetInstruction,
|
||||
message::Message,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signer},
|
||||
system_instruction, system_transaction,
|
||||
transaction::{SimpleAddressLoader, Transaction},
|
||||
|
@ -490,6 +491,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(2, txs.count());
|
||||
|
@ -500,6 +502,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(0, txs.count());
|
||||
|
@ -519,6 +522,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(3, txs.count());
|
||||
|
@ -529,6 +533,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(2, txs.count());
|
||||
|
@ -548,6 +553,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(3, txs.count());
|
||||
|
@ -558,6 +564,7 @@ mod tests {
|
|||
&Arc::new(FeatureSet::default()),
|
||||
votes_only,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
});
|
||||
assert_eq!(3, txs.count());
|
||||
|
|
|
@ -153,9 +153,13 @@ fn consume_scan_should_process_packet(
|
|||
}
|
||||
|
||||
// Try to sanitize the packet
|
||||
let (maybe_sanitized_transaction, sanitization_time_us) = measure_us!(
|
||||
packet.build_sanitized_transaction(&bank.feature_set, bank.vote_only_bank(), bank)
|
||||
);
|
||||
let (maybe_sanitized_transaction, sanitization_time_us) = measure_us!(packet
|
||||
.build_sanitized_transaction(
|
||||
&bank.feature_set,
|
||||
bank.vote_only_bank(),
|
||||
bank,
|
||||
bank.get_reserved_account_keys(),
|
||||
));
|
||||
|
||||
payload
|
||||
.slot_metrics_tracker
|
||||
|
@ -770,7 +774,12 @@ impl ThreadLocalUnprocessedPackets {
|
|||
.enumerate()
|
||||
.filter_map(|(packet_index, deserialized_packet)| {
|
||||
deserialized_packet
|
||||
.build_sanitized_transaction(&bank.feature_set, bank.vote_only_bank(), bank)
|
||||
.build_sanitized_transaction(
|
||||
&bank.feature_set,
|
||||
bank.vote_only_bank(),
|
||||
bank,
|
||||
bank.get_reserved_account_keys(),
|
||||
)
|
||||
.map(|transaction| (transaction, packet_index))
|
||||
})
|
||||
.unzip();
|
||||
|
|
|
@ -339,6 +339,7 @@ mod tests {
|
|||
crate::transaction_cost::*,
|
||||
solana_sdk::{
|
||||
hash::Hash,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
transaction::{
|
||||
|
@ -401,6 +402,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(true),
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -203,6 +203,7 @@ mod tests {
|
|||
feature_set::FeatureSet,
|
||||
hash::Hash,
|
||||
message::SimpleAddressLoader,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signer::keypair::Keypair,
|
||||
transaction::{MessageHash, SanitizedTransaction, VersionedTransaction},
|
||||
},
|
||||
|
@ -231,6 +232,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(true),
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -240,6 +242,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(false),
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use {
|
|||
solana_perf::test_tx::test_tx,
|
||||
solana_sdk::{
|
||||
hash::Hash,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
transaction::{
|
||||
Result, SanitizedTransaction, SimpleAddressLoader, TransactionVerificationMode,
|
||||
VersionedTransaction,
|
||||
|
@ -41,6 +42,7 @@ fn bench_gpusigverify(bencher: &mut Bencher) {
|
|||
message_hash,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
}?;
|
||||
|
||||
|
@ -84,6 +86,7 @@ fn bench_cpusigverify(bencher: &mut Bencher) {
|
|||
message_hash,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
}?;
|
||||
|
||||
|
|
|
@ -982,6 +982,7 @@ mod tests {
|
|||
solana_sdk::{
|
||||
hash::{hash, Hash},
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
transaction::{
|
||||
|
@ -1084,6 +1085,7 @@ mod tests {
|
|||
message_hash,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
}?;
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ use {
|
|||
native_token::{lamports_to_sol, sol_to_lamports, Sol},
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
shred_version::compute_shred_version,
|
||||
stake::{self, state::StakeStateV2},
|
||||
system_program,
|
||||
|
@ -461,6 +462,9 @@ fn compute_slot_cost(
|
|||
let mut program_ids = HashMap::new();
|
||||
let mut cost_tracker = CostTracker::default();
|
||||
|
||||
let feature_set = FeatureSet::all_enabled();
|
||||
let reserved_account_keys = ReservedAccountKeys::new_all_activated();
|
||||
|
||||
for entry in entries {
|
||||
num_transactions += entry.transactions.len();
|
||||
entry
|
||||
|
@ -472,6 +476,7 @@ fn compute_slot_cost(
|
|||
MessageHash::Compute,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&reserved_account_keys.active,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("Failed to compute cost of transaction: {:?}", err);
|
||||
|
@ -481,7 +486,7 @@ fn compute_slot_cost(
|
|||
.for_each(|transaction| {
|
||||
num_programs += transaction.message().instructions().len();
|
||||
|
||||
let tx_cost = CostModel::calculate_cost(&transaction, &FeatureSet::all_enabled());
|
||||
let tx_cost = CostModel::calculate_cost(&transaction, &feature_set);
|
||||
let result = cost_tracker.try_add(&tx_cost);
|
||||
if result.is_err() {
|
||||
println!(
|
||||
|
|
|
@ -81,6 +81,7 @@ use {
|
|||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signer},
|
||||
system_program,
|
||||
transaction::{SanitizedTransaction, Transaction, TransactionError},
|
||||
|
@ -201,7 +202,11 @@ fn execute_transactions(
|
|||
}
|
||||
.expect("lamports_per_signature must be available");
|
||||
let fee = bank.get_fee_for_message_with_lamports_per_signature(
|
||||
&SanitizedMessage::try_from_legacy_message(tx.message().clone()).unwrap(),
|
||||
&SanitizedMessage::try_from_legacy_message(
|
||||
tx.message().clone(),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap(),
|
||||
lamports_per_signature,
|
||||
);
|
||||
|
||||
|
@ -3706,7 +3711,11 @@ fn test_program_fees() {
|
|||
Some(&mint_keypair.pubkey()),
|
||||
);
|
||||
|
||||
let sanitized_message = SanitizedMessage::try_from_legacy_message(message.clone()).unwrap();
|
||||
let sanitized_message = SanitizedMessage::try_from_legacy_message(
|
||||
message.clone(),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
let expected_normal_fee = fee_structure.calculate_fee(
|
||||
&sanitized_message,
|
||||
congestion_multiplier,
|
||||
|
@ -3730,7 +3739,11 @@ fn test_program_fees() {
|
|||
],
|
||||
Some(&mint_keypair.pubkey()),
|
||||
);
|
||||
let sanitized_message = SanitizedMessage::try_from_legacy_message(message.clone()).unwrap();
|
||||
let sanitized_message = SanitizedMessage::try_from_legacy_message(
|
||||
message.clone(),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
let expected_prioritized_fee = fee_structure.calculate_fee(
|
||||
&sanitized_message,
|
||||
congestion_multiplier,
|
||||
|
|
|
@ -3657,7 +3657,11 @@ pub mod rpc_full {
|
|||
min_context_slot,
|
||||
})?;
|
||||
|
||||
let transaction = sanitize_transaction(unsanitized_tx, preflight_bank)?;
|
||||
let transaction = sanitize_transaction(
|
||||
unsanitized_tx,
|
||||
preflight_bank,
|
||||
preflight_bank.get_reserved_account_keys(),
|
||||
)?;
|
||||
let signature = *transaction.signature();
|
||||
|
||||
let mut last_valid_block_height = preflight_bank
|
||||
|
@ -3789,7 +3793,8 @@ pub mod rpc_full {
|
|||
});
|
||||
}
|
||||
|
||||
let transaction = sanitize_transaction(unsanitized_tx, bank)?;
|
||||
let transaction =
|
||||
sanitize_transaction(unsanitized_tx, bank, bank.get_reserved_account_keys())?;
|
||||
if sig_verify {
|
||||
verify_transaction(&transaction, &bank.feature_set)?;
|
||||
}
|
||||
|
@ -4041,10 +4046,12 @@ pub mod rpc_full {
|
|||
.map_err(|err| {
|
||||
Error::invalid_params(format!("invalid transaction message: {err}"))
|
||||
})?;
|
||||
let sanitized_message = SanitizedMessage::try_new(sanitized_versioned_message, bank)
|
||||
.map_err(|err| {
|
||||
Error::invalid_params(format!("invalid transaction message: {err}"))
|
||||
})?;
|
||||
let sanitized_message = SanitizedMessage::try_new(
|
||||
sanitized_versioned_message,
|
||||
bank,
|
||||
bank.get_reserved_account_keys(),
|
||||
)
|
||||
.map_err(|err| Error::invalid_params(format!("invalid transaction message: {err}")))?;
|
||||
let fee = bank.get_fee_for_message(&sanitized_message);
|
||||
Ok(new_response(bank, fee))
|
||||
}
|
||||
|
@ -4623,9 +4630,16 @@ where
|
|||
fn sanitize_transaction(
|
||||
transaction: VersionedTransaction,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<SanitizedTransaction> {
|
||||
SanitizedTransaction::try_create(transaction, MessageHash::Compute, None, address_loader)
|
||||
.map_err(|err| Error::invalid_params(format!("invalid transaction: {err}")))
|
||||
SanitizedTransaction::try_create(
|
||||
transaction,
|
||||
MessageHash::Compute,
|
||||
None,
|
||||
address_loader,
|
||||
reserved_account_keys,
|
||||
)
|
||||
.map_err(|err| Error::invalid_params(format!("invalid transaction: {err}")))
|
||||
}
|
||||
|
||||
pub fn create_validator_exit(exit: Arc<AtomicBool>) -> Arc<RwLock<Exit>> {
|
||||
|
@ -4771,6 +4785,7 @@ pub mod tests {
|
|||
Message, MessageHeader, VersionedMessage,
|
||||
},
|
||||
nonce::{self, state::DurableNonce},
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
rpc_port,
|
||||
signature::{Keypair, Signer},
|
||||
slot_hashes::SlotHashes,
|
||||
|
@ -9049,8 +9064,12 @@ pub mod tests {
|
|||
.to_string(),
|
||||
);
|
||||
assert_eq!(
|
||||
sanitize_transaction(unsanitary_versioned_tx, SimpleAddressLoader::Disabled)
|
||||
.unwrap_err(),
|
||||
sanitize_transaction(
|
||||
unsanitary_versioned_tx,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set()
|
||||
)
|
||||
.unwrap_err(),
|
||||
expect58
|
||||
);
|
||||
}
|
||||
|
@ -9070,7 +9089,12 @@ pub mod tests {
|
|||
};
|
||||
|
||||
assert_eq!(
|
||||
sanitize_transaction(versioned_tx, SimpleAddressLoader::Disabled).unwrap_err(),
|
||||
sanitize_transaction(
|
||||
versioned_tx,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set()
|
||||
)
|
||||
.unwrap_err(),
|
||||
Error::invalid_params(
|
||||
"invalid transaction: Transaction version is unsupported".to_string(),
|
||||
)
|
||||
|
|
|
@ -225,6 +225,7 @@ pub(crate) mod tests {
|
|||
nonce_info::{NonceFull, NoncePartial},
|
||||
pubkey::Pubkey,
|
||||
rent_debits::RentDebits,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signature, Signer},
|
||||
system_transaction,
|
||||
transaction::{
|
||||
|
@ -335,6 +336,7 @@ pub(crate) mod tests {
|
|||
MessageHash::Compute,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -364,7 +366,10 @@ pub(crate) mod tests {
|
|||
durable_nonce_fee: Some(DurableNonceFee::from(
|
||||
&NonceFull::from_partial(
|
||||
&rollback_partial,
|
||||
&SanitizedMessage::Legacy(LegacyMessage::new(message)),
|
||||
&SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)),
|
||||
&[(pubkey, nonce_account)],
|
||||
&rent_debits,
|
||||
)
|
||||
|
|
|
@ -17,10 +17,12 @@ use {
|
|||
solana_sdk::{
|
||||
hash::Hash,
|
||||
message::{AddressLoader, SanitizedMessage, SanitizedVersionedMessage},
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
simple_vote_transaction_checker::is_simple_vote_transaction,
|
||||
transaction::{Result, SanitizedVersionedTransaction},
|
||||
},
|
||||
std::collections::HashSet,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
@ -101,12 +103,14 @@ impl RuntimeTransaction<SanitizedMessage> {
|
|||
pub fn try_from(
|
||||
statically_loaded_runtime_tx: RuntimeTransaction<SanitizedVersionedMessage>,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self> {
|
||||
let mut tx = Self {
|
||||
signatures: statically_loaded_runtime_tx.signatures,
|
||||
message: SanitizedMessage::try_new(
|
||||
statically_loaded_runtime_tx.message,
|
||||
address_loader,
|
||||
reserved_account_keys,
|
||||
)?,
|
||||
meta: statically_loaded_runtime_tx.meta,
|
||||
};
|
||||
|
@ -132,6 +136,7 @@ mod tests {
|
|||
compute_budget::ComputeBudgetInstruction,
|
||||
instruction::Instruction,
|
||||
message::Message,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signer::{keypair::Keypair, Signer},
|
||||
transaction::{SimpleAddressLoader, Transaction, VersionedTransaction},
|
||||
},
|
||||
|
@ -256,6 +261,7 @@ mod tests {
|
|||
let dynamically_loaded_transaction = RuntimeTransaction::<SanitizedMessage>::try_from(
|
||||
statically_loaded_transaction,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
);
|
||||
let dynamically_loaded_transaction =
|
||||
dynamically_loaded_transaction.expect("created from statically loaded tx");
|
||||
|
|
|
@ -3470,7 +3470,15 @@ impl Bank {
|
|||
pub fn prepare_entry_batch(&self, txs: Vec<VersionedTransaction>) -> Result<TransactionBatch> {
|
||||
let sanitized_txs = txs
|
||||
.into_iter()
|
||||
.map(|tx| SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self))
|
||||
.map(|tx| {
|
||||
SanitizedTransaction::try_create(
|
||||
tx,
|
||||
MessageHash::Compute,
|
||||
None,
|
||||
self,
|
||||
self.get_reserved_account_keys(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let tx_account_lock_limit = self.get_transaction_account_lock_limit();
|
||||
let lock_results = self
|
||||
|
@ -5901,7 +5909,13 @@ impl Bank {
|
|||
tx.message.hash()
|
||||
};
|
||||
|
||||
SanitizedTransaction::try_create(tx, message_hash, None, self)
|
||||
SanitizedTransaction::try_create(
|
||||
tx,
|
||||
message_hash,
|
||||
None,
|
||||
self,
|
||||
self.get_reserved_account_keys(),
|
||||
)
|
||||
}?;
|
||||
|
||||
if verification_mode == TransactionVerificationMode::HashAndVerifyPrecompiles
|
||||
|
|
|
@ -189,7 +189,8 @@ pub(in crate::bank) fn create_genesis_config(lamports: u64) -> (GenesisConfig, K
|
|||
}
|
||||
|
||||
fn new_sanitized_message(message: Message) -> SanitizedMessage {
|
||||
SanitizedMessage::try_from_legacy_message(message).unwrap()
|
||||
SanitizedMessage::try_from_legacy_message(message, &ReservedAccountKeys::empty_key_set())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -285,15 +285,15 @@ impl SyncClient for BankClient {
|
|||
}
|
||||
|
||||
fn get_fee_for_message(&self, message: &Message) -> Result<u64> {
|
||||
SanitizedMessage::try_from_legacy_message(message.clone())
|
||||
.ok()
|
||||
.and_then(|sanitized_message| self.bank.get_fee_for_message(&sanitized_message))
|
||||
.ok_or_else(|| {
|
||||
TransportError::IoError(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Unable calculate fee",
|
||||
))
|
||||
})
|
||||
SanitizedMessage::try_from_legacy_message(
|
||||
message.clone(),
|
||||
self.bank.get_reserved_account_keys(),
|
||||
)
|
||||
.ok()
|
||||
.and_then(|sanitized_message| self.bank.get_fee_for_message(&sanitized_message))
|
||||
.ok_or_else(|| {
|
||||
TransportError::IoError(io::Error::new(io::ErrorKind::Other, "Unable calculate fee"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use {
|
|||
instruction::{AccountMeta, Instruction},
|
||||
message::{Message, SanitizedMessage},
|
||||
pubkey::{self, Pubkey},
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
sysvar::instructions::{self, construct_instructions_data},
|
||||
},
|
||||
test::Bencher,
|
||||
|
@ -29,10 +30,10 @@ fn bench_bincode_instruction_serialize(b: &mut Bencher) {
|
|||
#[bench]
|
||||
fn bench_construct_instructions_data(b: &mut Bencher) {
|
||||
let instructions = make_instructions();
|
||||
let message = SanitizedMessage::try_from_legacy_message(Message::new(
|
||||
&instructions,
|
||||
Some(&Pubkey::new_unique()),
|
||||
))
|
||||
let message = SanitizedMessage::try_from_legacy_message(
|
||||
Message::new(&instructions, Some(&Pubkey::new_unique())),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
b.iter(|| {
|
||||
let instructions = message.decompile_instructions();
|
||||
|
@ -52,10 +53,10 @@ fn bench_bincode_instruction_deserialize(b: &mut Bencher) {
|
|||
#[bench]
|
||||
fn bench_manual_instruction_deserialize(b: &mut Bencher) {
|
||||
let instructions = make_instructions();
|
||||
let message = SanitizedMessage::try_from_legacy_message(Message::new(
|
||||
&instructions,
|
||||
Some(&Pubkey::new_unique()),
|
||||
))
|
||||
let message = SanitizedMessage::try_from_legacy_message(
|
||||
Message::new(&instructions, Some(&Pubkey::new_unique())),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
let serialized = construct_instructions_data(&message.decompile_instructions());
|
||||
b.iter(|| {
|
||||
|
@ -69,10 +70,10 @@ fn bench_manual_instruction_deserialize(b: &mut Bencher) {
|
|||
#[bench]
|
||||
fn bench_manual_instruction_deserialize_single(b: &mut Bencher) {
|
||||
let instructions = make_instructions();
|
||||
let message = SanitizedMessage::try_from_legacy_message(Message::new(
|
||||
&instructions,
|
||||
Some(&Pubkey::new_unique()),
|
||||
))
|
||||
let message = SanitizedMessage::try_from_legacy_message(
|
||||
Message::new(&instructions, Some(&Pubkey::new_unique())),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
let serialized = construct_instructions_data(&message.decompile_instructions());
|
||||
b.iter(|| {
|
||||
|
|
|
@ -550,7 +550,7 @@ impl Message {
|
|||
|
||||
/// Returns true if the account at the specified index was requested to be
|
||||
/// writable. This method should not be used directly.
|
||||
fn is_writable_index(&self, i: usize) -> bool {
|
||||
pub(super) fn is_writable_index(&self, i: usize) -> bool {
|
||||
i < (self.header.num_required_signatures - self.header.num_readonly_signed_accounts)
|
||||
as usize
|
||||
|| (i >= self.header.num_required_signatures as usize
|
||||
|
@ -558,10 +558,11 @@ impl Message {
|
|||
- self.header.num_readonly_unsigned_accounts as usize)
|
||||
}
|
||||
|
||||
/// Returns true if the account at the specified index should be write
|
||||
/// locked when loaded for transaction processing in the runtime. This
|
||||
/// method differs from `is_maybe_writable` because it is aware of the
|
||||
/// latest reserved accounts which are not allowed to be write locked.
|
||||
/// Returns true if the account at the specified index is writable by the
|
||||
/// instructions in this message. Since the dynamic set of reserved accounts
|
||||
/// isn't used here to demote write locks, this shouldn't be used in the
|
||||
/// runtime.
|
||||
#[deprecated(since = "2.0.0", note = "Please use `is_maybe_writable` instead")]
|
||||
pub fn is_writable(&self, i: usize) -> bool {
|
||||
(self.is_writable_index(i))
|
||||
&& !is_builtin_key_or_sysvar(&self.account_keys[i])
|
||||
|
@ -587,7 +588,7 @@ impl Message {
|
|||
let mut writable_keys = vec![];
|
||||
let mut readonly_keys = vec![];
|
||||
for (i, key) in self.account_keys.iter().enumerate() {
|
||||
if self.is_writable(i) {
|
||||
if self.is_maybe_writable(i) {
|
||||
writable_keys.push(key);
|
||||
} else {
|
||||
readonly_keys.push(key);
|
||||
|
|
|
@ -17,7 +17,7 @@ use {
|
|||
solana_program::{system_instruction::SystemInstruction, system_program},
|
||||
sysvar::instructions::{BorrowedAccountMeta, BorrowedInstruction},
|
||||
},
|
||||
std::{borrow::Cow, convert::TryFrom},
|
||||
std::{borrow::Cow, collections::HashSet, convert::TryFrom},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
|
@ -31,12 +31,16 @@ pub struct LegacyMessage<'a> {
|
|||
}
|
||||
|
||||
impl<'a> LegacyMessage<'a> {
|
||||
pub fn new(message: legacy::Message) -> Self {
|
||||
pub fn new(message: legacy::Message, reserved_account_keys: &HashSet<Pubkey>) -> Self {
|
||||
let is_writable_account_cache = message
|
||||
.account_keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _key)| message.is_writable(i))
|
||||
.map(|(i, _key)| {
|
||||
message.is_writable_index(i)
|
||||
&& !reserved_account_keys.contains(&message.account_keys[i])
|
||||
&& !message.demote_program_id(i)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Self {
|
||||
message: Cow::Owned(message),
|
||||
|
@ -105,23 +109,34 @@ impl SanitizedMessage {
|
|||
pub fn try_new(
|
||||
sanitized_msg: SanitizedVersionedMessage,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self, SanitizeMessageError> {
|
||||
Ok(match sanitized_msg.message {
|
||||
VersionedMessage::Legacy(message) => {
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(message))
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(message, reserved_account_keys))
|
||||
}
|
||||
VersionedMessage::V0(message) => {
|
||||
let loaded_addresses =
|
||||
address_loader.load_addresses(&message.address_table_lookups)?;
|
||||
SanitizedMessage::V0(v0::LoadedMessage::new(message, loaded_addresses))
|
||||
SanitizedMessage::V0(v0::LoadedMessage::new(
|
||||
message,
|
||||
loaded_addresses,
|
||||
reserved_account_keys,
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a sanitized legacy message
|
||||
pub fn try_from_legacy_message(message: legacy::Message) -> Result<Self, SanitizeMessageError> {
|
||||
pub fn try_from_legacy_message(
|
||||
message: legacy::Message,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self, SanitizeMessageError> {
|
||||
message.sanitize()?;
|
||||
Ok(Self::Legacy(LegacyMessage::new(message)))
|
||||
Ok(Self::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
reserved_account_keys,
|
||||
)))
|
||||
}
|
||||
|
||||
/// Return true if this message contains duplicate account keys
|
||||
|
@ -431,7 +446,11 @@ mod tests {
|
|||
};
|
||||
|
||||
assert_eq!(
|
||||
SanitizedMessage::try_from_legacy_message(legacy_message_with_no_signers).err(),
|
||||
SanitizedMessage::try_from_legacy_message(
|
||||
legacy_message_with_no_signers,
|
||||
&HashSet::default(),
|
||||
)
|
||||
.err(),
|
||||
Some(SanitizeMessageError::IndexOutOfBounds),
|
||||
);
|
||||
}
|
||||
|
@ -455,6 +474,7 @@ mod tests {
|
|||
Hash::default(),
|
||||
instructions,
|
||||
),
|
||||
&HashSet::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -472,15 +492,18 @@ mod tests {
|
|||
let key4 = Pubkey::new_unique();
|
||||
let key5 = Pubkey::new_unique();
|
||||
|
||||
let legacy_message = SanitizedMessage::try_from_legacy_message(legacy::Message {
|
||||
header: MessageHeader {
|
||||
num_required_signatures: 2,
|
||||
num_readonly_signed_accounts: 1,
|
||||
num_readonly_unsigned_accounts: 1,
|
||||
let legacy_message = SanitizedMessage::try_from_legacy_message(
|
||||
legacy::Message {
|
||||
header: MessageHeader {
|
||||
num_required_signatures: 2,
|
||||
num_readonly_signed_accounts: 1,
|
||||
num_readonly_unsigned_accounts: 1,
|
||||
},
|
||||
account_keys: vec![key0, key1, key2, key3],
|
||||
..legacy::Message::default()
|
||||
},
|
||||
account_keys: vec![key0, key1, key2, key3],
|
||||
..legacy::Message::default()
|
||||
})
|
||||
&HashSet::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(legacy_message.num_readonly_accounts(), 2);
|
||||
|
@ -499,6 +522,7 @@ mod tests {
|
|||
writable: vec![key4],
|
||||
readonly: vec![key5],
|
||||
},
|
||||
&HashSet::default(),
|
||||
));
|
||||
|
||||
assert_eq!(v0_message.num_readonly_accounts(), 3);
|
||||
|
@ -525,6 +549,7 @@ mod tests {
|
|||
Hash::default(),
|
||||
instructions,
|
||||
),
|
||||
&HashSet::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -556,15 +581,18 @@ mod tests {
|
|||
let key4 = Pubkey::new_unique();
|
||||
let key5 = Pubkey::new_unique();
|
||||
|
||||
let legacy_message = SanitizedMessage::try_from_legacy_message(legacy::Message {
|
||||
header: MessageHeader {
|
||||
num_required_signatures: 2,
|
||||
num_readonly_signed_accounts: 1,
|
||||
num_readonly_unsigned_accounts: 1,
|
||||
let legacy_message = SanitizedMessage::try_from_legacy_message(
|
||||
legacy::Message {
|
||||
header: MessageHeader {
|
||||
num_required_signatures: 2,
|
||||
num_readonly_signed_accounts: 1,
|
||||
num_readonly_unsigned_accounts: 1,
|
||||
},
|
||||
account_keys: vec![key0, key1, key2, key3],
|
||||
..legacy::Message::default()
|
||||
},
|
||||
account_keys: vec![key0, key1, key2, key3],
|
||||
..legacy::Message::default()
|
||||
})
|
||||
&HashSet::default(),
|
||||
)
|
||||
.unwrap();
|
||||
match legacy_message {
|
||||
SanitizedMessage::Legacy(message) => {
|
||||
|
@ -596,6 +624,7 @@ mod tests {
|
|||
writable: vec![key4],
|
||||
readonly: vec![key5],
|
||||
},
|
||||
&HashSet::default(),
|
||||
));
|
||||
match v0_message {
|
||||
SanitizedMessage::V0(message) => {
|
||||
|
@ -646,6 +675,7 @@ mod tests {
|
|||
mock_secp256k1_instr,
|
||||
],
|
||||
),
|
||||
&HashSet::new(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
bpf_loader_upgradeable,
|
||||
message::{legacy::is_builtin_key_or_sysvar, v0, AccountKeys},
|
||||
message::{v0, AccountKeys},
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
std::{borrow::Cow, collections::HashSet},
|
||||
|
@ -55,32 +55,40 @@ impl LoadedAddresses {
|
|||
}
|
||||
|
||||
impl<'a> LoadedMessage<'a> {
|
||||
pub fn new(message: v0::Message, loaded_addresses: LoadedAddresses) -> Self {
|
||||
pub fn new(
|
||||
message: v0::Message,
|
||||
loaded_addresses: LoadedAddresses,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Self {
|
||||
let mut loaded_message = Self {
|
||||
message: Cow::Owned(message),
|
||||
loaded_addresses: Cow::Owned(loaded_addresses),
|
||||
is_writable_account_cache: Vec::default(),
|
||||
};
|
||||
loaded_message.set_is_writable_account_cache();
|
||||
loaded_message.set_is_writable_account_cache(reserved_account_keys);
|
||||
loaded_message
|
||||
}
|
||||
|
||||
pub fn new_borrowed(message: &'a v0::Message, loaded_addresses: &'a LoadedAddresses) -> Self {
|
||||
pub fn new_borrowed(
|
||||
message: &'a v0::Message,
|
||||
loaded_addresses: &'a LoadedAddresses,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Self {
|
||||
let mut loaded_message = Self {
|
||||
message: Cow::Borrowed(message),
|
||||
loaded_addresses: Cow::Borrowed(loaded_addresses),
|
||||
is_writable_account_cache: Vec::default(),
|
||||
};
|
||||
loaded_message.set_is_writable_account_cache();
|
||||
loaded_message.set_is_writable_account_cache(reserved_account_keys);
|
||||
loaded_message
|
||||
}
|
||||
|
||||
fn set_is_writable_account_cache(&mut self) {
|
||||
fn set_is_writable_account_cache(&mut self, reserved_account_keys: &HashSet<Pubkey>) {
|
||||
let is_writable_account_cache = self
|
||||
.account_keys()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _key)| self.is_writable_internal(i))
|
||||
.map(|(i, _key)| self.is_writable_internal(i, reserved_account_keys))
|
||||
.collect::<Vec<_>>();
|
||||
let _ = std::mem::replace(
|
||||
&mut self.is_writable_account_cache,
|
||||
|
@ -127,10 +135,14 @@ impl<'a> LoadedMessage<'a> {
|
|||
}
|
||||
|
||||
/// Returns true if the account at the specified index was loaded as writable
|
||||
fn is_writable_internal(&self, key_index: usize) -> bool {
|
||||
fn is_writable_internal(
|
||||
&self,
|
||||
key_index: usize,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> bool {
|
||||
if self.is_writable_index(key_index) {
|
||||
if let Some(key) = self.account_keys().get(key_index) {
|
||||
return !(is_builtin_key_or_sysvar(key) || self.demote_program_id(key_index));
|
||||
return !(reserved_account_keys.contains(key) || self.demote_program_id(key_index));
|
||||
}
|
||||
}
|
||||
false
|
||||
|
@ -201,6 +213,7 @@ mod tests {
|
|||
writable: vec![key4],
|
||||
readonly: vec![key5],
|
||||
},
|
||||
&HashSet::default(),
|
||||
);
|
||||
|
||||
(message, [key0, key1, key2, key3, key4, key5])
|
||||
|
@ -225,6 +238,7 @@ mod tests {
|
|||
writable: keys.split_off(2),
|
||||
readonly: keys,
|
||||
},
|
||||
&HashSet::default(),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -257,6 +271,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_is_writable() {
|
||||
solana_logger::setup();
|
||||
|
||||
let reserved_account_keys = HashSet::from_iter([sysvar::clock::id(), system_program::id()]);
|
||||
let create_message_with_keys = |keys: Vec<Pubkey>| {
|
||||
LoadedMessage::new(
|
||||
v0::Message {
|
||||
|
@ -272,6 +288,7 @@ mod tests {
|
|||
writable: keys[2..=2].to_vec(),
|
||||
readonly: keys[3..].to_vec(),
|
||||
},
|
||||
&reserved_account_keys,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -321,6 +338,7 @@ mod tests {
|
|||
writable: vec![key1, key2],
|
||||
readonly: vec![],
|
||||
},
|
||||
&HashSet::default(),
|
||||
);
|
||||
|
||||
assert!(message.is_writable_index(2));
|
||||
|
|
|
@ -302,10 +302,11 @@ mod tests {
|
|||
message::{Message as LegacyMessage, SanitizedMessage},
|
||||
pubkey::Pubkey,
|
||||
},
|
||||
std::collections::HashSet,
|
||||
};
|
||||
|
||||
fn new_sanitized_message(message: LegacyMessage) -> SanitizedMessage {
|
||||
SanitizedMessage::try_from_legacy_message(message).unwrap()
|
||||
SanitizedMessage::try_from_legacy_message(message, &HashSet::default()).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -124,6 +124,7 @@ mod tests {
|
|||
instruction::Instruction,
|
||||
message::Message,
|
||||
nonce::{self, state::DurableNonce},
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{keypair_from_seed, Signer},
|
||||
system_instruction, system_program,
|
||||
},
|
||||
|
@ -133,7 +134,11 @@ mod tests {
|
|||
instructions: &[Instruction],
|
||||
payer: Option<&Pubkey>,
|
||||
) -> SanitizedMessage {
|
||||
SanitizedMessage::try_from_legacy_message(Message::new(instructions, payer)).unwrap()
|
||||
SanitizedMessage::try_from_legacy_message(
|
||||
Message::new(instructions, payer),
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -12,6 +12,7 @@ use {
|
|||
},
|
||||
precompiles::verify_if_precompile,
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
sanitize::Sanitize,
|
||||
signature::Signature,
|
||||
simple_vote_transaction_checker::is_simple_vote_transaction,
|
||||
|
@ -19,6 +20,7 @@ use {
|
|||
transaction::{Result, Transaction, TransactionError, VersionedTransaction},
|
||||
},
|
||||
solana_program::message::SanitizedVersionedMessage,
|
||||
std::collections::HashSet,
|
||||
};
|
||||
|
||||
/// Maximum number of accounts that a transaction may lock.
|
||||
|
@ -66,17 +68,22 @@ impl SanitizedTransaction {
|
|||
message_hash: Hash,
|
||||
is_simple_vote_tx: bool,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self> {
|
||||
let signatures = tx.signatures;
|
||||
let SanitizedVersionedMessage { message } = tx.message;
|
||||
let message = match message {
|
||||
VersionedMessage::Legacy(message) => {
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(message))
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(message, reserved_account_keys))
|
||||
}
|
||||
VersionedMessage::V0(message) => {
|
||||
let loaded_addresses =
|
||||
address_loader.load_addresses(&message.address_table_lookups)?;
|
||||
SanitizedMessage::V0(v0::LoadedMessage::new(message, loaded_addresses))
|
||||
SanitizedMessage::V0(v0::LoadedMessage::new(
|
||||
message,
|
||||
loaded_addresses,
|
||||
reserved_account_keys,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -96,6 +103,7 @@ impl SanitizedTransaction {
|
|||
message_hash: impl Into<MessageHash>,
|
||||
is_simple_vote_tx: Option<bool>,
|
||||
address_loader: impl AddressLoader,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self> {
|
||||
let sanitized_versioned_tx = SanitizedVersionedTransaction::try_from(tx)?;
|
||||
let is_simple_vote_tx = is_simple_vote_tx
|
||||
|
@ -109,15 +117,23 @@ impl SanitizedTransaction {
|
|||
message_hash,
|
||||
is_simple_vote_tx,
|
||||
address_loader,
|
||||
reserved_account_keys,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_from_legacy_transaction(tx: Transaction) -> Result<Self> {
|
||||
/// Create a sanitized transaction from a legacy transaction
|
||||
pub fn try_from_legacy_transaction(
|
||||
tx: Transaction,
|
||||
reserved_account_keys: &HashSet<Pubkey>,
|
||||
) -> Result<Self> {
|
||||
tx.sanitize()?;
|
||||
|
||||
Ok(Self {
|
||||
message_hash: tx.message.hash(),
|
||||
message: SanitizedMessage::Legacy(LegacyMessage::new(tx.message)),
|
||||
message: SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
tx.message,
|
||||
reserved_account_keys,
|
||||
)),
|
||||
is_simple_vote_tx: false,
|
||||
signatures: tx.signatures,
|
||||
})
|
||||
|
@ -125,7 +141,7 @@ impl SanitizedTransaction {
|
|||
|
||||
/// Create a sanitized transaction from a legacy transaction. Used for tests only.
|
||||
pub fn from_transaction_for_tests(tx: Transaction) -> Self {
|
||||
Self::try_from_legacy_transaction(tx).unwrap()
|
||||
Self::try_from_legacy_transaction(tx, &ReservedAccountKeys::empty_key_set()).unwrap()
|
||||
}
|
||||
|
||||
/// Return the first signature for this transaction.
|
||||
|
@ -292,7 +308,10 @@ impl SanitizedTransaction {
|
|||
mod tests {
|
||||
use {
|
||||
super::*,
|
||||
crate::signer::{keypair::Keypair, Signer},
|
||||
crate::{
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signer::{keypair::Keypair, Signer},
|
||||
},
|
||||
solana_program::vote::{self, state::Vote},
|
||||
};
|
||||
|
||||
|
@ -317,6 +336,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(vote_transaction.is_simple_vote_transaction());
|
||||
|
@ -329,6 +349,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(false),
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!vote_transaction.is_simple_vote_transaction());
|
||||
|
@ -343,6 +364,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
None,
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(!vote_transaction.is_simple_vote_transaction());
|
||||
|
@ -355,6 +377,7 @@ mod tests {
|
|||
MessageHash::Compute,
|
||||
Some(true),
|
||||
SimpleAddressLoader::Disabled,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(vote_transaction.is_simple_vote_transaction());
|
||||
|
|
|
@ -491,6 +491,7 @@ mod tests {
|
|||
rent::Rent,
|
||||
rent_collector::{RentCollector, RENT_EXEMPT_RENT_EPOCH},
|
||||
rent_debits::RentDebits,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signature, Signer},
|
||||
system_program, system_transaction, sysvar,
|
||||
transaction::{Result, SanitizedTransaction, Transaction, TransactionError},
|
||||
|
@ -570,6 +571,18 @@ mod tests {
|
|||
features
|
||||
}
|
||||
|
||||
fn new_sanitized_message(message: Message) -> SanitizedMessage {
|
||||
SanitizedMessage::try_from_legacy_message(message, &ReservedAccountKeys::empty_key_set())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn new_unchecked_sanitized_message(message: Message) -> SanitizedMessage {
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
))
|
||||
}
|
||||
|
||||
fn load_accounts_with_fee(
|
||||
tx: Transaction,
|
||||
ka: &[TransactionAccount],
|
||||
|
@ -689,7 +702,7 @@ mod tests {
|
|||
instructions,
|
||||
);
|
||||
|
||||
let message = SanitizedMessage::try_from_legacy_message(tx.message().clone()).unwrap();
|
||||
let message = new_sanitized_message(tx.message().clone());
|
||||
let fee = FeeStructure::default().calculate_fee(
|
||||
&message,
|
||||
lamports_per_signature,
|
||||
|
@ -1217,7 +1230,7 @@ mod tests {
|
|||
Hash::default(),
|
||||
);
|
||||
|
||||
let message = SanitizedMessage::try_from_legacy_message(tx.message().clone()).unwrap();
|
||||
let message = new_sanitized_message(tx.message().clone());
|
||||
let fee = FeeStructure::default().calculate_fee(
|
||||
&message,
|
||||
lamports_per_signature,
|
||||
|
@ -1441,8 +1454,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mock_bank = TestCallbacks::default();
|
||||
let mut error_counter = TransactionErrorMetrics::default();
|
||||
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||
|
@ -1479,8 +1491,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
mock_bank
|
||||
.accounts_map
|
||||
|
@ -1548,8 +1559,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_lamports(200);
|
||||
|
@ -1593,8 +1603,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_lamports(200);
|
||||
|
@ -1637,8 +1646,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_lamports(200);
|
||||
|
@ -1684,8 +1692,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_owner(native_loader::id());
|
||||
|
@ -1754,8 +1761,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_executable(true);
|
||||
|
@ -1807,8 +1813,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_executable(true);
|
||||
|
@ -1868,8 +1873,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_executable(true);
|
||||
|
@ -1957,8 +1961,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_executable(true);
|
||||
|
@ -2110,8 +2113,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let mut mock_bank = TestCallbacks::default();
|
||||
let mut account_data = AccountSharedData::default();
|
||||
account_data.set_executable(true);
|
||||
|
@ -2202,8 +2204,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let sanitized_transaction = SanitizedTransaction::new_for_tests(
|
||||
sanitized_message,
|
||||
vec![Signature::new_unique()],
|
||||
|
|
|
@ -160,6 +160,7 @@ mod tests {
|
|||
native_loader::{self, create_loadable_account_for_test},
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
secp256k1_instruction::new_secp256k1_instruction,
|
||||
secp256k1_program, system_program,
|
||||
transaction_context::TransactionContext,
|
||||
|
@ -177,7 +178,8 @@ mod tests {
|
|||
}
|
||||
|
||||
fn new_sanitized_message(message: Message) -> SanitizedMessage {
|
||||
SanitizedMessage::try_from_legacy_message(message).unwrap()
|
||||
SanitizedMessage::try_from_legacy_message(message, &ReservedAccountKeys::empty_key_set())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -82,6 +82,7 @@ mod test {
|
|||
instruction::CompiledInstruction,
|
||||
message::{LegacyMessage, Message, MessageHeader, SanitizedMessage},
|
||||
rent::Rent,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::TransactionError,
|
||||
transaction_context::TransactionContext,
|
||||
|
@ -114,8 +115,10 @@ mod test {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
));
|
||||
|
||||
let transaction_accounts = vec![
|
||||
(key1.pubkey(), AccountSharedData::default()),
|
||||
|
@ -166,8 +169,10 @@ mod test {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
));
|
||||
|
||||
let transaction_accounts = vec![
|
||||
(key1.pubkey(), AccountSharedData::default()),
|
||||
|
|
|
@ -995,6 +995,7 @@ mod tests {
|
|||
fee_calculator::FeeCalculator,
|
||||
message::{LegacyMessage, Message, MessageHeader},
|
||||
rent_debits::RentDebits,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::{Keypair, Signature},
|
||||
sysvar::{self, rent::Rent},
|
||||
transaction::{SanitizedTransaction, Transaction, TransactionError},
|
||||
|
@ -1007,6 +1008,13 @@ mod tests {
|
|||
},
|
||||
};
|
||||
|
||||
fn new_unchecked_sanitized_message(message: Message) -> SanitizedMessage {
|
||||
SanitizedMessage::Legacy(LegacyMessage::new(
|
||||
message,
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
))
|
||||
}
|
||||
|
||||
struct TestForkGraph {}
|
||||
|
||||
impl ForkGraph for TestForkGraph {
|
||||
|
@ -1711,8 +1719,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||
let mock_bank = MockBankCallback::default();
|
||||
let batch_processor = TransactionBatchProcessor::<TestForkGraph>::default();
|
||||
|
@ -1836,8 +1843,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
let loaded_programs = LoadedProgramsForTxBatch::default();
|
||||
let mock_bank = MockBankCallback::default();
|
||||
let batch_processor = TransactionBatchProcessor::<TestForkGraph>::default();
|
||||
|
@ -1954,8 +1960,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
|
||||
let sanitized_transaction_1 = SanitizedTransaction::new_for_tests(
|
||||
sanitized_message,
|
||||
|
@ -1985,8 +1990,7 @@ mod tests {
|
|||
recent_blockhash: Hash::default(),
|
||||
};
|
||||
|
||||
let legacy = LegacyMessage::new(message);
|
||||
let sanitized_message = SanitizedMessage::Legacy(legacy);
|
||||
let sanitized_message = new_unchecked_sanitized_message(message);
|
||||
|
||||
let sanitized_transaction_2 = SanitizedTransaction::new_for_tests(
|
||||
sanitized_message,
|
||||
|
|
|
@ -4,6 +4,7 @@ use {
|
|||
instruction::{AccountMeta, CompiledInstruction},
|
||||
message::{Message, MessageHeader},
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::Signature,
|
||||
transaction::{SanitizedTransaction, Transaction},
|
||||
},
|
||||
|
@ -126,7 +127,11 @@ impl SanitizedTransactionBuilder {
|
|||
message,
|
||||
};
|
||||
|
||||
SanitizedTransaction::try_from_legacy_transaction(transaction).unwrap()
|
||||
SanitizedTransaction::try_from_legacy_transaction(
|
||||
transaction,
|
||||
&ReservedAccountKeys::new_all_activated().active,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ use {
|
|||
AccountKeys, Message, MessageHeader, VersionedMessage,
|
||||
},
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
signature::Signature,
|
||||
transaction::{
|
||||
Result as TransactionResult, Transaction, TransactionError, TransactionVersion,
|
||||
|
@ -980,12 +981,16 @@ impl VersionedTransactionWithStatusMeta {
|
|||
show_rewards: bool,
|
||||
) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
|
||||
let version = self.validate_version(max_supported_transaction_version)?;
|
||||
let reserved_account_keys = ReservedAccountKeys::new_all_activated();
|
||||
|
||||
let account_keys = match &self.transaction.message {
|
||||
VersionedMessage::Legacy(message) => parse_legacy_message_accounts(message),
|
||||
VersionedMessage::V0(message) => {
|
||||
let loaded_message =
|
||||
LoadedMessage::new_borrowed(message, &self.meta.loaded_addresses);
|
||||
let loaded_message = LoadedMessage::new_borrowed(
|
||||
message,
|
||||
&self.meta.loaded_addresses,
|
||||
&reserved_account_keys.active,
|
||||
);
|
||||
parse_v0_message_accounts(&loaded_message)
|
||||
}
|
||||
};
|
||||
|
@ -1228,8 +1233,13 @@ impl EncodableWithMeta for v0::Message {
|
|||
meta: &TransactionStatusMeta,
|
||||
) -> Self::Encoded {
|
||||
if encoding == UiTransactionEncoding::JsonParsed {
|
||||
let reserved_account_keys = ReservedAccountKeys::new_all_activated();
|
||||
let account_keys = AccountKeys::new(&self.account_keys, Some(&meta.loaded_addresses));
|
||||
let loaded_message = LoadedMessage::new_borrowed(self, &meta.loaded_addresses);
|
||||
let loaded_message = LoadedMessage::new_borrowed(
|
||||
self,
|
||||
&meta.loaded_addresses,
|
||||
&reserved_account_keys.active,
|
||||
);
|
||||
UiMessage::Parsed(UiParsedMessage {
|
||||
account_keys: parse_v0_message_accounts(&loaded_message),
|
||||
recent_blockhash: self.recent_blockhash.to_string(),
|
||||
|
|
|
@ -54,6 +54,7 @@ mod test {
|
|||
solana_sdk::{
|
||||
message::{v0, v0::LoadedAddresses, MessageHeader},
|
||||
pubkey::Pubkey,
|
||||
reserved_account_keys::ReservedAccountKeys,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -126,6 +127,7 @@ mod test {
|
|||
writable: vec![pubkey4],
|
||||
readonly: vec![pubkey5],
|
||||
},
|
||||
&ReservedAccountKeys::empty_key_set(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue