Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Add support for versioned transactions, but disable by default
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Aug 11, 2021
1 parent 06ade67 commit 679e7a2
Show file tree
Hide file tree
Showing 41 changed files with 1,800 additions and 1,014 deletions.
23 changes: 13 additions & 10 deletions core/benches/banking_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use solana_sdk::signature::Signer;
use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
use solana_sdk::timing::{duration_as_us, timestamp};
use solana_sdk::transaction::Transaction;
use solana_sdk::transaction::{Transaction, VersionedTransaction};
use solana_streamer::socket::SocketAddrSpace;
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
Expand Down Expand Up @@ -287,7 +287,7 @@ fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
fn simulate_process_entries(
randomize_txs: bool,
mint_keypair: &Keypair,
mut tx_vector: Vec<Transaction>,
mut tx_vector: Vec<VersionedTransaction>,
genesis_config: &GenesisConfig,
keypairs: &[Keypair],
initial_lamports: u64,
Expand All @@ -301,12 +301,15 @@ fn simulate_process_entries(
}

for i in (0..num_accounts).step_by(2) {
tx_vector.push(system_transaction::transfer(
&keypairs[i],
&keypairs[i + 1].pubkey(),
initial_lamports,
bank.last_blockhash(),
));
tx_vector.push(
system_transaction::transfer(
&keypairs[i],
&keypairs[i + 1].pubkey(),
initial_lamports,
bank.last_blockhash(),
)
.into(),
);
}

// Transfer lamports to each other
Expand All @@ -315,7 +318,7 @@ fn simulate_process_entries(
hash: next_hash(&bank.last_blockhash(), 1, &tx_vector),
transactions: tx_vector,
};
process_entries(&bank, &mut [entry], randomize_txs, None, None).unwrap();
process_entries(&bank, vec![entry], randomize_txs, None, None).unwrap();
}

#[allow(clippy::same_item_push)]
Expand All @@ -335,7 +338,7 @@ fn bench_process_entries(randomize_txs: bool, bencher: &mut Bencher) {
} = create_genesis_config((num_accounts + 1) as u64 * initial_lamports);

let mut keypairs: Vec<Keypair> = vec![];
let tx_vector: Vec<Transaction> = Vec::with_capacity(num_accounts / 2);
let tx_vector: Vec<VersionedTransaction> = Vec::with_capacity(num_accounts / 2);

for _ in 0..num_accounts {
let keypair = Keypair::new();
Expand Down
2 changes: 1 addition & 1 deletion core/benches/shredder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn make_test_entry(txs_per_entry: u64) -> Entry {
Entry {
num_hashes: 100_000,
hash: Hash::default(),
transactions: vec![test_tx::test_tx(); txs_per_entry as usize],
transactions: vec![test_tx::test_tx().into(); txs_per_entry as usize],
}
}
fn make_large_unchained_entries(txs_per_entry: u64, num_entries: u64) -> Vec<Entry> {
Expand Down
86 changes: 38 additions & 48 deletions core/src/banking_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,15 @@ use solana_sdk::{
},
message::Message,
pubkey::Pubkey,
sanitized_transaction::SanitizedTransaction,
short_vec::decode_shortu16_len,
signature::Signature,
timing::{duration_as_ms, timestamp, AtomicInterval},
transaction::{self, Transaction, TransactionError},
transaction::{self, SanitizedTransaction, TransactionError, VersionedTransaction},
};
use solana_transaction_status::token_balances::{
collect_token_balances, TransactionTokenBalancesSet,
};
use std::{
borrow::Cow,
cmp,
collections::{HashMap, VecDeque},
env,
Expand Down Expand Up @@ -729,9 +727,9 @@ impl BankingStage {
}

#[allow(clippy::match_wild_err_arm)]
fn record_transactions<'a>(
fn record_transactions(
bank_slot: Slot,
txs: impl Iterator<Item = &'a Transaction>,
txs: &[SanitizedTransaction],
results: &[TransactionExecutionResult],
recorder: &TransactionRecorder,
) -> (Result<usize, PohRecorderError>, Vec<usize>) {
Expand All @@ -740,9 +738,9 @@ impl BankingStage {
.iter()
.zip(txs)
.enumerate()
.filter_map(|(i, ((r, _n), x))| {
.filter_map(|(i, ((r, _n), tx))| {
if Bank::can_commit(r) {
Some((x.clone(), i))
Some((tx.to_versioned_transaction(), i))
} else {
None
}
Expand Down Expand Up @@ -835,7 +833,7 @@ impl BankingStage {

let mut record_time = Measure::start("record_time");
let (num_to_commit, retryable_record_txs) =
Self::record_transactions(bank.slot(), batch.transactions_iter(), &results, poh);
Self::record_transactions(bank.slot(), batch.sanitized_transactions(), &results, poh);
inc_new_counter_info!(
"banking_stage-record_transactions_num_to_commit",
*num_to_commit.as_ref().unwrap_or(&0)
Expand Down Expand Up @@ -865,7 +863,7 @@ impl BankingStage {

bank_utils::find_and_send_votes(sanitized_txs, &tx_results, Some(gossip_vote_sender));
if let Some(transaction_status_sender) = transaction_status_sender {
let txs = batch.transactions_iter().cloned().collect();
let txs = batch.sanitized_transactions().to_vec();
let post_balances = bank.collect_balances(batch);
let post_token_balances = collect_token_balances(bank, batch, &mut mint_decimals);
transaction_status_sender.send_transaction_status_batch(
Expand Down Expand Up @@ -1050,19 +1048,22 @@ impl BankingStage {
libsecp256k1_0_5_upgrade_enabled: bool,
cost_tracker: &Arc<RwLock<CostTracker>>,
banking_stage_stats: &BankingStageStats,
) -> (Vec<SanitizedTransaction<'static>>, Vec<usize>, Vec<usize>) {
) -> (Vec<SanitizedTransaction>, Vec<usize>, Vec<usize>) {
let mut retryable_transaction_packet_indexes: Vec<usize> = vec![];

let verified_transactions_with_packet_indexes: Vec<_> = transaction_indexes
.iter()
.filter_map(|tx_index| {
let p = &msgs.packets[*tx_index];
let tx: Transaction = limited_deserialize(&p.data[0..p.meta.size]).ok()?;
tx.verify_precompiles(libsecp256k1_0_5_upgrade_enabled)
.ok()?;
let tx: VersionedTransaction = limited_deserialize(&p.data[0..p.meta.size]).ok()?;
let message_bytes = Self::packet_message(p)?;
let message_hash = Message::hash_raw_message(message_bytes);
let tx = SanitizedTransaction::try_create(Cow::Owned(tx), message_hash).ok()?;
let tx = SanitizedTransaction::try_create(tx, message_hash, |_| {
Err(TransactionError::UnsupportedVersion)
})
.ok()?;
tx.verify_precompiles(libsecp256k1_0_5_upgrade_enabled)
.ok()?;
Some((tx, *tx_index))
})
.collect();
Expand Down Expand Up @@ -1565,12 +1566,12 @@ mod tests {
signature::{Keypair, Signer},
system_instruction::SystemError,
system_transaction,
transaction::TransactionError,
transaction::{Transaction, TransactionError},
};
use solana_streamer::socket::SocketAddrSpace;
use solana_transaction_status::TransactionWithStatusMeta;
use std::{
convert::TryInto,
convert::{TryFrom, TryInto},
net::SocketAddr,
path::Path,
sync::{
Expand Down Expand Up @@ -1794,7 +1795,7 @@ mod tests {
if !entries.is_empty() {
blockhash = entries.last().unwrap().hash;
for entry in entries {
bank.process_transactions(entry.transactions.iter())
bank.process_entry_transactions(entry.transactions)
.iter()
.for_each(|x| assert_eq!(*x, Ok(())));
}
Expand Down Expand Up @@ -1906,8 +1907,8 @@ mod tests {
.collect();

let bank = Bank::new_no_wallclock_throttle_for_tests(&genesis_config);
for entry in &entries {
bank.process_transactions(entry.transactions.iter())
for entry in entries {
bank.process_entry_transactions(entry.transactions)
.iter()
.for_each(|x| assert_eq!(*x, Ok(())));
}
Expand All @@ -1920,6 +1921,12 @@ mod tests {
Blockstore::destroy(&ledger_path).unwrap();
}

fn sanitize_transactions(txs: Vec<Transaction>) -> Vec<SanitizedTransaction> {
txs.into_iter()
.map(|tx| SanitizedTransaction::try_from(tx).unwrap())
.collect()
}

#[test]
fn test_bank_record_transactions() {
solana_logger::setup();
Expand Down Expand Up @@ -1964,20 +1971,15 @@ mod tests {
let keypair2 = Keypair::new();
let pubkey2 = solana_sdk::pubkey::new_rand();

let transactions = vec![
let txs = sanitize_transactions(vec![
system_transaction::transfer(&mint_keypair, &pubkey, 1, genesis_config.hash()),
system_transaction::transfer(&keypair2, &pubkey2, 1, genesis_config.hash()),
];
]);

let mut results = vec![(Ok(()), None), (Ok(()), None)];
let _ = BankingStage::record_transactions(
bank.slot(),
transactions.iter(),
&results,
&recorder,
);
let _ = BankingStage::record_transactions(bank.slot(), &txs, &results, &recorder);
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
assert_eq!(entry.transactions.len(), transactions.len());
assert_eq!(entry.transactions.len(), txs.len());

// InstructionErrors should still be recorded
results[0] = (
Expand All @@ -1987,39 +1989,27 @@ mod tests {
)),
None,
);
let (res, retryable) = BankingStage::record_transactions(
bank.slot(),
transactions.iter(),
&results,
&recorder,
);
let (res, retryable) =
BankingStage::record_transactions(bank.slot(), &txs, &results, &recorder);
res.unwrap();
assert!(retryable.is_empty());
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
assert_eq!(entry.transactions.len(), transactions.len());
assert_eq!(entry.transactions.len(), txs.len());

// Other TransactionErrors should not be recorded
results[0] = (Err(TransactionError::AccountNotFound), None);
let (res, retryable) = BankingStage::record_transactions(
bank.slot(),
transactions.iter(),
&results,
&recorder,
);
let (res, retryable) =
BankingStage::record_transactions(bank.slot(), &txs, &results, &recorder);
res.unwrap();
assert!(retryable.is_empty());
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
assert_eq!(entry.transactions.len(), transactions.len() - 1);
assert_eq!(entry.transactions.len(), txs.len() - 1);

// Once bank is set to a new bank (setting bank.slot() + 1 in record_transactions),
// record_transactions should throw MaxHeightReached and return the set of retryable
// txs
let (res, retryable) = BankingStage::record_transactions(
bank.slot() + 1,
transactions.iter(),
&results,
&recorder,
);
let (res, retryable) =
BankingStage::record_transactions(bank.slot() + 1, &txs, &results, &recorder);
assert_matches!(res, Err(PohRecorderError::MaxHeightReached));
// The first result was an error so it's filtered out. The second result was Ok(),
// so it should be marked as retryable
Expand Down
2 changes: 1 addition & 1 deletion core/src/broadcast_stage/broadcast_duplicates_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ impl BroadcastRun for BroadcastDuplicatesRun {
// Update the recent blockhash based on transactions in the entries
for entry in &receive_results.entries {
if !entry.transactions.is_empty() {
self.recent_blockhash = Some(entry.transactions[0].message.recent_blockhash);
self.recent_blockhash = Some(*entry.transactions[0].message.recent_blockhash());
break;
}
}
Expand Down
10 changes: 4 additions & 6 deletions core/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//!
use crate::execute_cost_table::ExecuteCostTable;
use log::*;
use solana_sdk::{pubkey::Pubkey, sanitized_transaction::SanitizedTransaction};
use solana_sdk::{pubkey::Pubkey, transaction::SanitizedTransaction};
use std::collections::HashMap;

// 07-27-2021, compute_unit to microsecond conversion ratio collected from mainnet-beta
Expand Down Expand Up @@ -141,7 +141,7 @@ impl CostModel {

// calculate account access cost
let message = transaction.message();
message.account_keys.iter().enumerate().for_each(|(i, k)| {
message.account_keys_iter().enumerate().for_each(|(i, k)| {
let is_signer = message.is_signer(i);
let is_writable = message.is_writable(i);

Expand Down Expand Up @@ -201,10 +201,8 @@ impl CostModel {
fn find_transaction_cost(&self, transaction: &SanitizedTransaction) -> u64 {
let mut cost: u64 = 0;

for instruction in &transaction.message().instructions {
let program_id =
transaction.message().account_keys[instruction.program_id_index as usize];
let instruction_cost = self.find_instruction_cost(&program_id);
for (program_id, instruction) in transaction.message().program_instructions_iter() {
let instruction_cost = self.find_instruction_cost(program_id);
trace!(
"instruction {:?} has cost of {}",
instruction,
Expand Down
2 changes: 1 addition & 1 deletion core/src/cost_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! - add_transaction_cost(&tx), mutable function to accumulate `tx` cost to tracker.
//!
use crate::cost_model::{CostModel, CostModelError, TransactionCost};
use solana_sdk::{clock::Slot, pubkey::Pubkey, sanitized_transaction::SanitizedTransaction};
use solana_sdk::{clock::Slot, pubkey::Pubkey, transaction::SanitizedTransaction};
use std::{
collections::HashMap,
sync::{Arc, RwLock},
Expand Down
Loading

0 comments on commit 679e7a2

Please sign in to comment.