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

View File

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

View File

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

View File

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

View File

@ -70,7 +70,8 @@ use {
system_instruction, system_instruction,
sysvar::stake_history, sysvar::stake_history,
transaction::{ transaction::{
self, AddressLoader, SanitizedTransaction, TransactionError, VersionedTransaction, self, AddressLoader, MessageHash, SanitizedTransaction, TransactionError,
VersionedTransaction,
}, },
}, },
solana_send_transaction_service::{ solana_send_transaction_service::{
@ -4277,10 +4278,9 @@ where
fn sanitize_transaction( fn sanitize_transaction(
transaction: VersionedTransaction, transaction: VersionedTransaction,
address_loader: &impl AddressLoader, address_loader: impl AddressLoader,
) -> Result<SanitizedTransaction> { ) -> Result<SanitizedTransaction> {
let message_hash = transaction.message.hash(); SanitizedTransaction::try_create(transaction, MessageHash::Compute, None, address_loader)
SanitizedTransaction::try_create(transaction, message_hash, None, address_loader)
.map_err(|err| Error::invalid_params(format!("invalid transaction: {}", err))) .map_err(|err| Error::invalid_params(format!("invalid transaction: {}", err)))
} }
@ -4420,7 +4420,7 @@ pub mod tests {
system_program, system_transaction, system_program, system_transaction,
timing::slot_duration_from_slots_per_year, timing::slot_duration_from_slots_per_year,
transaction::{ transaction::{
self, DisabledAddressLoader, Transaction, TransactionError, TransactionVersion, self, SimpleAddressLoader, Transaction, TransactionError, TransactionVersion,
}, },
}, },
solana_transaction_status::{ solana_transaction_status::{
@ -7823,7 +7823,8 @@ pub mod tests {
.to_string(), .to_string(),
); );
assert_eq!( assert_eq!(
sanitize_transaction(unsanitary_versioned_tx, &DisabledAddressLoader).unwrap_err(), sanitize_transaction(unsanitary_versioned_tx, SimpleAddressLoader::Disabled)
.unwrap_err(),
expect58 expect58
); );
} }
@ -7843,9 +7844,9 @@ pub mod tests {
}; };
assert_eq!( assert_eq!(
sanitize_transaction(versioned_tx, &DisabledAddressLoader).unwrap_err(), sanitize_transaction(versioned_tx, SimpleAddressLoader::Disabled).unwrap_err(),
Error::invalid_params( 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}, signature::{Keypair, Signature, Signer},
system_transaction, system_transaction,
transaction::{ transaction::{
DisabledAddressLoader, SanitizedTransaction, Transaction, VersionedTransaction, MessageHash, SanitizedTransaction, SimpleAddressLoader, Transaction,
VersionedTransaction,
}, },
}, },
solana_transaction_status::{ solana_transaction_status::{
@ -304,14 +305,13 @@ pub(crate) mod tests {
Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger"); Blockstore::open(&ledger_path).expect("Expected to be able to open database ledger");
let blockstore = Arc::new(blockstore); let blockstore = Arc::new(blockstore);
let message_hash = Hash::new_unique();
let transaction = build_test_transaction_legacy(); let transaction = build_test_transaction_legacy();
let transaction = VersionedTransaction::from(transaction); let transaction = VersionedTransaction::from(transaction);
let transaction = SanitizedTransaction::try_create( let transaction = SanitizedTransaction::try_create(
transaction, transaction,
message_hash, MessageHash::Compute,
Some(true), None,
&DisabledAddressLoader, SimpleAddressLoader::Disabled,
) )
.unwrap(); .unwrap();

View File

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

View File

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

View File

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

View File

@ -39,14 +39,35 @@ pub struct TransactionAccountLocks<'a> {
pub writable: Vec<&'a Pubkey>, pub writable: Vec<&'a Pubkey>,
} }
pub trait AddressLoader { pub trait AddressLoader: Clone {
fn load_addresses(&self, lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses>; fn load_addresses(self, lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses>;
} }
pub struct DisabledAddressLoader; #[derive(Clone)]
impl AddressLoader for DisabledAddressLoader { pub enum SimpleAddressLoader {
fn load_addresses(&self, _lookups: &[MessageAddressTableLookup]) -> Result<LoadedAddresses> { Disabled,
Err(TransactionError::UnsupportedVersion) 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. /// the address for each table index.
pub fn try_create( pub fn try_create(
tx: VersionedTransaction, tx: VersionedTransaction,
message_hash: Hash, message_hash: impl Into<MessageHash>,
is_simple_vote_tx: Option<bool>, is_simple_vote_tx: Option<bool>,
address_loader: &impl AddressLoader, address_loader: impl AddressLoader,
) -> Result<Self> { ) -> Result<Self> {
tx.sanitize()?; tx.sanitize()?;
let message_hash = match message_hash.into() {
MessageHash::Compute => tx.message.hash(),
MessageHash::Precomputed(hash) => hash,
};
let signatures = tx.signatures; let signatures = tx.signatures;
let message = match tx.message { let message = match tx.message {
VersionedMessage::Legacy(message) => SanitizedMessage::Legacy(message), VersionedMessage::Legacy(message) => SanitizedMessage::Legacy(message),