Refactor: Sanitized transaction creation (#23558)
* Refactor: SanitizedTransaction::try_create optionally computes hash * Refactor: Add SimpleAddressLoader
This commit is contained in:
parent
f05ac7a899
commit
8c8f9694e0
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in New Issue