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:
@ -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);
|
||||
|
Reference in New Issue
Block a user