Refactor: Sanitized transaction creation (#23558)

* Refactor: SanitizedTransaction::try_create optionally computes hash

* Refactor: Add SimpleAddressLoader
This commit is contained in:
Justin Starry 2022-03-15 12:02:22 +08:00 committed by GitHub
parent f05ac7a899
commit 8c8f9694e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 81 additions and 55 deletions

View File

@ -1680,7 +1680,7 @@ impl BankingStage {
transaction_indexes: &[usize],
feature_set: &Arc<feature_set::FeatureSet>,
votes_only: bool,
address_loader: &impl AddressLoader,
address_loader: impl AddressLoader,
) -> (Vec<SanitizedTransaction>, Vec<usize>) {
transaction_indexes
.iter()
@ -1697,7 +1697,7 @@ impl BankingStage {
tx,
message_hash,
Some(p.meta.is_simple_vote_tx()),
address_loader,
address_loader.clone(),
)
.ok()?;
tx.verify_precompiles(feature_set).ok()?;
@ -2128,7 +2128,7 @@ mod tests {
signature::{Keypair, Signer},
system_instruction::SystemError,
system_transaction,
transaction::{DisabledAddressLoader, Transaction, TransactionError},
transaction::{MessageHash, SimpleAddressLoader, Transaction, TransactionError},
},
solana_streamer::{recvmmsg::recv_mmsg, socket::SocketAddrSpace},
solana_transaction_status::{TransactionStatusMeta, VersionedTransactionWithStatusMeta},
@ -3464,10 +3464,13 @@ mod tests {
});
let tx = VersionedTransaction::try_new(message, &[&keypair]).unwrap();
let message_hash = tx.message.hash();
let sanitized_tx =
SanitizedTransaction::try_create(tx.clone(), message_hash, Some(false), bank.as_ref())
.unwrap();
let sanitized_tx = SanitizedTransaction::try_create(
tx.clone(),
MessageHash::Compute,
Some(false),
bank.as_ref(),
)
.unwrap();
let entry = next_versioned_entry(&genesis_config.hash(), 1, vec![tx]);
let entries = vec![entry];
@ -4145,7 +4148,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(2, txs.len());
assert_eq!(vec![0, 1], tx_packet_index);
@ -4156,7 +4159,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(0, txs.len());
assert_eq!(0, tx_packet_index.len());
@ -4176,7 +4179,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(3, txs.len());
assert_eq!(vec![0, 1, 2], tx_packet_index);
@ -4187,7 +4190,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(2, txs.len());
assert_eq!(vec![0, 2], tx_packet_index);
@ -4207,7 +4210,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(3, txs.len());
assert_eq!(vec![0, 1, 2], tx_packet_index);
@ -4218,7 +4221,7 @@ mod tests {
&packet_indexes,
&Arc::new(FeatureSet::default()),
votes_only,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
assert_eq!(3, txs.len());
assert_eq!(vec![0, 1, 2], tx_packet_index);

View File

@ -6,7 +6,7 @@ use {
solana_sdk::{
hash::Hash,
transaction::{
DisabledAddressLoader, Result, SanitizedTransaction, TransactionVerificationMode,
Result, SanitizedTransaction, SimpleAddressLoader, TransactionVerificationMode,
VersionedTransaction,
},
},
@ -39,7 +39,7 @@ fn bench_gpusigverify(bencher: &mut Bencher) {
versioned_tx,
message_hash,
None,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
)
}?;
@ -80,7 +80,7 @@ fn bench_cpusigverify(bencher: &mut Bencher) {
versioned_tx,
message_hash,
None,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
)
}?;

View File

@ -933,7 +933,7 @@ mod tests {
signature::{Keypair, Signer},
system_transaction,
transaction::{
DisabledAddressLoader, Result, SanitizedTransaction, VersionedTransaction,
Result, SanitizedTransaction, SimpleAddressLoader, VersionedTransaction,
},
},
};
@ -1022,7 +1022,7 @@ mod tests {
versioned_tx,
message_hash,
None,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
)
}?;

View File

@ -60,7 +60,7 @@ use {
shred_version::compute_shred_version,
stake::{self, state::StakeState},
system_program,
transaction::{DisabledAddressLoader, SanitizedTransaction},
transaction::{MessageHash, SanitizedTransaction, SimpleAddressLoader},
},
solana_stake_program::stake_state::{self, PointValue},
solana_vote_program::{
@ -242,9 +242,9 @@ fn output_slot(
let tx_signature = transaction.signatures[0];
let sanitize_result = SanitizedTransaction::try_create(
transaction,
Hash::default(),
MessageHash::Compute,
None,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
);
match sanitize_result {
@ -794,9 +794,9 @@ fn compute_slot_cost(blockstore: &Blockstore, slot: Slot) -> Result<(), String>
.filter_map(|transaction| {
SanitizedTransaction::try_create(
transaction,
Hash::default(),
MessageHash::Compute,
None,
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
)
.map_err(|err| {
warn!("Failed to compute cost of transaction: {:?}", err);

View File

@ -70,7 +70,8 @@ use {
system_instruction,
sysvar::stake_history,
transaction::{
self, AddressLoader, SanitizedTransaction, TransactionError, VersionedTransaction,
self, AddressLoader, MessageHash, SanitizedTransaction, TransactionError,
VersionedTransaction,
},
},
solana_send_transaction_service::{
@ -4277,10 +4278,9 @@ where
fn sanitize_transaction(
transaction: VersionedTransaction,
address_loader: &impl AddressLoader,
address_loader: impl AddressLoader,
) -> Result<SanitizedTransaction> {
let message_hash = transaction.message.hash();
SanitizedTransaction::try_create(transaction, message_hash, None, address_loader)
SanitizedTransaction::try_create(transaction, MessageHash::Compute, None, address_loader)
.map_err(|err| Error::invalid_params(format!("invalid transaction: {}", err)))
}
@ -4420,7 +4420,7 @@ pub mod tests {
system_program, system_transaction,
timing::slot_duration_from_slots_per_year,
transaction::{
self, DisabledAddressLoader, Transaction, TransactionError, TransactionVersion,
self, SimpleAddressLoader, Transaction, TransactionError, TransactionVersion,
},
},
solana_transaction_status::{
@ -7823,7 +7823,8 @@ pub mod tests {
.to_string(),
);
assert_eq!(
sanitize_transaction(unsanitary_versioned_tx, &DisabledAddressLoader).unwrap_err(),
sanitize_transaction(unsanitary_versioned_tx, SimpleAddressLoader::Disabled)
.unwrap_err(),
expect58
);
}
@ -7843,9 +7844,9 @@ pub mod tests {
};
assert_eq!(
sanitize_transaction(versioned_tx, &DisabledAddressLoader).unwrap_err(),
sanitize_transaction(versioned_tx, SimpleAddressLoader::Disabled).unwrap_err(),
Error::invalid_params(
"invalid transaction: Transaction version is unsupported".to_string(),
"invalid transaction: Transaction loads an address table account that doesn't exist".to_string(),
)
);
}

View File

@ -225,7 +225,8 @@ pub(crate) mod tests {
signature::{Keypair, Signature, Signer},
system_transaction,
transaction::{
DisabledAddressLoader, SanitizedTransaction, Transaction, VersionedTransaction,
MessageHash, SanitizedTransaction, SimpleAddressLoader, Transaction,
VersionedTransaction,
},
},
solana_transaction_status::{
@ -304,14 +305,13 @@ pub(crate) mod tests {
Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger");
let blockstore = Arc::new(blockstore);
let message_hash = Hash::new_unique();
let transaction = build_test_transaction_legacy();
let transaction = VersionedTransaction::from(transaction);
let transaction = SanitizedTransaction::try_create(
transaction,
message_hash,
Some(true),
&DisabledAddressLoader,
MessageHash::Compute,
None,
SimpleAddressLoader::Disabled,
)
.unwrap();

View File

@ -127,7 +127,7 @@ use {
sysvar::{self, Sysvar, SysvarId},
timing::years_as_slots,
transaction::{
Result, SanitizedTransaction, Transaction, TransactionError,
MessageHash, Result, SanitizedTransaction, Transaction, TransactionError,
TransactionVerificationMode, VersionedTransaction,
},
transaction_context::{InstructionTrace, TransactionAccount, TransactionContext},
@ -3439,10 +3439,7 @@ impl Bank {
pub fn prepare_entry_batch(&self, txs: Vec<VersionedTransaction>) -> Result<TransactionBatch> {
let sanitized_txs = txs
.into_iter()
.map(|tx| {
let message_hash = tx.message.hash();
SanitizedTransaction::try_create(tx, message_hash, None, self)
})
.map(|tx| SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self))
.collect::<Result<Vec<_>>>()?;
let lock_results = self
.rc

View File

@ -8,9 +8,9 @@ use {
},
};
impl AddressLoader for Bank {
impl AddressLoader for &Bank {
fn load_addresses(
&self,
self,
address_table_lookups: &[MessageAddressTableLookup],
) -> TransactionResult<LoadedAddresses> {
if !self.versioned_tx_message_enabled() {

View File

@ -263,7 +263,7 @@ mod tests {
hash::Hash,
signature::{Keypair, Signer},
system_transaction,
transaction::{DisabledAddressLoader, VersionedTransaction},
transaction::{MessageHash, SimpleAddressLoader, VersionedTransaction},
},
solana_vote_program::vote_transaction,
std::{cmp, sync::Arc},
@ -326,12 +326,11 @@ mod tests {
&keypair,
None,
);
let message_hash = transaction.message.hash();
let vote_transaction = SanitizedTransaction::try_create(
VersionedTransaction::from(transaction),
message_hash,
MessageHash::Compute,
Some(true),
&DisabledAddressLoader,
SimpleAddressLoader::Disabled,
)
.unwrap();
(vote_transaction, vec![mint_keypair.pubkey()], 10)

View File

@ -39,14 +39,35 @@ pub struct TransactionAccountLocks<'a> {
pub writable: Vec<&'a Pubkey>,
}
pub trait AddressLoader {
fn load_addresses(&self, lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses>;
pub trait AddressLoader: Clone {
fn load_addresses(self, lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses>;
}
pub struct DisabledAddressLoader;
impl AddressLoader for DisabledAddressLoader {
fn load_addresses(&self, _lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses> {
Err(TransactionError::UnsupportedVersion)
#[derive(Clone)]
pub enum SimpleAddressLoader {
Disabled,
Enabled(LoadedAddresses),
}
impl AddressLoader for SimpleAddressLoader {
fn load_addresses(self, _lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses> {
match self {
Self::Disabled => Err(TransactionError::AddressLookupTableNotFound),
Self::Enabled(loaded_addresses) => Ok(loaded_addresses),
}
}
}
/// Type that represents whether the transaction message has been precomputed or
/// not.
pub enum MessageHash {
Precomputed(Hash),
Compute,
}
impl From<Hash> for MessageHash {
fn from(hash: Hash) -> Self {
Self::Precomputed(hash)
}
}
@ -56,12 +77,17 @@ impl SanitizedTransaction {
/// the address for each table index.
pub fn try_create(
tx: VersionedTransaction,
message_hash: Hash,
message_hash: impl Into<MessageHash>,
is_simple_vote_tx: Option<bool>,
address_loader: &impl AddressLoader,
address_loader: impl AddressLoader,
) -> Result<Self> {
tx.sanitize()?;
let message_hash = match message_hash.into() {
MessageHash::Compute => tx.message.hash(),
MessageHash::Precomputed(hash) => hash,
};
let signatures = tx.signatures;
let message = match tx.message {
VersionedMessage::Legacy(message) => SanitizedMessage::Legacy(message),