Store versioned transactions in the ledger, disabled by default (#19139)

* Add support for versioned transactions, but disable by default

* merge conflicts

* trent's feedback

* bump Cargo.lock

* Fix transaction error encoding

* Rename legacy_transaction method

* cargo clippy

* Clean up casts, int arithmetic, and unused methods

* Check for duplicates in sanitized message conversion

* fix clippy

* fix new test

* Fix bpf conditional compilation for message module
This commit is contained in:
Justin Starry
2021-08-17 15:17:56 -07:00
committed by GitHub
parent 098e2b2de3
commit c50b01cb60
47 changed files with 2373 additions and 1049 deletions

View File

@ -47,10 +47,10 @@ use solana_sdk::{
native_token::{lamports_to_sol, sol_to_lamports, Sol},
pubkey::Pubkey,
rent::Rent,
sanitized_transaction::SanitizedTransaction,
shred_version::compute_shred_version,
stake::{self, state::StakeState},
system_program,
transaction::{SanitizedTransaction, TransactionError},
};
use solana_stake_program::stake_state::{self, PointValue};
use solana_vote_program::{
@ -58,7 +58,6 @@ use solana_vote_program::{
vote_state::{self, VoteState},
};
use std::{
borrow::Cow,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
ffi::OsStr,
fs::{self, File},
@ -121,7 +120,7 @@ fn output_entry(
method: &LedgerOutputMethod,
slot: Slot,
entry_index: usize,
entry: &Entry,
entry: Entry,
) {
match method {
LedgerOutputMethod::Print => {
@ -132,10 +131,11 @@ fn output_entry(
entry.hash,
entry.transactions.len()
);
for (transactions_index, transaction) in entry.transactions.iter().enumerate() {
for (transactions_index, transaction) in entry.transactions.into_iter().enumerate() {
println!(" Transaction {}", transactions_index);
let transaction_status = blockstore
.read_transaction_status((transaction.signatures[0], slot))
let tx_signature = transaction.signatures[0];
let tx_status = blockstore
.read_transaction_status((tx_signature, slot))
.unwrap_or_else(|err| {
eprintln!(
"Failed to read transaction status for {} at slot {}: {}",
@ -145,13 +145,16 @@ fn output_entry(
})
.map(|transaction_status| transaction_status.into());
solana_cli_output::display::println_transaction(
transaction,
&transaction_status,
" ",
None,
None,
);
if let Some(legacy_tx) = transaction.into_legacy_transaction() {
solana_cli_output::display::println_transaction(
&legacy_tx, &tx_status, " ", None, None,
);
} else {
eprintln!(
"Failed to print unsupported transaction for {} at slot {}",
tx_signature, slot
);
}
}
}
LedgerOutputMethod::Json => {
@ -199,7 +202,7 @@ fn output_slot(
}
if verbose_level >= 2 {
for (entry_index, entry) in entries.iter().enumerate() {
for (entry_index, entry) in entries.into_iter().enumerate() {
output_entry(blockstore, method, slot, entry_index, entry);
}
@ -208,26 +211,41 @@ fn output_slot(
let mut transactions = 0;
let mut hashes = 0;
let mut program_ids = HashMap::new();
for entry in &entries {
transactions += entry.transactions.len();
hashes += entry.num_hashes;
for transaction in &entry.transactions {
for instruction in &transaction.message().instructions {
let program_id =
transaction.message().account_keys[instruction.program_id_index as usize];
*program_ids.entry(program_id).or_insert(0) += 1;
}
}
}
let hash = if let Some(entry) = entries.last() {
let blockhash = if let Some(entry) = entries.last() {
entry.hash
} else {
Hash::default()
};
for entry in entries {
transactions += entry.transactions.len();
hashes += entry.num_hashes;
for transaction in entry.transactions {
let tx_signature = transaction.signatures[0];
let sanitize_result =
SanitizedTransaction::try_create(transaction, Hash::default(), |_| {
Err(TransactionError::UnsupportedVersion)
});
match sanitize_result {
Ok(transaction) => {
for (program_id, _) in transaction.message().program_instructions_iter() {
*program_ids.entry(*program_id).or_insert(0) += 1;
}
}
Err(err) => {
warn!(
"Failed to analyze unsupported transaction {}: {:?}",
tx_signature, err
);
}
}
}
}
println!(
" Transactions: {} hashes: {} block_hash: {}",
transactions, hashes, hash,
transactions, hashes, blockhash,
);
println!(" Programs: {:?}", program_ids);
}
@ -745,54 +763,56 @@ fn compute_slot_cost(blockstore: &Blockstore, slot: Slot) -> Result<(), String>
.get_slot_entries_with_shred_info(slot, 0, false)
.map_err(|err| format!(" Slot: {}, Failed to load entries, err {:?}", slot, err))?;
let mut transactions = 0;
let mut programs = 0;
let num_entries = entries.len();
let mut num_transactions = 0;
let mut num_programs = 0;
let mut program_ids = HashMap::new();
let mut cost_model = CostModel::default();
cost_model.initialize_cost_table(&blockstore.read_program_costs().unwrap());
let cost_model = Arc::new(RwLock::new(cost_model));
let mut cost_tracker = CostTracker::new(cost_model.clone());
for entry in &entries {
transactions += entry.transactions.len();
for entry in entries {
num_transactions += entry.transactions.len();
let mut cost_model = cost_model.write().unwrap();
for transaction in &entry.transactions {
programs += transaction.message().instructions.len();
let transaction =
match SanitizedTransaction::try_create(Cow::Borrowed(transaction), Hash::default())
entry
.transactions
.into_iter()
.filter_map(|transaction| {
SanitizedTransaction::try_create(transaction, Hash::default(), |_| {
Err(TransactionError::UnsupportedVersion)
})
.map_err(|err| {
warn!("Failed to compute cost of transaction: {:?}", err);
})
.ok()
})
.for_each(|transaction| {
num_programs += transaction.message().instructions().len();
let tx_cost = cost_model.calculate_cost(&transaction);
if cost_tracker.try_add(tx_cost).is_err() {
println!(
"Slot: {}, CostModel rejected transaction {:?}, stats {:?}!",
slot,
transaction,
cost_tracker.get_stats()
);
}
for (program_id, _instruction) in transaction.message().program_instructions_iter()
{
Ok(tx) => tx,
Err(err) => {
warn!(
"failed to sanitize transaction, err {:?}, tx {:?}",
err, transaction
);
continue;
}
};
let tx_cost = cost_model.calculate_cost(&transaction);
if cost_tracker.try_add(tx_cost).is_err() {
println!(
"Slot: {}, CostModel rejected transaction {:?}, stats {:?}!",
slot,
transaction,
cost_tracker.get_stats()
);
}
for instruction in &transaction.message().instructions {
let program_id =
transaction.message().account_keys[instruction.program_id_index as usize];
*program_ids.entry(program_id).or_insert(0) += 1;
}
}
*program_ids.entry(*program_id).or_insert(0) += 1;
}
});
}
println!(
"Slot: {}, Entries: {}, Transactions: {}, Programs {}, {:?}",
slot,
entries.len(),
transactions,
programs,
num_entries,
num_transactions,
num_programs,
cost_tracker.get_stats()
);
println!(" Programs: {:?}", program_ids);