From d52c56d8e02b7b27fe651ea953797c0748ce3f6f Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Wed, 21 Jun 2023 22:02:53 +0000 Subject: [PATCH 01/15] adding ATL support to bench-tps --- bench-tps/src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 0788181e85b6a1..940ebecd24193c 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -349,6 +349,13 @@ fn main() { *read_from_client_file, ); + // TAO NOTE - keypairs here have been generated and funded. Can use them in ATL extendtion + // if testing ATL, then + // 1. CreateATL + // 2. ExtendATL to num_of_accounts_in_atl, borrow keys funded above + // 3. return: atl_pubkey, and num_of_accounts_in_atl + // 4. pass them to do_bench_tps() so each TX going out will have atl in it. + let nonce_keypairs = if *use_durable_nonce { Some(generate_durable_nonce_accounts(client.clone(), &keypairs)) } else { From 1b72ff9ba5dba7692ca56798e6cabc668a3daaf8 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Thu, 22 Jun 2023 21:36:53 +0000 Subject: [PATCH 02/15] 1. create address-table-lookup account in test cluster if bench command requires it --- Cargo.lock | 1 + bench-tps/Cargo.toml | 1 + bench-tps/src/address_table_lookup.rs | 83 +++++++++++++++++++ bench-tps/src/bench_tps_client.rs | 2 + bench-tps/src/bench_tps_client/bank_client.rs | 4 + bench-tps/src/bench_tps_client/rpc_client.rs | 4 + bench-tps/src/bench_tps_client/thin_client.rs | 5 ++ bench-tps/src/bench_tps_client/tpu_client.rs | 4 + bench-tps/src/lib.rs | 1 + bench-tps/src/main.rs | 9 ++ 10 files changed, 114 insertions(+) create mode 100644 bench-tps/src/address_table_lookup.rs diff --git a/Cargo.lock b/Cargo.lock index bb7473a266a052..7fc25c70434c73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5184,6 +5184,7 @@ dependencies = [ "serde_json", "serde_yaml 0.9.21", "serial_test", + "solana-address-lookup-table-program", "solana-clap-utils", "solana-cli-config", "solana-client", diff --git a/bench-tps/Cargo.toml b/bench-tps/Cargo.toml index 803e820a5bd576..8c21be35427148 100644 --- a/bench-tps/Cargo.toml +++ b/bench-tps/Cargo.toml @@ -16,6 +16,7 @@ rand = { workspace = true } rayon = { workspace = true } serde_json = { workspace = true } serde_yaml = { workspace = true } +solana-address-lookup-table-program = { workspace = true } solana-clap-utils = { workspace = true } solana-cli-config = { workspace = true } solana-client = { workspace = true } diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs new file mode 100644 index 00000000000000..981748d188cab6 --- /dev/null +++ b/bench-tps/src/address_table_lookup.rs @@ -0,0 +1,83 @@ +use { + crate::{ + bench_tps_client::*, + cli::{Config, InstructionPaddingConfig}, + perf_utils::{sample_txs, SampleStats}, + send_batch::*, + }, + log::*, + rand::distributions::{Distribution, Uniform}, + rayon::prelude::*, + solana_address_lookup_table_program::{ + id, + instruction::{create_lookup_table,}, + state::AddressLookupTable, + }, + solana_client::{nonce_utils, rpc_request::MAX_MULTIPLE_ACCOUNTS}, + solana_metrics::{self, datapoint_info}, + solana_sdk::{ + account::Account, + clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, + commitment_config::CommitmentConfig, + compute_budget::ComputeBudgetInstruction, + hash::Hash, + instruction::{AccountMeta, Instruction}, + message::Message, + native_token::Sol, + pubkey::Pubkey, + signature::{Keypair, Signer}, + system_instruction, + timing::{duration_as_ms, duration_as_s, duration_as_us, timestamp}, + transaction::Transaction, + }, + std::{ + sync::{ + Arc, + }, + thread::sleep, + time::{Duration, Instant}, + }, +}; + +pub fn create_address_lookup_table_account( + client: Arc, + funding_key: &Keypair, + number_of_accounts_in_atl: usize, + keypairs: &Vec, +) /*-> Result<>*/ { + let recent_slot = client.get_slot().unwrap_or(0); + let (create_lookup_table_ix, lookup_table_address) = create_lookup_table( + funding_key.pubkey(), // authority + funding_key.pubkey(), // payer + recent_slot, // slot + ); + info!("==== {:?}, {:?}, {:?}", recent_slot, lookup_table_address, create_lookup_table_ix); + + { + let recent_blockhash = client.get_latest_blockhash().unwrap(); + let transaction = Transaction::new_signed_with_payer( + &[create_lookup_table_ix], + Some(&funding_key.pubkey()), + &[funding_key], + recent_blockhash, + ); + + info!("==== {:?}", transaction); + let tx_sig = client.send_transaction(transaction).unwrap(); + info!("==== {:?}", tx_sig); + + + // Sleep a few slots to allow transactions to process + sleep(Duration::from_secs(1)); + + // confirm tx + + let lookup_table_account = client + .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) + .unwrap(); + info!("==== {:?}", lookup_table_account); + let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + info!("==== {:?}", lookup_table); + } +} + diff --git a/bench-tps/src/bench_tps_client.rs b/bench-tps/src/bench_tps_client.rs index 3ab15bec11f7ee..feac7d88575dff 100644 --- a/bench-tps/src/bench_tps_client.rs +++ b/bench-tps/src/bench_tps_client.rs @@ -93,6 +93,8 @@ pub trait BenchTpsClient { ) -> Result; fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> Result>>; + + fn get_slot(&self) -> Result; } mod bank_client; diff --git a/bench-tps/src/bench_tps_client/bank_client.rs b/bench-tps/src/bench_tps_client/bank_client.rs index 1aef7284c01ed6..bdbd1ab6f1e4b3 100644 --- a/bench-tps/src/bench_tps_client/bank_client.rs +++ b/bench-tps/src/bench_tps_client/bank_client.rs @@ -111,4 +111,8 @@ impl BenchTpsClient for BankClient { fn get_multiple_accounts(&self, _pubkeys: &[Pubkey]) -> Result>> { unimplemented!("BankClient doesn't support get_multiple_accounts"); } + + fn get_slot(&self) -> Result { + SyncClient::get_slot(self).map_err(|err| err.into()) + } } diff --git a/bench-tps/src/bench_tps_client/rpc_client.rs b/bench-tps/src/bench_tps_client/rpc_client.rs index 57e97120d0b4af..fb61add6bcfa1d 100644 --- a/bench-tps/src/bench_tps_client/rpc_client.rs +++ b/bench-tps/src/bench_tps_client/rpc_client.rs @@ -103,4 +103,8 @@ impl BenchTpsClient for RpcClient { fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> Result>> { RpcClient::get_multiple_accounts(self, pubkeys).map_err(|err| err.into()) } + + fn get_slot(&self) -> Result { + RpcClient::get_slot(self).map_err(|err| err.into()) + } } diff --git a/bench-tps/src/bench_tps_client/thin_client.rs b/bench-tps/src/bench_tps_client/thin_client.rs index 6696774d679a8a..91fe5b86471ca3 100644 --- a/bench-tps/src/bench_tps_client/thin_client.rs +++ b/bench-tps/src/bench_tps_client/thin_client.rs @@ -110,4 +110,9 @@ impl BenchTpsClient for ThinClient { .get_multiple_accounts(pubkeys) .map_err(|err| err.into()) } + + fn get_slot(&self) -> Result { + SyncClient::get_slot(self).map_err(|err| err.into()) + } + } diff --git a/bench-tps/src/bench_tps_client/tpu_client.rs b/bench-tps/src/bench_tps_client/tpu_client.rs index ae762e52922ec5..b5e5895ee42751 100644 --- a/bench-tps/src/bench_tps_client/tpu_client.rs +++ b/bench-tps/src/bench_tps_client/tpu_client.rs @@ -127,4 +127,8 @@ where .get_multiple_accounts(pubkeys) .map_err(|err| err.into()) } + + fn get_slot(&self) -> Result { + self.rpc_client().get_slot().map_err(|err| err.into()) + } } diff --git a/bench-tps/src/lib.rs b/bench-tps/src/lib.rs index 5226b4e56f07d5..7371a07241b770 100644 --- a/bench-tps/src/lib.rs +++ b/bench-tps/src/lib.rs @@ -1,4 +1,5 @@ #![allow(clippy::integer_arithmetic)] +pub mod address_table_lookup; pub mod bench; pub mod bench_tps_client; pub mod cli; diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 940ebecd24193c..b70f59316a9d22 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -3,6 +3,7 @@ use { clap::value_t, log::*, solana_bench_tps::{ + address_table_lookup::{create_address_lookup_table_account,}, bench::{do_bench_tps, max_lamports_for_prioritization}, bench_tps_client::BenchTpsClient, cli::{self, ExternalClientType}, @@ -355,6 +356,14 @@ fn main() { // 2. ExtendATL to num_of_accounts_in_atl, borrow keys funded above // 3. return: atl_pubkey, and num_of_accounts_in_atl // 4. pass them to do_bench_tps() so each TX going out will have atl in it. + let number_of_accounts_in_atl = 64; + create_address_lookup_table_account( + client.clone(), + id, + number_of_accounts_in_atl, + &keypairs, + ); + return; let nonce_keypairs = if *use_durable_nonce { Some(generate_durable_nonce_accounts(client.clone(), &keypairs)) From 3648df7401c41bba44f1d113052711c7f5192831 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Thu, 22 Jun 2023 23:11:22 +0000 Subject: [PATCH 03/15] 2. populate address-table-lookup account with requested number of accounts, in multiple transactions, each within MTU limit; --- bench-tps/src/address_table_lookup.rs | 136 ++++++++++++------ bench-tps/src/bench_tps_client/thin_client.rs | 1 - bench-tps/src/main.rs | 13 +- 3 files changed, 96 insertions(+), 54 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index 981748d188cab6..e7ad7524021552 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -1,83 +1,131 @@ use { crate::{ bench_tps_client::*, - cli::{Config, InstructionPaddingConfig}, - perf_utils::{sample_txs, SampleStats}, - send_batch::*, }, log::*, - rand::distributions::{Distribution, Uniform}, - rayon::prelude::*, solana_address_lookup_table_program::{ - id, - instruction::{create_lookup_table,}, + instruction::{create_lookup_table, extend_lookup_table}, state::AddressLookupTable, }, - solana_client::{nonce_utils, rpc_request::MAX_MULTIPLE_ACCOUNTS}, - solana_metrics::{self, datapoint_info}, solana_sdk::{ - account::Account, - clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, commitment_config::CommitmentConfig, - compute_budget::ComputeBudgetInstruction, hash::Hash, - instruction::{AccountMeta, Instruction}, - message::Message, - native_token::Sol, pubkey::Pubkey, signature::{Keypair, Signer}, - system_instruction, - timing::{duration_as_ms, duration_as_s, duration_as_us, timestamp}, + slot_history::Slot, transaction::Transaction, }, std::{ - sync::{ - Arc, - }, + sync::Arc, thread::sleep, - time::{Duration, Instant}, + time::Duration, }, }; +// Number of pubkeys to be included in single extend_lookup_table transaction that not exceeds MTU +const NUMBER_OF_ADDRESSES_PER_EXTEND: usize = 16; + pub fn create_address_lookup_table_account( client: Arc, funding_key: &Keypair, - number_of_accounts_in_atl: usize, + num_addresses: usize, keypairs: &Vec, -) /*-> Result<>*/ { - let recent_slot = client.get_slot().unwrap_or(0); +) -> Result { + let (transaction, lookup_table_address) = build_create_lookup_table_tx( + funding_key, + client.get_slot().unwrap_or(0), + client.get_latest_blockhash().unwrap(), + ); + send_and_confirm_transaction(client.clone(), transaction, &lookup_table_address); + + let mut i: usize = 0; + while i < num_addresses { + let extend_num_addresses = NUMBER_OF_ADDRESSES_PER_EXTEND.min(num_addresses - i); + i += extend_num_addresses; + + let transaction = build_extend_lookup_table_tx( + &lookup_table_address, + funding_key, + extend_num_addresses, + client.get_latest_blockhash().unwrap(), + ); + send_and_confirm_transaction(client.clone(), transaction, &lookup_table_address); + } + + Ok(lookup_table_address) +} + +fn build_create_lookup_table_tx( + funding_key: &Keypair, + recent_slot: Slot, + recent_blockhash: Hash, +) -> (Transaction, Pubkey) { let (create_lookup_table_ix, lookup_table_address) = create_lookup_table( funding_key.pubkey(), // authority funding_key.pubkey(), // payer - recent_slot, // slot + recent_slot, // slot + ); + info!( + "==== {:?}, {:?}, {:?}", + recent_slot, lookup_table_address, create_lookup_table_ix ); - info!("==== {:?}, {:?}, {:?}", recent_slot, lookup_table_address, create_lookup_table_ix); - { - let recent_blockhash = client.get_latest_blockhash().unwrap(); - let transaction = Transaction::new_signed_with_payer( + ( + Transaction::new_signed_with_payer( &[create_lookup_table_ix], Some(&funding_key.pubkey()), &[funding_key], recent_blockhash, - ); + ), + lookup_table_address, + ) +} - info!("==== {:?}", transaction); - let tx_sig = client.send_transaction(transaction).unwrap(); - info!("==== {:?}", tx_sig); +fn build_extend_lookup_table_tx( + lookup_table_address: &Pubkey, + funding_key: &Keypair, + num_addresses: usize, + recent_blockhash: Hash, +) -> Transaction { + info!("==========================="); + let mut addresses = Vec::with_capacity(num_addresses); + // TODO - replace new_unique with keys from keypairs, + // Or maybe not necessary? Should log and check what accounts.rs does with new_unique + // keys when loading + addresses.resize_with(num_addresses, Pubkey::new_unique); + let extend_lookup_table_ix = extend_lookup_table( + *lookup_table_address, + funding_key.pubkey(), // authority + Some(funding_key.pubkey()), // payer + addresses, + ); + info!("==== {:?}", extend_lookup_table_ix); + Transaction::new_signed_with_payer( + &[extend_lookup_table_ix], + Some(&funding_key.pubkey()), + &[funding_key], + recent_blockhash, + ) +} - // Sleep a few slots to allow transactions to process - sleep(Duration::from_secs(1)); +fn send_and_confirm_transaction( + client: Arc, + transaction: Transaction, + lookup_table_address: &Pubkey, +) { + info!("==== {:?}", transaction); + let tx_sig = client.send_transaction(transaction).unwrap(); + info!("==== {:?}", tx_sig); - // confirm tx + // Sleep a few slots to allow transactions to process + sleep(Duration::from_secs(1)); - let lookup_table_account = client - .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) - .unwrap(); - info!("==== {:?}", lookup_table_account); - let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); - info!("==== {:?}", lookup_table); - } + // confirm tx + let lookup_table_account = client + .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) + .unwrap(); + info!("==== {:?}", lookup_table_account); + let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + info!("==== {:?}", lookup_table); } - diff --git a/bench-tps/src/bench_tps_client/thin_client.rs b/bench-tps/src/bench_tps_client/thin_client.rs index 91fe5b86471ca3..b70b189af4e5dc 100644 --- a/bench-tps/src/bench_tps_client/thin_client.rs +++ b/bench-tps/src/bench_tps_client/thin_client.rs @@ -114,5 +114,4 @@ impl BenchTpsClient for ThinClient { fn get_slot(&self) -> Result { SyncClient::get_slot(self).map_err(|err| err.into()) } - } diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index b70f59316a9d22..719f8e6186e320 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -3,7 +3,7 @@ use { clap::value_t, log::*, solana_bench_tps::{ - address_table_lookup::{create_address_lookup_table_account,}, + address_table_lookup::create_address_lookup_table_account, bench::{do_bench_tps, max_lamports_for_prioritization}, bench_tps_client::BenchTpsClient, cli::{self, ExternalClientType}, @@ -350,19 +350,14 @@ fn main() { *read_from_client_file, ); - // TAO NOTE - keypairs here have been generated and funded. Can use them in ATL extendtion + // TAO NOTE - keypairs here have been generated and funded. Can use them in ATL extendtion // if testing ATL, then // 1. CreateATL // 2. ExtendATL to num_of_accounts_in_atl, borrow keys funded above // 3. return: atl_pubkey, and num_of_accounts_in_atl // 4. pass them to do_bench_tps() so each TX going out will have atl in it. - let number_of_accounts_in_atl = 64; - create_address_lookup_table_account( - client.clone(), - id, - number_of_accounts_in_atl, - &keypairs, - ); + let number_of_accounts_in_atl = 72; + create_address_lookup_table_account(client.clone(), id, number_of_accounts_in_atl, &keypairs); return; let nonce_keypairs = if *use_durable_nonce { From 05c320f81c2c1d5052c79d84723698732ab627a8 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Fri, 23 Jun 2023 22:08:35 +0000 Subject: [PATCH 04/15] 3. Update bench transfer transaction to be VersionedTransaction, and V0 Message if transaction is going to use ATL; otherwise continue use Legacy Message; --- bench-tps/src/bench.rs | 57 ++++++++++++++----- bench-tps/src/bench_tps_client.rs | 5 +- bench-tps/src/bench_tps_client/bank_client.rs | 5 +- bench-tps/src/bench_tps_client/rpc_client.rs | 7 ++- bench-tps/src/bench_tps_client/thin_client.rs | 5 +- bench-tps/src/bench_tps_client/tpu_client.rs | 7 ++- bench-tps/src/main.rs | 1 - runtime/src/accounts.rs | 12 ++++ 8 files changed, 78 insertions(+), 21 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index d6444ebe4b41fb..4941d8192bc9e9 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -12,17 +12,18 @@ use { solana_metrics::{self, datapoint_info}, solana_sdk::{ account::Account, + address_lookup_table_account::AddressLookupTableAccount, clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::{AccountMeta, Instruction}, - message::Message, + message::{Message, VersionedMessage, v0,}, native_token::Sol, pubkey::Pubkey, signature::{Keypair, Signer}, system_instruction, timing::{duration_as_ms, duration_as_s, duration_as_us, timestamp}, - transaction::Transaction, + transaction::{Transaction, VersionedTransaction,}, }, spl_instruction_padding::instruction::wrap_instruction, std::{ @@ -70,7 +71,7 @@ pub fn max_lamports_for_prioritization(use_randomized_compute_unit_price: bool) // 32K page size, so it'd cost 0 extra CU. const TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE: u32 = 30 * 1024; -pub type TimestampedTransaction = (Transaction, Option); +pub type TimestampedTransaction = (VersionedTransaction, Option); pub type SharedTransactions = Arc>>>; /// Keypairs split into source and destination @@ -584,7 +585,7 @@ fn transfer_with_compute_unit_price_and_padding( recent_blockhash: Hash, instruction_padding_config: &Option, compute_unit_price: Option, -) -> Transaction { +) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); let instruction = if let Some(instruction_padding_config) = instruction_padding_config { @@ -610,8 +611,23 @@ fn transfer_with_compute_unit_price_and_padding( TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE, ), ]); - let message = Message::new(&instructions, Some(&from_pubkey)); - Transaction::new(&[from_keypair], message, recent_blockhash) + let versioned_transaction = VersionedTransaction::try_new( + //VersionedMessage::Legacy(Message::new_with_blockhash(&instructions, Some(&from_pubkey), &recent_blockhash)), + VersionedMessage::V0( + v0::Message::try_compile( + &from_pubkey, //payer + &instructions, + // TODO - taking from created ATL account + &[AddressLookupTableAccount {key: Pubkey::new_unique(), addresses: vec![],} ], + recent_blockhash, + ).unwrap() + ), + &[from_keypair], + ).unwrap(); + + info!("==== versioned_transaction {:?}", versioned_transaction); + + versioned_transaction } fn get_nonce_accounts( @@ -682,7 +698,7 @@ fn nonced_transfer_with_padding( nonce_authority: &Keypair, nonce_hash: Hash, instruction_padding_config: &Option, -) -> Transaction { +) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); let instruction = if let Some(instruction_padding_config) = instruction_padding_config { @@ -702,13 +718,24 @@ fn nonced_transfer_with_padding( TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE, ), ]); - let message = Message::new_with_nonce( - instructions, - Some(&from_pubkey), - nonce_account, - &nonce_authority.pubkey(), - ); - Transaction::new(&[from_keypair, nonce_authority], message, nonce_hash) + // TODO - using versionedTransaction + let versioned_nonce_transaction = VersionedTransaction::try_new( + VersionedMessage::Legacy( + Message::new_with_nonce( + instructions, + Some(&from_pubkey), + nonce_account, + &nonce_authority.pubkey(), + ) + ), + &[from_keypair], + ).unwrap(); + + info!("==== versioned_nonce_transaction {:?}", versioned_nonce_transaction); + + // TODO - need to sign the tx with + // nonce_hash + versioned_nonce_transaction } fn generate_nonced_system_txs( @@ -906,7 +933,7 @@ fn do_tx_transfers( ); } - if let Err(error) = client.send_batch(transactions) { + if let Err(error) = client.send_versioned_transaction_batch(transactions) { warn!("send_batch_sync in do_tx_transfers failed: {}", error); } diff --git a/bench-tps/src/bench_tps_client.rs b/bench-tps/src/bench_tps_client.rs index feac7d88575dff..0597b07fc64940 100644 --- a/bench-tps/src/bench_tps_client.rs +++ b/bench-tps/src/bench_tps_client.rs @@ -2,7 +2,7 @@ use { solana_rpc_client_api::client_error::Error as ClientError, solana_sdk::{ account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, transaction::Transaction, + message::Message, pubkey::Pubkey, signature::Signature, transaction::{Transaction, VersionedTransaction}, transport::TransportError, }, solana_tpu_client::tpu_client::TpuSenderError, @@ -34,6 +34,9 @@ pub trait BenchTpsClient { /// Send a batch of signed transactions without confirmation. fn send_batch(&self, transactions: Vec) -> Result<()>; + /// Send a batch of signed versioned transactions without confirmation. + fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()>; + /// Get latest blockhash fn get_latest_blockhash(&self) -> Result; diff --git a/bench-tps/src/bench_tps_client/bank_client.rs b/bench-tps/src/bench_tps_client/bank_client.rs index bdbd1ab6f1e4b3..8597e7c92beb28 100644 --- a/bench-tps/src/bench_tps_client/bank_client.rs +++ b/bench-tps/src/bench_tps_client/bank_client.rs @@ -10,7 +10,7 @@ use { message::Message, pubkey::Pubkey, signature::Signature, - transaction::Transaction, + transaction::{Transaction, VersionedTransaction,}, }, }; @@ -21,6 +21,9 @@ impl BenchTpsClient for BankClient { fn send_batch(&self, transactions: Vec) -> Result<()> { AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) } + fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { + AsyncClient::async_send_versioned_transaction_batch(self, transactions).map_err(|err| err.into()) + } fn get_latest_blockhash(&self) -> Result { SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) } diff --git a/bench-tps/src/bench_tps_client/rpc_client.rs b/bench-tps/src/bench_tps_client/rpc_client.rs index fb61add6bcfa1d..53e109c6cb0687 100644 --- a/bench-tps/src/bench_tps_client/rpc_client.rs +++ b/bench-tps/src/bench_tps_client/rpc_client.rs @@ -3,7 +3,8 @@ use { solana_rpc_client::rpc_client::RpcClient, solana_sdk::{ account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, transaction::Transaction, + message::Message, pubkey::Pubkey, signature::Signature, + transaction::{Transaction, VersionedTransaction,}, }, }; @@ -17,6 +18,10 @@ impl BenchTpsClient for RpcClient { } Ok(()) } + fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { + BenchTpsClient::send_versioned_transaction_batch(self, transactions)?; + Ok(()) + } fn get_latest_blockhash(&self) -> Result { RpcClient::get_latest_blockhash(self).map_err(|err| err.into()) } diff --git a/bench-tps/src/bench_tps_client/thin_client.rs b/bench-tps/src/bench_tps_client/thin_client.rs index b70b189af4e5dc..7634bbda4c8327 100644 --- a/bench-tps/src/bench_tps_client/thin_client.rs +++ b/bench-tps/src/bench_tps_client/thin_client.rs @@ -10,7 +10,7 @@ use { message::Message, pubkey::Pubkey, signature::Signature, - transaction::Transaction, + transaction::{Transaction, VersionedTransaction,}, }, }; @@ -21,6 +21,9 @@ impl BenchTpsClient for ThinClient { fn send_batch(&self, transactions: Vec) -> Result<()> { AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) } + fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { + AsyncClient::async_send_versioned_transaction_batch(self, transactions).map_err(|err| err.into()) + } fn get_latest_blockhash(&self) -> Result { SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) } diff --git a/bench-tps/src/bench_tps_client/tpu_client.rs b/bench-tps/src/bench_tps_client/tpu_client.rs index b5e5895ee42751..1a85167e74113c 100644 --- a/bench-tps/src/bench_tps_client/tpu_client.rs +++ b/bench-tps/src/bench_tps_client/tpu_client.rs @@ -4,7 +4,8 @@ use { solana_connection_cache::connection_cache::{ConnectionManager, ConnectionPool}, solana_sdk::{ account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, transaction::Transaction, + message::Message, pubkey::Pubkey, signature::Signature, + transaction::{Transaction, VersionedTransaction,}, }, }; @@ -22,6 +23,10 @@ where self.try_send_transaction_batch(&transactions)?; Ok(()) } + fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { + BenchTpsClient::send_versioned_transaction_batch(self, transactions)?; + Ok(()) + } fn get_latest_blockhash(&self) -> Result { self.rpc_client() .get_latest_blockhash() diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 719f8e6186e320..cd9452235a98f4 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -358,7 +358,6 @@ fn main() { // 4. pass them to do_bench_tps() so each TX going out will have atl in it. let number_of_accounts_in_atl = 72; create_address_lookup_table_account(client.clone(), id, number_of_accounts_in_atl, &keypairs); - return; let nonce_keypairs = if *use_durable_nonce { Some(generate_durable_nonce_accounts(client.clone(), &keypairs)) diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index d12f5405ad2c19..1b91570bd42bef 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -781,17 +781,26 @@ impl Accounts { address_table_lookup: &MessageAddressTableLookup, slot_hashes: &SlotHashes, ) -> std::result::Result { + + debug!("load_lookup_table_addresses, address_table_lookup {:?}", address_table_lookup); + let table_account = self .accounts_db .load_with_fixed_root(ancestors, &address_table_lookup.account_key) .map(|(account, _rent)| account) .ok_or(AddressLookupError::LookupTableAccountNotFound)?; + + debug!("load_lookup_table_addresses, table_account {:?}", table_account); + if table_account.owner() == &solana_address_lookup_table_program::id() { let current_slot = ancestors.max_slot(); let lookup_table = AddressLookupTable::deserialize(table_account.data()) .map_err(|_ix_err| AddressLookupError::InvalidAccountData)?; + + debug!("load_lookup_table_addresses, lookup_table {:?}", lookup_table); + Ok(LoadedAddresses { writable: lookup_table.lookup( current_slot, @@ -805,6 +814,9 @@ impl Accounts { )?, }) } else { + + debug!("load_lookup_table_addresses, InvalidAccountOwner"); + Err(AddressLookupError::InvalidAccountOwner) } } From 75feb6e0c20d3a8c2aa9a7b65555f81b5ecae417 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Sat, 24 Jun 2023 00:43:41 +0000 Subject: [PATCH 05/15] 4. Add a bpf instruction to bench Transfer tansaction that loads all requested accounts from ATL; --- bench-tps/src/address_table_lookup.rs | 6 --- bench-tps/src/bench.rs | 68 +++++++++++++++++++++++---- bench-tps/src/main.rs | 6 ++- runtime/src/accounts.rs | 12 +---- runtime/src/bank.rs | 6 +++ 5 files changed, 71 insertions(+), 27 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index e7ad7524021552..50cf4028980e4d 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -65,10 +65,6 @@ fn build_create_lookup_table_tx( funding_key.pubkey(), // payer recent_slot, // slot ); - info!( - "==== {:?}, {:?}, {:?}", - recent_slot, lookup_table_address, create_lookup_table_ix - ); ( Transaction::new_signed_with_payer( @@ -87,7 +83,6 @@ fn build_extend_lookup_table_tx( num_addresses: usize, recent_blockhash: Hash, ) -> Transaction { - info!("==========================="); let mut addresses = Vec::with_capacity(num_addresses); // TODO - replace new_unique with keys from keypairs, // Or maybe not necessary? Should log and check what accounts.rs does with new_unique @@ -99,7 +94,6 @@ fn build_extend_lookup_table_tx( Some(funding_key.pubkey()), // payer addresses, ); - info!("==== {:?}", extend_lookup_table_ix); Transaction::new_signed_with_payer( &[extend_lookup_table_ix], diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 4941d8192bc9e9..63b7a10e1d6f9f 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -8,12 +8,16 @@ use { log::*, rand::distributions::{Distribution, Uniform}, rayon::prelude::*, + solana_address_lookup_table_program::{ + state::AddressLookupTable, + }, solana_client::{nonce_utils, rpc_request::MAX_MULTIPLE_ACCOUNTS}, solana_metrics::{self, datapoint_info}, solana_sdk::{ account::Account, address_lookup_table_account::AddressLookupTableAccount, clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, + commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::{AccountMeta, Instruction}, @@ -49,7 +53,7 @@ const MAX_TX_QUEUE_AGE: u64 = (MAX_PROCESSING_AGE as f64 * DEFAULT_S_PER_SLOT) a // `TRANSFER_TRANSACTION_COMPUTE_UNIT * MAX_COMPUTE_UNIT_PRICE * COMPUTE_UNIT_PRICE_MULTIPLIER / 1_000_000` const MAX_COMPUTE_UNIT_PRICE: u64 = 50; const COMPUTE_UNIT_PRICE_MULTIPLIER: u64 = 1_000; -const TRANSFER_TRANSACTION_COMPUTE_UNIT: u32 = 600; // 1 transfer is plus 3 compute_budget ixs +const TRANSFER_TRANSACTION_COMPUTE_UNIT: u32 = 600 + 10; // 1 transfer is plus 3 compute_budget ixs; //TODO added 10 to use noop ix to fool runtime /// calculate maximum possible prioritization fee, if `use-randomized-compute-unit-price` is /// enabled, round to nearest lamports. pub fn max_lamports_for_prioritization(use_randomized_compute_unit_price: bool) -> u64 { @@ -123,6 +127,7 @@ struct TransactionChunkGenerator<'a, 'b, T: ?Sized> { reclaim_lamports_back_to_source_account: bool, use_randomized_compute_unit_price: bool, instruction_padding_config: Option, + lookup_table_address: Option, } impl<'a, 'b, T> TransactionChunkGenerator<'a, 'b, T> @@ -137,6 +142,7 @@ where use_randomized_compute_unit_price: bool, instruction_padding_config: Option, num_conflict_groups: Option, + lookup_table_address: Option, ) -> Self { let account_chunks = if let Some(num_conflict_groups) = num_conflict_groups { KeypairChunks::new_with_conflict_groups(gen_keypairs, chunk_size, num_conflict_groups) @@ -154,6 +160,7 @@ where reclaim_lamports_back_to_source_account: false, use_randomized_compute_unit_price, instruction_padding_config, + lookup_table_address, } } @@ -167,6 +174,20 @@ where ); let signing_start = Instant::now(); + let address_lookup_table_account = self.lookup_table_address.and_then(|lookup_table_address| { + let lookup_table_account = self.client + .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) + .unwrap(); + info!("==== {:?}", lookup_table_account); + let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + info!("==== {:?}", lookup_table); + Some(AddressLookupTableAccount { + key: lookup_table_address, + addresses: lookup_table.addresses.to_vec(), + }) + }); + info!("==== address_lookup_table_account {:?}", address_lookup_table_account); + let source_chunk = &self.account_chunks.source[self.chunk_index]; let dest_chunk = &self.account_chunks.dest[self.chunk_index]; let transactions = if let Some(nonce_chunks) = &self.nonce_chunks { @@ -190,6 +211,7 @@ where blockhash.unwrap(), &self.instruction_padding_config, self.use_randomized_compute_unit_price, + &address_lookup_table_account, ) }; @@ -368,6 +390,7 @@ pub fn do_bench_tps( config: Config, gen_keypairs: Vec, nonce_keypairs: Option>, + lookup_table_address: Option, ) -> u64 where T: 'static + BenchTpsClient + Send + Sync + ?Sized, @@ -396,6 +419,7 @@ where use_randomized_compute_unit_price, instruction_padding_config, num_conflict_groups, + lookup_table_address, ); let first_tx_count = loop { @@ -522,6 +546,7 @@ fn generate_system_txs( blockhash: &Hash, instruction_padding_config: &Option, use_randomized_compute_unit_price: bool, + address_lookup_table_account: &Option, ) -> Vec { let pairs: Vec<_> = if !reclaim { source.iter().zip(dest.iter()).collect() @@ -553,6 +578,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, Some(**compute_unit_price), + address_lookup_table_account, ), Some(timestamp()), ) @@ -570,6 +596,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, None, + address_lookup_table_account, ), Some(timestamp()), ) @@ -585,6 +612,7 @@ fn transfer_with_compute_unit_price_and_padding( recent_blockhash: Hash, instruction_padding_config: &Option, compute_unit_price: Option, + address_lookup_table_account: &Option, ) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); @@ -611,18 +639,43 @@ fn transfer_with_compute_unit_price_and_padding( TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE, ), ]); - let versioned_transaction = VersionedTransaction::try_new( - //VersionedMessage::Legacy(Message::new_with_blockhash(&instructions, Some(&from_pubkey), &recent_blockhash)), + + let versioned_message = if let Some(address_lookup_table_account) = address_lookup_table_account { + let address_lookup_table_account_clone = address_lookup_table_account.clone(); + let address_lookup_table_accounts = vec![address_lookup_table_account_clone]; + + // TAO NOTE - add fake IX to force load all accounts in ATL + // however the transaction will fail to execute (solana_runtime::bank] tx error: + // ProgramAccountNotFound), so the transfers wont land, so the bench results are invalid. + // TODO - need to either create the fake program account, mark it executable and hope it + // allows successful execution; OR hack the runtime to ignore this program pubkey (since + // the bench test doesn't concern execution; OR ask on Discord to see if any program + // available to load many accounts without executing anything. + let account_metas: Vec<_> = address_lookup_table_account.addresses.iter().map(|pubkey| { + AccountMeta::new(pubkey.clone(), false) + }).collect(); + //let noop_key_string = "11111111111111111111111111111111"; + let noop_key_string = "FbXmsPdGqmSPrtbPCuvX16SEWqA3w6Ee16wu6jucFZuG"; + let noop_key = noop_key_string.parse::().unwrap(); //Pubkey::new_unique() + instructions.extend_from_slice(&[ + Instruction::new_with_bincode(noop_key, &(), + account_metas, + ), + ]); + VersionedMessage::V0( v0::Message::try_compile( &from_pubkey, //payer &instructions, - // TODO - taking from created ATL account - &[AddressLookupTableAccount {key: Pubkey::new_unique(), addresses: vec![],} ], + &address_lookup_table_accounts, recent_blockhash, ).unwrap() - ), - &[from_keypair], + ) + } else { + VersionedMessage::Legacy(Message::new_with_blockhash(&instructions, Some(&from_pubkey), &recent_blockhash)) + }; + let versioned_transaction = VersionedTransaction::try_new( + versioned_message, &[from_keypair], ).unwrap(); info!("==== versioned_transaction {:?}", versioned_transaction); @@ -718,7 +771,6 @@ fn nonced_transfer_with_padding( TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE, ), ]); - // TODO - using versionedTransaction let versioned_nonce_transaction = VersionedTransaction::try_new( VersionedMessage::Legacy( Message::new_with_nonce( diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index cd9452235a98f4..b6c78c871336b1 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -356,13 +356,15 @@ fn main() { // 2. ExtendATL to num_of_accounts_in_atl, borrow keys funded above // 3. return: atl_pubkey, and num_of_accounts_in_atl // 4. pass them to do_bench_tps() so each TX going out will have atl in it. + // TODO - taking from cli arg let number_of_accounts_in_atl = 72; - create_address_lookup_table_account(client.clone(), id, number_of_accounts_in_atl, &keypairs); + // TODO - only creates ATL if cli arg is used, otherwise pass None + let lookup_table_address = create_address_lookup_table_account(client.clone(), id, number_of_accounts_in_atl, &keypairs).ok(); let nonce_keypairs = if *use_durable_nonce { Some(generate_durable_nonce_accounts(client.clone(), &keypairs)) } else { None }; - do_bench_tps(client, cli_config, keypairs, nonce_keypairs); + do_bench_tps(client, cli_config, keypairs, nonce_keypairs, lookup_table_address); } diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 1b91570bd42bef..e40a053667d98a 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -781,25 +781,18 @@ impl Accounts { address_table_lookup: &MessageAddressTableLookup, slot_hashes: &SlotHashes, ) -> std::result::Result { - - debug!("load_lookup_table_addresses, address_table_lookup {:?}", address_table_lookup); - let table_account = self .accounts_db .load_with_fixed_root(ancestors, &address_table_lookup.account_key) .map(|(account, _rent)| account) .ok_or(AddressLookupError::LookupTableAccountNotFound)?; - - debug!("load_lookup_table_addresses, table_account {:?}", table_account); - if table_account.owner() == &solana_address_lookup_table_program::id() { let current_slot = ancestors.max_slot(); let lookup_table = AddressLookupTable::deserialize(table_account.data()) .map_err(|_ix_err| AddressLookupError::InvalidAccountData)?; - - debug!("load_lookup_table_addresses, lookup_table {:?}", lookup_table); + debug!("==== load_lookup_table_addresses, lookup_table {:?}", lookup_table); Ok(LoadedAddresses { writable: lookup_table.lookup( @@ -814,9 +807,6 @@ impl Accounts { )?, }) } else { - - debug!("load_lookup_table_addresses, InvalidAccountOwner"); - Err(AddressLookupError::InvalidAccountOwner) } } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c65e3da439c322..63fce49bbf38f3 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -6049,6 +6049,12 @@ impl Bank { counts: CommitTransactionCounts, timings: &mut ExecuteTimings, ) -> TransactionResults { + // TAO TODO - remove the print + execution_results.iter().zip(sanitized_txs).for_each(|(execution_result, tx)| { + debug!("==== tx_sig {:?}, execution_result {:?}", tx.signature(), execution_result); + }); + + assert!( !self.freeze_started(), "commit_transactions() working on a bank that is already frozen or is undergoing freezing!" From 9d078132800add40bdf51d46c3039cd2c96b8c49 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Sun, 25 Jun 2023 17:56:09 +0000 Subject: [PATCH 06/15] 5. add cli arg to specify number of accounts to load from ATL --- bench-tps/src/bench.rs | 12 +++++++++++- bench-tps/src/cli.rs | 16 ++++++++++++++++ bench-tps/src/main.rs | 15 ++------------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 63b7a10e1d6f9f..a1e73ca2091d8e 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -1,5 +1,6 @@ use { crate::{ + address_table_lookup::create_address_lookup_table_account, bench_tps_client::*, cli::{Config, InstructionPaddingConfig}, perf_utils::{sample_txs, SampleStats}, @@ -390,7 +391,6 @@ pub fn do_bench_tps( config: Config, gen_keypairs: Vec, nonce_keypairs: Option>, - lookup_table_address: Option, ) -> u64 where T: 'static + BenchTpsClient + Send + Sync + ?Sized, @@ -407,9 +407,19 @@ where use_durable_nonce, instruction_padding_config, num_conflict_groups, + number_of_accounts_from_address_lookup_table, .. } = config; + // if --number_of_accounts_from_address_lookup_table is used, creates Lookup Table account, + // then extend it with spepcified number of account. + // All bench transfer transactions will include a `noop` instruction to load + // number_of_accounts_from_address_lookup_table from Lookup Table account as writable accounts. + // TODO - add `noop` program id to cli, and make it dependent with --number_of_accounts_from_address_lookup_table + let lookup_table_address = number_of_accounts_from_address_lookup_table.and_then(|number_of_accounts_from_address_lookup_table| { + create_address_lookup_table_account(client.clone(), &id, number_of_accounts_from_address_lookup_table, &gen_keypairs).ok() + }); + assert!(gen_keypairs.len() >= 2 * tx_count); let chunk_generator = TransactionChunkGenerator::new( client.clone(), diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 9acf1e74ce3c70..28dc8ac687efb2 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -74,6 +74,7 @@ pub struct Config { pub num_conflict_groups: Option, pub bind_address: IpAddr, pub client_node_id: Option, + pub number_of_accounts_from_address_lookup_table: Option, } impl Eq for Config {} @@ -109,6 +110,7 @@ impl Default for Config { num_conflict_groups: None, bind_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), client_node_id: None, + number_of_accounts_from_address_lookup_table: None, } } } @@ -382,6 +384,13 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .validator(is_keypair) .help("File containing the node identity (keypair) of a validator with active stake. This allows communicating with network using staked connection"), ) + .arg( + Arg::with_name("number_of_accounts_from_address_lookup_table") + .long("number-of-accounts-from-address-lookup-table") + .takes_value(true) + .validator(|arg| is_within_range(arg, 0..)) + .help("The additional number of accounts bench TPS transaction to load from address-lookup-table, use it to bench number of account per transaction") + ) } /// Parses a clap `ArgMatches` structure into a `Config` @@ -557,6 +566,13 @@ pub fn parse_args(matches: &ArgMatches) -> Result { args.client_node_id = Some(client_node_id); } + if let Some(number_of_accounts_from_address_lookup_table) = matches.value_of("number_of_accounts_from_address_lookup_table") { + let parsed_number_of_accounts_from_address_lookup_table = number_of_accounts_from_address_lookup_table + .parse() + .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; + args.number_of_accounts_from_address_lookup_table = Some(parsed_number_of_accounts_from_address_lookup_table); + } + Ok(args) } diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index b6c78c871336b1..4fabb10043d174 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -3,7 +3,6 @@ use { clap::value_t, log::*, solana_bench_tps::{ - address_table_lookup::create_address_lookup_table_account, bench::{do_bench_tps, max_lamports_for_prioritization}, bench_tps_client::BenchTpsClient, cli::{self, ExternalClientType}, @@ -257,6 +256,7 @@ fn main() { instruction_padding_config, bind_address, client_node_id, + number_of_accounts_from_address_lookup_table, .. } = &cli_config; @@ -350,21 +350,10 @@ fn main() { *read_from_client_file, ); - // TAO NOTE - keypairs here have been generated and funded. Can use them in ATL extendtion - // if testing ATL, then - // 1. CreateATL - // 2. ExtendATL to num_of_accounts_in_atl, borrow keys funded above - // 3. return: atl_pubkey, and num_of_accounts_in_atl - // 4. pass them to do_bench_tps() so each TX going out will have atl in it. - // TODO - taking from cli arg - let number_of_accounts_in_atl = 72; - // TODO - only creates ATL if cli arg is used, otherwise pass None - let lookup_table_address = create_address_lookup_table_account(client.clone(), id, number_of_accounts_in_atl, &keypairs).ok(); - let nonce_keypairs = if *use_durable_nonce { Some(generate_durable_nonce_accounts(client.clone(), &keypairs)) } else { None }; - do_bench_tps(client, cli_config, keypairs, nonce_keypairs, lookup_table_address); + do_bench_tps(client, cli_config, keypairs, nonce_keypairs); } From 83cea1b94447fe05c5aa4f473e1a2f471957defc Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Mon, 26 Jun 2023 17:47:15 +0000 Subject: [PATCH 07/15] add sbf_program_pubkey that loads accounts from ATL to cli --- Cargo.lock | 1 + bench-tps/Cargo.toml | 1 + bench-tps/src/bench.rs | 51 ++++++++++++++++++------------------------ bench-tps/src/cli.rs | 46 +++++++++++++++++++++++++++---------- bench-tps/src/main.rs | 2 +- 5 files changed, 59 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fc25c70434c73..021075e8425072 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5178,6 +5178,7 @@ version = "1.17.0" dependencies = [ "clap 2.33.3", "crossbeam-channel", + "itertools", "log", "rand 0.7.3", "rayon", diff --git a/bench-tps/Cargo.toml b/bench-tps/Cargo.toml index 8c21be35427148..b2fe285f4b0654 100644 --- a/bench-tps/Cargo.toml +++ b/bench-tps/Cargo.toml @@ -11,6 +11,7 @@ edition = { workspace = true } [dependencies] clap = { workspace = true } crossbeam-channel = { workspace = true } +itertools = { workspace = true } log = { workspace = true } rand = { workspace = true } rayon = { workspace = true } diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index a1e73ca2091d8e..2870ce7e23fc94 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -128,7 +128,7 @@ struct TransactionChunkGenerator<'a, 'b, T: ?Sized> { reclaim_lamports_back_to_source_account: bool, use_randomized_compute_unit_price: bool, instruction_padding_config: Option, - lookup_table_address: Option, + lookup_table_address: Option<(Pubkey, Pubkey)>, } impl<'a, 'b, T> TransactionChunkGenerator<'a, 'b, T> @@ -143,7 +143,7 @@ where use_randomized_compute_unit_price: bool, instruction_padding_config: Option, num_conflict_groups: Option, - lookup_table_address: Option, + lookup_table_address: Option<(Pubkey, Pubkey)>, ) -> Self { let account_chunks = if let Some(num_conflict_groups) = num_conflict_groups { KeypairChunks::new_with_conflict_groups(gen_keypairs, chunk_size, num_conflict_groups) @@ -175,17 +175,20 @@ where ); let signing_start = Instant::now(); - let address_lookup_table_account = self.lookup_table_address.and_then(|lookup_table_address| { + let address_lookup_table_account = self.lookup_table_address.and_then(|(lookup_table_address, sbf_program_id)| { let lookup_table_account = self.client .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) .unwrap(); info!("==== {:?}", lookup_table_account); let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); info!("==== {:?}", lookup_table); - Some(AddressLookupTableAccount { - key: lookup_table_address, - addresses: lookup_table.addresses.to_vec(), - }) + Some(( + AddressLookupTableAccount { + key: lookup_table_address, + addresses: lookup_table.addresses.to_vec(), + }, + sbf_program_id, + )) }); info!("==== address_lookup_table_account {:?}", address_lookup_table_account); @@ -407,17 +410,17 @@ where use_durable_nonce, instruction_padding_config, num_conflict_groups, - number_of_accounts_from_address_lookup_table, + load_accounts_from_address_lookup_table, .. } = config; - // if --number_of_accounts_from_address_lookup_table is used, creates Lookup Table account, - // then extend it with spepcified number of account. - // All bench transfer transactions will include a `noop` instruction to load - // number_of_accounts_from_address_lookup_table from Lookup Table account as writable accounts. - // TODO - add `noop` program id to cli, and make it dependent with --number_of_accounts_from_address_lookup_table - let lookup_table_address = number_of_accounts_from_address_lookup_table.and_then(|number_of_accounts_from_address_lookup_table| { - create_address_lookup_table_account(client.clone(), &id, number_of_accounts_from_address_lookup_table, &gen_keypairs).ok() + // if --load_accounts_from_address_lookup_table is used, creates Lookup Table account, + // then extend it with spepcified number of account. + // All bench transfer transactions will include a `sbf_program_id` instruction to load + // specified number of accounts from Lookup Table account as writable accounts. + let lookup_table_address = load_accounts_from_address_lookup_table.and_then(|(sbf_program_id, number_of_accounts)| { + let lookup_table_account = create_address_lookup_table_account(client.clone(), &id, number_of_accounts, &gen_keypairs).unwrap(); + Some((lookup_table_account, sbf_program_id)) }); assert!(gen_keypairs.len() >= 2 * tx_count); @@ -556,7 +559,7 @@ fn generate_system_txs( blockhash: &Hash, instruction_padding_config: &Option, use_randomized_compute_unit_price: bool, - address_lookup_table_account: &Option, + address_lookup_table_account: &Option<(AddressLookupTableAccount, Pubkey)>, ) -> Vec { let pairs: Vec<_> = if !reclaim { source.iter().zip(dest.iter()).collect() @@ -622,7 +625,7 @@ fn transfer_with_compute_unit_price_and_padding( recent_blockhash: Hash, instruction_padding_config: &Option, compute_unit_price: Option, - address_lookup_table_account: &Option, + address_lookup_table_account: &Option<(AddressLookupTableAccount, Pubkey)>, ) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); @@ -650,25 +653,15 @@ fn transfer_with_compute_unit_price_and_padding( ), ]); - let versioned_message = if let Some(address_lookup_table_account) = address_lookup_table_account { + let versioned_message = if let Some((address_lookup_table_account, sbf_program_id)) = address_lookup_table_account { let address_lookup_table_account_clone = address_lookup_table_account.clone(); let address_lookup_table_accounts = vec![address_lookup_table_account_clone]; - // TAO NOTE - add fake IX to force load all accounts in ATL - // however the transaction will fail to execute (solana_runtime::bank] tx error: - // ProgramAccountNotFound), so the transfers wont land, so the bench results are invalid. - // TODO - need to either create the fake program account, mark it executable and hope it - // allows successful execution; OR hack the runtime to ignore this program pubkey (since - // the bench test doesn't concern execution; OR ask on Discord to see if any program - // available to load many accounts without executing anything. let account_metas: Vec<_> = address_lookup_table_account.addresses.iter().map(|pubkey| { AccountMeta::new(pubkey.clone(), false) }).collect(); - //let noop_key_string = "11111111111111111111111111111111"; - let noop_key_string = "FbXmsPdGqmSPrtbPCuvX16SEWqA3w6Ee16wu6jucFZuG"; - let noop_key = noop_key_string.parse::().unwrap(); //Pubkey::new_unique() instructions.extend_from_slice(&[ - Instruction::new_with_bincode(noop_key, &(), + Instruction::new_with_bincode(sbf_program_id.clone(), &(), account_metas, ), ]); diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 28dc8ac687efb2..7cca026a0d79b2 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -1,8 +1,11 @@ use { clap::{crate_description, crate_name, App, Arg, ArgMatches}, + itertools::Itertools, solana_clap_utils::{ hidden_unless_forced, - input_validators::{is_keypair, is_url, is_url_or_moniker, is_within_range}, + input_validators::{ + is_keypair, is_url, is_url_or_moniker, is_within_range, + }, }, solana_cli_config::{ConfigInput, CONFIG_FILE}, solana_sdk::{ @@ -74,7 +77,7 @@ pub struct Config { pub num_conflict_groups: Option, pub bind_address: IpAddr, pub client_node_id: Option, - pub number_of_accounts_from_address_lookup_table: Option, + pub load_accounts_from_address_lookup_table: Option<(Pubkey, usize)>, } impl Eq for Config {} @@ -110,7 +113,7 @@ impl Default for Config { num_conflict_groups: None, bind_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), client_node_id: None, - number_of_accounts_from_address_lookup_table: None, + load_accounts_from_address_lookup_table: None, } } } @@ -385,11 +388,21 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .help("File containing the node identity (keypair) of a validator with active stake. This allows communicating with network using staked connection"), ) .arg( - Arg::with_name("number_of_accounts_from_address_lookup_table") - .long("number-of-accounts-from-address-lookup-table") + Arg::with_name("load_accounts_from_address_lookup_table") + .long("load-accounts-from-address-lookup-table") + .value_names(&["SBF_PROGRAM_PUBKEY", "NUMBER_OF_ACCOUNTS_TO_LOAD"]) .takes_value(true) - .validator(|arg| is_within_range(arg, 0..)) - .help("The additional number of accounts bench TPS transaction to load from address-lookup-table, use it to bench number of account per transaction") + .number_of_values(2) + .multiple(true) + .help( + "Specify a SBF program to load number of accounts from ATL in bench-tps Transfer transaction; \ + When thhis argument is used, bench-tps creates a address-lookup account with NUMBER_OF_ACCOUNTS_TO_LOAD\ + accounts in test cluster, then sends VersionedTransaction with V0 message includes a instruction\ + that load all accounts from ATL by program of SBF_PROGRAM_PUBKEY; \ + Otherwise, bench-tps creates VersionedTransaction with LegacyMessage without using ATL;\ + 1st parameter is a pubkey string of SBF program to be used;\ + 2nd parameter is the number of accounts to be loaded by the SBF program from ATL.", + ), ) } @@ -566,11 +579,20 @@ pub fn parse_args(matches: &ArgMatches) -> Result { args.client_node_id = Some(client_node_id); } - if let Some(number_of_accounts_from_address_lookup_table) = matches.value_of("number_of_accounts_from_address_lookup_table") { - let parsed_number_of_accounts_from_address_lookup_table = number_of_accounts_from_address_lookup_table - .parse() - .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; - args.number_of_accounts_from_address_lookup_table = Some(parsed_number_of_accounts_from_address_lookup_table); + if let Some(values) = matches.values_of("load_accounts_from_address_lookup_table") { + for (sbf_program_pubkey_string, number_of_accounts) in values.into_iter().tuples() { + let sbf_program_pubkey = sbf_program_pubkey_string.parse::().map_err(|_| "Can't parse pubkey string")?; + let parsed_number_of_accounts = number_of_accounts + .parse() + .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; + // TODO - remove log + log::info!("==== instruct {:?} to load {:?} accounts from from ATL", sbf_program_pubkey, parsed_number_of_accounts); + // NOTE - support multiple ATL IXs later + args.load_accounts_from_address_lookup_table = Some(( + sbf_program_pubkey, + parsed_number_of_accounts, + )); + } } Ok(args) diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 4fabb10043d174..83da26bc7ef7f6 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -256,7 +256,7 @@ fn main() { instruction_padding_config, bind_address, client_node_id, - number_of_accounts_from_address_lookup_table, + load_accounts_from_address_lookup_table, .. } = &cli_config; From 49b9ac6ca99a13e8be14ef7a9be5594d3fa9cc76 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Mon, 26 Jun 2023 22:22:29 +0000 Subject: [PATCH 08/15] some clean up --- bench-tps/src/address_table_lookup.rs | 22 +-- bench-tps/src/bench.rs | 128 ++++++++++-------- bench-tps/src/bench_tps_client.rs | 15 +- bench-tps/src/bench_tps_client/bank_client.rs | 10 +- bench-tps/src/bench_tps_client/rpc_client.rs | 20 ++- bench-tps/src/bench_tps_client/thin_client.rs | 10 +- bench-tps/src/bench_tps_client/tpu_client.rs | 19 ++- bench-tps/src/cli.rs | 20 ++- bench-tps/src/main.rs | 1 - runtime/src/accounts.rs | 2 - runtime/src/bank.rs | 16 ++- 11 files changed, 154 insertions(+), 109 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index 50cf4028980e4d..805fcd10664ac7 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -1,7 +1,5 @@ use { - crate::{ - bench_tps_client::*, - }, + crate::bench_tps_client::*, log::*, solana_address_lookup_table_program::{ instruction::{create_lookup_table, extend_lookup_table}, @@ -15,11 +13,7 @@ use { slot_history::Slot, transaction::Transaction, }, - std::{ - sync::Arc, - thread::sleep, - time::Duration, - }, + std::{sync::Arc, thread::sleep, time::Duration}, }; // Number of pubkeys to be included in single extend_lookup_table transaction that not exceeds MTU @@ -29,7 +23,6 @@ pub fn create_address_lookup_table_account, funding_key: &Keypair, num_addresses: usize, - keypairs: &Vec, ) -> Result { let (transaction, lookup_table_address) = build_create_lookup_table_tx( funding_key, @@ -84,9 +77,8 @@ fn build_extend_lookup_table_tx( recent_blockhash: Hash, ) -> Transaction { let mut addresses = Vec::with_capacity(num_addresses); - // TODO - replace new_unique with keys from keypairs, - // Or maybe not necessary? Should log and check what accounts.rs does with new_unique - // keys when loading + // NOTE - generated bunch of random addresses for sbf program (eg noop.so) to use, + // if real accounts are required, can use funded keypairs in lookup-table. addresses.resize_with(num_addresses, Pubkey::new_unique); let extend_lookup_table_ix = extend_lookup_table( *lookup_table_address, @@ -108,9 +100,8 @@ fn send_and_confirm_transaction u64 { @@ -175,22 +173,32 @@ where ); let signing_start = Instant::now(); - let address_lookup_table_account = self.lookup_table_address.and_then(|(lookup_table_address, sbf_program_id)| { - let lookup_table_account = self.client - .get_account_with_commitment(&lookup_table_address, CommitmentConfig::processed()) - .unwrap(); - info!("==== {:?}", lookup_table_account); - let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); - info!("==== {:?}", lookup_table); - Some(( - AddressLookupTableAccount { - key: lookup_table_address, - addresses: lookup_table.addresses.to_vec(), - }, - sbf_program_id, - )) - }); - info!("==== address_lookup_table_account {:?}", address_lookup_table_account); + let address_lookup_table_account = + self.lookup_table_address + .and_then(|(lookup_table_address, sbf_program_id)| { + let lookup_table_account = self + .client + .get_account_with_commitment( + &lookup_table_address, + CommitmentConfig::processed(), + ) + .unwrap(); + info!("==== {:?}", lookup_table_account); + let lookup_table = + AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + info!("==== {:?}", lookup_table); + Some(( + AddressLookupTableAccount { + key: lookup_table_address, + addresses: lookup_table.addresses.to_vec(), + }, + sbf_program_id, + )) + }); + info!( + "==== address_lookup_table_account {:?}", + address_lookup_table_account + ); let source_chunk = &self.account_chunks.source[self.chunk_index]; let dest_chunk = &self.account_chunks.dest[self.chunk_index]; @@ -415,13 +423,16 @@ where } = config; // if --load_accounts_from_address_lookup_table is used, creates Lookup Table account, - // then extend it with spepcified number of account. + // then extend it with spepcified number of account. // All bench transfer transactions will include a `sbf_program_id` instruction to load // specified number of accounts from Lookup Table account as writable accounts. - let lookup_table_address = load_accounts_from_address_lookup_table.and_then(|(sbf_program_id, number_of_accounts)| { - let lookup_table_account = create_address_lookup_table_account(client.clone(), &id, number_of_accounts, &gen_keypairs).unwrap(); - Some((lookup_table_account, sbf_program_id)) - }); + let lookup_table_address = + load_accounts_from_address_lookup_table.and_then(|(sbf_program_id, number_of_accounts)| { + let lookup_table_account = + create_address_lookup_table_account(client.clone(), &id, number_of_accounts) + .unwrap(); + Some((lookup_table_account, sbf_program_id)) + }); assert!(gen_keypairs.len() >= 2 * tx_count); let chunk_generator = TransactionChunkGenerator::new( @@ -653,18 +664,22 @@ fn transfer_with_compute_unit_price_and_padding( ), ]); - let versioned_message = if let Some((address_lookup_table_account, sbf_program_id)) = address_lookup_table_account { + let versioned_message = if let Some((address_lookup_table_account, sbf_program_id)) = + address_lookup_table_account + { let address_lookup_table_account_clone = address_lookup_table_account.clone(); let address_lookup_table_accounts = vec![address_lookup_table_account_clone]; - - let account_metas: Vec<_> = address_lookup_table_account.addresses.iter().map(|pubkey| { - AccountMeta::new(pubkey.clone(), false) - }).collect(); - instructions.extend_from_slice(&[ - Instruction::new_with_bincode(sbf_program_id.clone(), &(), + + let account_metas: Vec<_> = address_lookup_table_account + .addresses + .iter() + .map(|pubkey| AccountMeta::new(pubkey.clone(), false)) + .collect(); + instructions.extend_from_slice(&[Instruction::new_with_bincode( + sbf_program_id.clone(), + &(), account_metas, - ), - ]); + )]); VersionedMessage::V0( v0::Message::try_compile( @@ -672,14 +687,18 @@ fn transfer_with_compute_unit_price_and_padding( &instructions, &address_lookup_table_accounts, recent_blockhash, - ).unwrap() ) + .unwrap(), + ) } else { - VersionedMessage::Legacy(Message::new_with_blockhash(&instructions, Some(&from_pubkey), &recent_blockhash)) + VersionedMessage::Legacy(Message::new_with_blockhash( + &instructions, + Some(&from_pubkey), + &recent_blockhash, + )) }; - let versioned_transaction = VersionedTransaction::try_new( - versioned_message, &[from_keypair], - ).unwrap(); + let versioned_transaction = + VersionedTransaction::try_new(versioned_message, &[from_keypair]).unwrap(); info!("==== versioned_transaction {:?}", versioned_transaction); @@ -752,7 +771,7 @@ fn nonced_transfer_with_padding( lamports: u64, nonce_account: &Pubkey, nonce_authority: &Keypair, - nonce_hash: Hash, + _nonce_hash: Hash, instruction_padding_config: &Option, ) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); @@ -775,21 +794,22 @@ fn nonced_transfer_with_padding( ), ]); let versioned_nonce_transaction = VersionedTransaction::try_new( - VersionedMessage::Legacy( - Message::new_with_nonce( - instructions, - Some(&from_pubkey), - nonce_account, - &nonce_authority.pubkey(), - ) - ), + VersionedMessage::Legacy(Message::new_with_nonce( + instructions, + Some(&from_pubkey), + nonce_account, + &nonce_authority.pubkey(), + )), &[from_keypair], - ).unwrap(); + ) + .unwrap(); - info!("==== versioned_nonce_transaction {:?}", versioned_nonce_transaction); + info!( + "==== versioned_nonce_transaction {:?}", + versioned_nonce_transaction + ); - // TODO - need to sign the tx with - // nonce_hash + // TODO - need to sign the tx with `nonce_hash`? versioned_nonce_transaction } diff --git a/bench-tps/src/bench_tps_client.rs b/bench-tps/src/bench_tps_client.rs index 0597b07fc64940..b1d7aa46b5712c 100644 --- a/bench-tps/src/bench_tps_client.rs +++ b/bench-tps/src/bench_tps_client.rs @@ -1,8 +1,14 @@ use { solana_rpc_client_api::client_error::Error as ClientError, solana_sdk::{ - account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, transaction::{Transaction, VersionedTransaction}, + account::Account, + commitment_config::CommitmentConfig, + epoch_info::EpochInfo, + hash::Hash, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::{Transaction, VersionedTransaction}, transport::TransportError, }, solana_tpu_client::tpu_client::TpuSenderError, @@ -35,7 +41,10 @@ pub trait BenchTpsClient { fn send_batch(&self, transactions: Vec) -> Result<()>; /// Send a batch of signed versioned transactions without confirmation. - fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()>; + fn send_versioned_transaction_batch( + &self, + transactions: Vec, + ) -> Result<()>; /// Get latest blockhash fn get_latest_blockhash(&self) -> Result; diff --git a/bench-tps/src/bench_tps_client/bank_client.rs b/bench-tps/src/bench_tps_client/bank_client.rs index 8597e7c92beb28..154cfe43dd8343 100644 --- a/bench-tps/src/bench_tps_client/bank_client.rs +++ b/bench-tps/src/bench_tps_client/bank_client.rs @@ -10,7 +10,7 @@ use { message::Message, pubkey::Pubkey, signature::Signature, - transaction::{Transaction, VersionedTransaction,}, + transaction::{Transaction, VersionedTransaction}, }, }; @@ -21,8 +21,12 @@ impl BenchTpsClient for BankClient { fn send_batch(&self, transactions: Vec) -> Result<()> { AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) } - fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { - AsyncClient::async_send_versioned_transaction_batch(self, transactions).map_err(|err| err.into()) + fn send_versioned_transaction_batch( + &self, + transactions: Vec, + ) -> Result<()> { + AsyncClient::async_send_versioned_transaction_batch(self, transactions) + .map_err(|err| err.into()) } fn get_latest_blockhash(&self) -> Result { SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) diff --git a/bench-tps/src/bench_tps_client/rpc_client.rs b/bench-tps/src/bench_tps_client/rpc_client.rs index 53e109c6cb0687..3f929152b45efd 100644 --- a/bench-tps/src/bench_tps_client/rpc_client.rs +++ b/bench-tps/src/bench_tps_client/rpc_client.rs @@ -2,9 +2,14 @@ use { crate::bench_tps_client::{BenchTpsClient, BenchTpsError, Result}, solana_rpc_client::rpc_client::RpcClient, solana_sdk::{ - account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, - transaction::{Transaction, VersionedTransaction,}, + account::Account, + commitment_config::CommitmentConfig, + epoch_info::EpochInfo, + hash::Hash, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::{Transaction, VersionedTransaction}, }, }; @@ -18,8 +23,13 @@ impl BenchTpsClient for RpcClient { } Ok(()) } - fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { - BenchTpsClient::send_versioned_transaction_batch(self, transactions)?; + fn send_versioned_transaction_batch( + &self, + transactions: Vec, + ) -> Result<()> { + for transaction in transactions { + RpcClient::send_transaction(self, &transaction)?; + } Ok(()) } fn get_latest_blockhash(&self) -> Result { diff --git a/bench-tps/src/bench_tps_client/thin_client.rs b/bench-tps/src/bench_tps_client/thin_client.rs index 7634bbda4c8327..e00b7594434010 100644 --- a/bench-tps/src/bench_tps_client/thin_client.rs +++ b/bench-tps/src/bench_tps_client/thin_client.rs @@ -10,7 +10,7 @@ use { message::Message, pubkey::Pubkey, signature::Signature, - transaction::{Transaction, VersionedTransaction,}, + transaction::{Transaction, VersionedTransaction}, }, }; @@ -21,8 +21,12 @@ impl BenchTpsClient for ThinClient { fn send_batch(&self, transactions: Vec) -> Result<()> { AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) } - fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { - AsyncClient::async_send_versioned_transaction_batch(self, transactions).map_err(|err| err.into()) + fn send_versioned_transaction_batch( + &self, + transactions: Vec, + ) -> Result<()> { + AsyncClient::async_send_versioned_transaction_batch(self, transactions) + .map_err(|err| err.into()) } fn get_latest_blockhash(&self) -> Result { SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) diff --git a/bench-tps/src/bench_tps_client/tpu_client.rs b/bench-tps/src/bench_tps_client/tpu_client.rs index 1a85167e74113c..04ed333e1ed6a2 100644 --- a/bench-tps/src/bench_tps_client/tpu_client.rs +++ b/bench-tps/src/bench_tps_client/tpu_client.rs @@ -3,9 +3,14 @@ use { solana_client::tpu_client::TpuClient, solana_connection_cache::connection_cache::{ConnectionManager, ConnectionPool}, solana_sdk::{ - account::Account, commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, - message::Message, pubkey::Pubkey, signature::Signature, - transaction::{Transaction, VersionedTransaction,}, + account::Account, + commitment_config::CommitmentConfig, + epoch_info::EpochInfo, + hash::Hash, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::{Transaction, VersionedTransaction}, }, }; @@ -23,8 +28,12 @@ where self.try_send_transaction_batch(&transactions)?; Ok(()) } - fn send_versioned_transaction_batch(&self, transactions: Vec) -> Result<()> { - BenchTpsClient::send_versioned_transaction_batch(self, transactions)?; + fn send_versioned_transaction_batch( + &self, + transactions: Vec, + ) -> Result<()> { + self.rpc_client() + .send_versioned_transaction_batch(transactions)?; Ok(()) } fn get_latest_blockhash(&self) -> Result { diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 7cca026a0d79b2..9268a3be3ec228 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -3,9 +3,7 @@ use { itertools::Itertools, solana_clap_utils::{ hidden_unless_forced, - input_validators::{ - is_keypair, is_url, is_url_or_moniker, is_within_range, - }, + input_validators::{is_keypair, is_url, is_url_or_moniker, is_within_range}, }, solana_cli_config::{ConfigInput, CONFIG_FILE}, solana_sdk::{ @@ -403,7 +401,7 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { 1st parameter is a pubkey string of SBF program to be used;\ 2nd parameter is the number of accounts to be loaded by the SBF program from ATL.", ), - ) + ) } /// Parses a clap `ArgMatches` structure into a `Config` @@ -581,17 +579,15 @@ pub fn parse_args(matches: &ArgMatches) -> Result { if let Some(values) = matches.values_of("load_accounts_from_address_lookup_table") { for (sbf_program_pubkey_string, number_of_accounts) in values.into_iter().tuples() { - let sbf_program_pubkey = sbf_program_pubkey_string.parse::().map_err(|_| "Can't parse pubkey string")?; + let sbf_program_pubkey = sbf_program_pubkey_string + .parse::() + .map_err(|_| "Can't parse pubkey string")?; let parsed_number_of_accounts = number_of_accounts .parse() .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; - // TODO - remove log - log::info!("==== instruct {:?} to load {:?} accounts from from ATL", sbf_program_pubkey, parsed_number_of_accounts); - // NOTE - support multiple ATL IXs later - args.load_accounts_from_address_lookup_table = Some(( - sbf_program_pubkey, - parsed_number_of_accounts, - )); + // NOTE - can support multiple ATL IXs later, for now, only use one such ix. + args.load_accounts_from_address_lookup_table = + Some((sbf_program_pubkey, parsed_number_of_accounts)); } } diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 83da26bc7ef7f6..0788181e85b6a1 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -256,7 +256,6 @@ fn main() { instruction_padding_config, bind_address, client_node_id, - load_accounts_from_address_lookup_table, .. } = &cli_config; diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index e40a053667d98a..d12f5405ad2c19 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -792,8 +792,6 @@ impl Accounts { let lookup_table = AddressLookupTable::deserialize(table_account.data()) .map_err(|_ix_err| AddressLookupError::InvalidAccountData)?; - debug!("==== load_lookup_table_addresses, lookup_table {:?}", lookup_table); - Ok(LoadedAddresses { writable: lookup_table.lookup( current_slot, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 63fce49bbf38f3..9c83fcdf7d94f7 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -6050,11 +6050,17 @@ impl Bank { timings: &mut ExecuteTimings, ) -> TransactionResults { // TAO TODO - remove the print - execution_results.iter().zip(sanitized_txs).for_each(|(execution_result, tx)| { - debug!("==== tx_sig {:?}, execution_result {:?}", tx.signature(), execution_result); - }); - - + execution_results + .iter() + .zip(sanitized_txs) + .for_each(|(execution_result, tx)| { + debug!( + "==== tx_sig {:?}, execution_result {:?}", + tx.signature(), + execution_result + ); + }); + assert!( !self.freeze_started(), "commit_transactions() working on a bank that is already frozen or is undergoing freezing!" From 66d3f188bf9ad101b185c154287f89178c425848 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Tue, 27 Jun 2023 19:17:43 +0000 Subject: [PATCH 09/15] clippy --- bench-tps/src/address_table_lookup.rs | 2 +- bench-tps/src/bench.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index 805fcd10664ac7..8dde28cb86c518 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -108,7 +108,7 @@ fn send_and_confirm_transaction= 2 * tx_count); @@ -673,10 +673,10 @@ fn transfer_with_compute_unit_price_and_padding( let account_metas: Vec<_> = address_lookup_table_account .addresses .iter() - .map(|pubkey| AccountMeta::new(pubkey.clone(), false)) + .map(|pubkey| AccountMeta::new(*pubkey, false)) .collect(); instructions.extend_from_slice(&[Instruction::new_with_bincode( - sbf_program_id.clone(), + *sbf_program_id, &(), account_metas, )]); From e3d31338ef962c2b32194728e46d5751c461018b Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Wed, 9 Aug 2023 23:10:22 +0000 Subject: [PATCH 10/15] refreshed address_table_lookup.rs --- bench-tps/src/address_table_lookup.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index 8dde28cb86c518..bae30c204d532c 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -1,5 +1,6 @@ use { crate::bench_tps_client::*, + itertools::Itertools, log::*, solana_address_lookup_table_program::{ instruction::{create_lookup_table, extend_lookup_table}, @@ -16,9 +17,7 @@ use { std::{sync::Arc, thread::sleep, time::Duration}, }; -// Number of pubkeys to be included in single extend_lookup_table transaction that not exceeds MTU -const NUMBER_OF_ADDRESSES_PER_EXTEND: usize = 16; - +/// To create a lookup-table account via `client`, and extend it with `num_addresses`. pub fn create_address_lookup_table_account( client: Arc, funding_key: &Keypair, @@ -31,6 +30,11 @@ pub fn create_address_lookup_table_account Transaction { - let mut addresses = Vec::with_capacity(num_addresses); - // NOTE - generated bunch of random addresses for sbf program (eg noop.so) to use, - // if real accounts are required, can use funded keypairs in lookup-table. - addresses.resize_with(num_addresses, Pubkey::new_unique); + // generates random addresses to populate lookup table account + let addresses = (0..num_addresses).map(|_| Pubkey::new_unique()).collect_vec(); let extend_lookup_table_ix = extend_lookup_table( *lookup_table_address, funding_key.pubkey(), // authority @@ -100,8 +102,7 @@ fn send_and_confirm_transaction Date: Thu, 10 Aug 2023 17:21:43 +0000 Subject: [PATCH 11/15] replace tuple with wrapper structure, and other bench.rs clean ups --- bench-tps/src/address_table_lookup.rs | 4 +- bench-tps/src/bench.rs | 114 +++++++++++--------------- bench-tps/src/cli.rs | 42 ++++++---- runtime/src/bank.rs | 12 --- 4 files changed, 77 insertions(+), 95 deletions(-) diff --git a/bench-tps/src/address_table_lookup.rs b/bench-tps/src/address_table_lookup.rs index bae30c204d532c..3b65388b7941a4 100644 --- a/bench-tps/src/address_table_lookup.rs +++ b/bench-tps/src/address_table_lookup.rs @@ -81,7 +81,9 @@ fn build_extend_lookup_table_tx( recent_blockhash: Hash, ) -> Transaction { // generates random addresses to populate lookup table account - let addresses = (0..num_addresses).map(|_| Pubkey::new_unique()).collect_vec(); + let addresses = (0..num_addresses) + .map(|_| Pubkey::new_unique()) + .collect_vec(); let extend_lookup_table_ix = extend_lookup_table( *lookup_table_address, funding_key.pubkey(), // authority diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 12540eb48eb36b..ae4be2ea78ea67 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -84,6 +84,12 @@ struct KeypairChunks<'a> { dest: Vec>, } +/// Accounts pubkeys needed to construct instruction that uses ATL +struct AtlInstructionAccounts { + lookup_table_account: AddressLookupTableAccount, + noop_program_id: Pubkey, +} + impl<'a> KeypairChunks<'a> { /// Split input slice of keypairs into two sets of chunks of given size fn new(keypairs: &'a [Keypair], chunk_size: usize) -> Self { @@ -126,7 +132,7 @@ struct TransactionChunkGenerator<'a, 'b, T: ?Sized> { reclaim_lamports_back_to_source_account: bool, use_randomized_compute_unit_price: bool, instruction_padding_config: Option, - lookup_table_address: Option<(Pubkey, Pubkey)>, + atl_instruction_accounts: Option, } impl<'a, 'b, T> TransactionChunkGenerator<'a, 'b, T> @@ -141,7 +147,7 @@ where use_randomized_compute_unit_price: bool, instruction_padding_config: Option, num_conflict_groups: Option, - lookup_table_address: Option<(Pubkey, Pubkey)>, + atl_instruction_accounts: Option, ) -> Self { let account_chunks = if let Some(num_conflict_groups) = num_conflict_groups { KeypairChunks::new_with_conflict_groups(gen_keypairs, chunk_size, num_conflict_groups) @@ -159,7 +165,7 @@ where reclaim_lamports_back_to_source_account: false, use_randomized_compute_unit_price, instruction_padding_config, - lookup_table_address, + atl_instruction_accounts, } } @@ -173,33 +179,6 @@ where ); let signing_start = Instant::now(); - let address_lookup_table_account = - self.lookup_table_address - .map(|(lookup_table_address, sbf_program_id)| { - let lookup_table_account = self - .client - .get_account_with_commitment( - &lookup_table_address, - CommitmentConfig::processed(), - ) - .unwrap(); - info!("==== {:?}", lookup_table_account); - let lookup_table = - AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); - info!("==== {:?}", lookup_table); - ( - AddressLookupTableAccount { - key: lookup_table_address, - addresses: lookup_table.addresses.to_vec(), - }, - sbf_program_id, - ) - }); - info!( - "==== address_lookup_table_account {:?}", - address_lookup_table_account - ); - let source_chunk = &self.account_chunks.source[self.chunk_index]; let dest_chunk = &self.account_chunks.dest[self.chunk_index]; let transactions = if let Some(nonce_chunks) = &self.nonce_chunks { @@ -223,7 +202,7 @@ where blockhash.unwrap(), &self.instruction_padding_config, self.use_randomized_compute_unit_price, - &address_lookup_table_account, + &self.atl_instruction_accounts, ) }; @@ -423,15 +402,31 @@ where } = config; // if --load_accounts_from_address_lookup_table is used, creates Lookup Table account, - // then extend it with spepcified number of account. - // All bench transfer transactions will include a `sbf_program_id` instruction to load + // then extend it with requested number of accounts. + // All bench transfer transactions will include a `noop_program_id` instruction to load // specified number of accounts from Lookup Table account as writable accounts. - let lookup_table_address = - load_accounts_from_address_lookup_table.map(|(sbf_program_id, number_of_accounts)| { - let lookup_table_account = - create_address_lookup_table_account(client.clone(), &id, number_of_accounts) - .unwrap(); - (lookup_table_account, sbf_program_id) + let alt_instruction_accounts = + load_accounts_from_address_lookup_table.map(|lookup_table_config| { + let lookup_table_account_address = create_address_lookup_table_account( + client.clone(), + &id, + lookup_table_config.number_addresses, + ) + .unwrap(); + let lookup_table_account = client + .get_account_with_commitment( + &lookup_table_account_address, + CommitmentConfig::processed(), + ) + .unwrap(); + let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + AtlInstructionAccounts { + lookup_table_account: AddressLookupTableAccount { + key: lookup_table_account_address, + addresses: lookup_table.addresses.to_vec(), + }, + noop_program_id: lookup_table_config.noop_program_id, + } }); assert!(gen_keypairs.len() >= 2 * tx_count); @@ -443,7 +438,7 @@ where use_randomized_compute_unit_price, instruction_padding_config, num_conflict_groups, - lookup_table_address, + alt_instruction_accounts, ); let first_tx_count = loop { @@ -570,7 +565,7 @@ fn generate_system_txs( blockhash: &Hash, instruction_padding_config: &Option, use_randomized_compute_unit_price: bool, - address_lookup_table_account: &Option<(AddressLookupTableAccount, Pubkey)>, + atl_instruction_accounts: &Option, ) -> Vec { let pairs: Vec<_> = if !reclaim { source.iter().zip(dest.iter()).collect() @@ -602,7 +597,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, Some(**compute_unit_price), - address_lookup_table_account, + atl_instruction_accounts, ), Some(timestamp()), ) @@ -620,7 +615,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, None, - address_lookup_table_account, + atl_instruction_accounts, ), Some(timestamp()), ) @@ -636,7 +631,7 @@ fn transfer_with_compute_unit_price_and_padding( recent_blockhash: Hash, instruction_padding_config: &Option, compute_unit_price: Option, - address_lookup_table_account: &Option<(AddressLookupTableAccount, Pubkey)>, + atl_instruction_accounts: &Option, ) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); @@ -664,19 +659,19 @@ fn transfer_with_compute_unit_price_and_padding( ), ]); - let versioned_message = if let Some((address_lookup_table_account, sbf_program_id)) = - address_lookup_table_account - { - let address_lookup_table_account_clone = address_lookup_table_account.clone(); + let versioned_message = if let Some(atl_instruction_accounts) = atl_instruction_accounts { + let address_lookup_table_account_clone = + atl_instruction_accounts.lookup_table_account.clone(); let address_lookup_table_accounts = vec![address_lookup_table_account_clone]; - let account_metas: Vec<_> = address_lookup_table_account + let account_metas: Vec<_> = atl_instruction_accounts + .lookup_table_account .addresses .iter() .map(|pubkey| AccountMeta::new(*pubkey, false)) .collect(); instructions.extend_from_slice(&[Instruction::new_with_bincode( - *sbf_program_id, + atl_instruction_accounts.noop_program_id, &(), account_metas, )]); @@ -697,12 +692,7 @@ fn transfer_with_compute_unit_price_and_padding( &recent_blockhash, )) }; - let versioned_transaction = - VersionedTransaction::try_new(versioned_message, &[from_keypair]).unwrap(); - - info!("==== versioned_transaction {:?}", versioned_transaction); - - versioned_transaction + VersionedTransaction::try_new(versioned_message, &[from_keypair]).unwrap() } fn get_nonce_accounts( @@ -793,7 +783,7 @@ fn nonced_transfer_with_padding( TRANSFER_TRANSACTION_LOADED_ACCOUNTS_DATA_SIZE, ), ]); - let versioned_nonce_transaction = VersionedTransaction::try_new( + VersionedTransaction::try_new( VersionedMessage::Legacy(Message::new_with_nonce( instructions, Some(&from_pubkey), @@ -802,15 +792,7 @@ fn nonced_transfer_with_padding( )), &[from_keypair], ) - .unwrap(); - - info!( - "==== versioned_nonce_transaction {:?}", - versioned_nonce_transaction - ); - - // TODO - need to sign the tx with `nonce_hash`? - versioned_nonce_transaction + .unwrap() } fn generate_nonced_system_txs( diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 9268a3be3ec228..550e28aaf53cc7 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -44,6 +44,15 @@ pub struct InstructionPaddingConfig { pub data_size: u32, } +#[derive(Eq, PartialEq, Debug)] +pub struct LookupTableConfig { + // program_id of `noop` program in test cluster; bench-tps uses `noop` program to + // load accounts from ALT + pub noop_program_id: Pubkey, + // number of addresses (up to 256) to be added to ATL for `noop` to load + pub number_addresses: usize, +} + /// Holds the configuration for a single run of the benchmark #[derive(PartialEq, Debug)] pub struct Config { @@ -75,7 +84,7 @@ pub struct Config { pub num_conflict_groups: Option, pub bind_address: IpAddr, pub client_node_id: Option, - pub load_accounts_from_address_lookup_table: Option<(Pubkey, usize)>, + pub load_accounts_from_address_lookup_table: Option, } impl Eq for Config {} @@ -388,18 +397,18 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .arg( Arg::with_name("load_accounts_from_address_lookup_table") .long("load-accounts-from-address-lookup-table") - .value_names(&["SBF_PROGRAM_PUBKEY", "NUMBER_OF_ACCOUNTS_TO_LOAD"]) + .value_names(&["NOOP_PROGRAM_PUBKEY", "NUMBER_OF_ACCOUNTS_TO_LOAD"]) .takes_value(true) .number_of_values(2) - .multiple(true) + .multiple(false) .help( - "Specify a SBF program to load number of accounts from ATL in bench-tps Transfer transaction; \ - When thhis argument is used, bench-tps creates a address-lookup account with NUMBER_OF_ACCOUNTS_TO_LOAD\ - accounts in test cluster, then sends VersionedTransaction with V0 message includes a instruction\ - that load all accounts from ATL by program of SBF_PROGRAM_PUBKEY; \ - Otherwise, bench-tps creates VersionedTransaction with LegacyMessage without using ATL;\ - 1st parameter is a pubkey string of SBF program to be used;\ - 2nd parameter is the number of accounts to be loaded by the SBF program from ATL.", + "Uses `noop` SBF program to load number of accounts from ATL in bench-tps Transfer transaction; \ + When this argument is used, bench-tps creates a address-lookup account with NUMBER_OF_ACCOUNTS_TO_LOAD \ + accounts in test cluster, then sends VersionedTransaction with V0 message includes a instruction \ + that load all accounts from ATL by `noop` program of NOOP_PROGRAM_PUBKEY; \ + Otherwise, bench-tps creates VersionedTransaction with LegacyMessage without using ATL; \ + 1st parameter is a pubkey string of `noop` program to be used, which must have been deployed to test cluster; \ + 2nd parameter is the number of accounts [0..256] to be loaded by the `noop` program from ATL.", ), ) } @@ -578,16 +587,17 @@ pub fn parse_args(matches: &ArgMatches) -> Result { } if let Some(values) = matches.values_of("load_accounts_from_address_lookup_table") { - for (sbf_program_pubkey_string, number_of_accounts) in values.into_iter().tuples() { - let sbf_program_pubkey = sbf_program_pubkey_string + for (noop_program_pubkey_string, number_of_accounts) in values.into_iter().tuples() { + let noop_program_id = noop_program_pubkey_string .parse::() .map_err(|_| "Can't parse pubkey string")?; - let parsed_number_of_accounts = number_of_accounts + let number_addresses = number_of_accounts .parse() .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; - // NOTE - can support multiple ATL IXs later, for now, only use one such ix. - args.load_accounts_from_address_lookup_table = - Some((sbf_program_pubkey, parsed_number_of_accounts)); + args.load_accounts_from_address_lookup_table = Some(LookupTableConfig { + noop_program_id, + number_addresses, + }); } } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 9c83fcdf7d94f7..c65e3da439c322 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -6049,18 +6049,6 @@ impl Bank { counts: CommitTransactionCounts, timings: &mut ExecuteTimings, ) -> TransactionResults { - // TAO TODO - remove the print - execution_results - .iter() - .zip(sanitized_txs) - .for_each(|(execution_result, tx)| { - debug!( - "==== tx_sig {:?}, execution_result {:?}", - tx.signature(), - execution_result - ); - }); - assert!( !self.freeze_started(), "commit_transactions() working on a bank that is already frozen or is undergoing freezing!" From f9d9a48a7aba9c639242c4b84f675ac18030c57c Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Thu, 10 Aug 2023 23:25:28 +0000 Subject: [PATCH 12/15] separate bundle cli argument into two --- bench-tps/src/cli.rs | 61 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 550e28aaf53cc7..1d57651d2ea561 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -1,9 +1,8 @@ use { clap::{crate_description, crate_name, App, Arg, ArgMatches}, - itertools::Itertools, solana_clap_utils::{ hidden_unless_forced, - input_validators::{is_keypair, is_url, is_url_or_moniker, is_within_range}, + input_validators::{is_keypair, is_pubkey, is_url, is_url_or_moniker, is_within_range}, }, solana_cli_config::{ConfigInput, CONFIG_FILE}, solana_sdk::{ @@ -395,21 +394,25 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .help("File containing the node identity (keypair) of a validator with active stake. This allows communicating with network using staked connection"), ) .arg( - Arg::with_name("load_accounts_from_address_lookup_table") - .long("load-accounts-from-address-lookup-table") - .value_names(&["NOOP_PROGRAM_PUBKEY", "NUMBER_OF_ACCOUNTS_TO_LOAD"]) + Arg::with_name("alt_instruction_program_id") + .long("alt-instruction-program-id") + .value_name("ALT_INSTRUCTION_PROGRAM_ID") .takes_value(true) - .number_of_values(2) - .multiple(false) - .help( - "Uses `noop` SBF program to load number of accounts from ATL in bench-tps Transfer transaction; \ - When this argument is used, bench-tps creates a address-lookup account with NUMBER_OF_ACCOUNTS_TO_LOAD \ - accounts in test cluster, then sends VersionedTransaction with V0 message includes a instruction \ - that load all accounts from ATL by `noop` program of NOOP_PROGRAM_PUBKEY; \ - Otherwise, bench-tps creates VersionedTransaction with LegacyMessage without using ATL; \ - 1st parameter is a pubkey string of `noop` program to be used, which must have been deployed to test cluster; \ - 2nd parameter is the number of accounts [0..256] to be loaded by the `noop` program from ATL.", - ), + .requires("alt_instruction_load_accounts_count") + .validator(is_pubkey) + .help("If program id of deployed SBF progrem, for example `noop`, is provided; bench transfer transactions \ + will include an additional instruction to use the program to load number of accounts from an \ + address lookup table account." + ) + ) + .arg( + Arg::with_name("alt_instruction_load_accounts_count") + .long("alt-instruction-load-accounts-count") + .value_name("ALT_INSTRUCTION_LOAD_ACCOUNTS_COUNT") + .takes_value(true) + .requires("alt_instruction_program_id") + .validator(|n| is_within_range(n, 0..256)) + .help("The number of accounts are loaded from address lookup table account by program identified as `alt_instruction_program_id`") ) } @@ -586,19 +589,19 @@ pub fn parse_args(matches: &ArgMatches) -> Result { args.client_node_id = Some(client_node_id); } - if let Some(values) = matches.values_of("load_accounts_from_address_lookup_table") { - for (noop_program_pubkey_string, number_of_accounts) in values.into_iter().tuples() { - let noop_program_id = noop_program_pubkey_string - .parse::() - .map_err(|_| "Can't parse pubkey string")?; - let number_addresses = number_of_accounts - .parse() - .map_err(|_| "Can't parse number-of-accounts-from-address-lookup-table")?; - args.load_accounts_from_address_lookup_table = Some(LookupTableConfig { - noop_program_id, - number_addresses, - }); - } + if let Some(alt_instruction_program_id) = matches.value_of("alt_instruction_program_id") { + let alt_instruction_load_accounts_count = matches + .value_of("alt_instruction_load_accounts_count") + .unwrap() + .parse() + .map_err(|_| "Can't parse alt_instruction_load_accounts_count")?; + let alt_instruction_program_id = alt_instruction_program_id + .parse::() + .map_err(|_| "Can't parse pubkey alt_instruction_program_id")?; + args.load_accounts_from_address_lookup_table = Some(LookupTableConfig { + noop_program_id: alt_instruction_program_id, + number_addresses: alt_instruction_load_accounts_count, + }); } Ok(args) From de7f6facf92bf51c290602f3c8bb338a3411b553 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Fri, 11 Aug 2023 01:22:27 +0000 Subject: [PATCH 13/15] renames --- bench-tps/src/bench.rs | 77 +++++++++++++++++++++--------------------- bench-tps/src/cli.rs | 20 +++++------ 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index ae4be2ea78ea67..de64087f09abaa 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -85,9 +85,9 @@ struct KeypairChunks<'a> { } /// Accounts pubkeys needed to construct instruction that uses ATL -struct AtlInstructionAccounts { +struct AltInstructionAccounts { lookup_table_account: AddressLookupTableAccount, - noop_program_id: Pubkey, + alt_instruction_program_id: Pubkey, } impl<'a> KeypairChunks<'a> { @@ -132,7 +132,7 @@ struct TransactionChunkGenerator<'a, 'b, T: ?Sized> { reclaim_lamports_back_to_source_account: bool, use_randomized_compute_unit_price: bool, instruction_padding_config: Option, - atl_instruction_accounts: Option, + alt_instruction_accounts: Option, } impl<'a, 'b, T> TransactionChunkGenerator<'a, 'b, T> @@ -147,7 +147,7 @@ where use_randomized_compute_unit_price: bool, instruction_padding_config: Option, num_conflict_groups: Option, - atl_instruction_accounts: Option, + alt_instruction_accounts: Option, ) -> Self { let account_chunks = if let Some(num_conflict_groups) = num_conflict_groups { KeypairChunks::new_with_conflict_groups(gen_keypairs, chunk_size, num_conflict_groups) @@ -165,7 +165,7 @@ where reclaim_lamports_back_to_source_account: false, use_randomized_compute_unit_price, instruction_padding_config, - atl_instruction_accounts, + alt_instruction_accounts, } } @@ -202,7 +202,7 @@ where blockhash.unwrap(), &self.instruction_padding_config, self.use_randomized_compute_unit_price, - &self.atl_instruction_accounts, + &self.alt_instruction_accounts, ) }; @@ -397,37 +397,36 @@ where use_durable_nonce, instruction_padding_config, num_conflict_groups, - load_accounts_from_address_lookup_table, + alt_instruction_config, .. } = config; - // if --load_accounts_from_address_lookup_table is used, creates Lookup Table account, + // if --alt_instruction_load_accounts_count is used, creates Lookup Table account, // then extend it with requested number of accounts. - // All bench transfer transactions will include a `noop_program_id` instruction to load + // All bench transfer transactions will include a `alt_instruction_program_id` instruction to load // specified number of accounts from Lookup Table account as writable accounts. - let alt_instruction_accounts = - load_accounts_from_address_lookup_table.map(|lookup_table_config| { - let lookup_table_account_address = create_address_lookup_table_account( - client.clone(), - &id, - lookup_table_config.number_addresses, + let alt_instruction_accounts = alt_instruction_config.map(|alt_instruction_config| { + let lookup_table_account_address = create_address_lookup_table_account( + client.clone(), + &id, + alt_instruction_config.alt_instruction_load_accounts_count, + ) + .unwrap(); + let lookup_table_account = client + .get_account_with_commitment( + &lookup_table_account_address, + CommitmentConfig::processed(), ) .unwrap(); - let lookup_table_account = client - .get_account_with_commitment( - &lookup_table_account_address, - CommitmentConfig::processed(), - ) - .unwrap(); - let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); - AtlInstructionAccounts { - lookup_table_account: AddressLookupTableAccount { - key: lookup_table_account_address, - addresses: lookup_table.addresses.to_vec(), - }, - noop_program_id: lookup_table_config.noop_program_id, - } - }); + let lookup_table = AddressLookupTable::deserialize(&lookup_table_account.data).unwrap(); + AltInstructionAccounts { + lookup_table_account: AddressLookupTableAccount { + key: lookup_table_account_address, + addresses: lookup_table.addresses.to_vec(), + }, + alt_instruction_program_id: alt_instruction_config.alt_instruction_program_id, + } + }); assert!(gen_keypairs.len() >= 2 * tx_count); let chunk_generator = TransactionChunkGenerator::new( @@ -565,7 +564,7 @@ fn generate_system_txs( blockhash: &Hash, instruction_padding_config: &Option, use_randomized_compute_unit_price: bool, - atl_instruction_accounts: &Option, + alt_instruction_accounts: &Option, ) -> Vec { let pairs: Vec<_> = if !reclaim { source.iter().zip(dest.iter()).collect() @@ -597,7 +596,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, Some(**compute_unit_price), - atl_instruction_accounts, + alt_instruction_accounts, ), Some(timestamp()), ) @@ -615,7 +614,7 @@ fn generate_system_txs( *blockhash, instruction_padding_config, None, - atl_instruction_accounts, + alt_instruction_accounts, ), Some(timestamp()), ) @@ -631,7 +630,7 @@ fn transfer_with_compute_unit_price_and_padding( recent_blockhash: Hash, instruction_padding_config: &Option, compute_unit_price: Option, - atl_instruction_accounts: &Option, + alt_instruction_accounts: &Option, ) -> VersionedTransaction { let from_pubkey = from_keypair.pubkey(); let transfer_instruction = system_instruction::transfer(&from_pubkey, to, lamports); @@ -659,19 +658,19 @@ fn transfer_with_compute_unit_price_and_padding( ), ]); - let versioned_message = if let Some(atl_instruction_accounts) = atl_instruction_accounts { + let versioned_message = if let Some(alt_instruction_accounts) = alt_instruction_accounts { let address_lookup_table_account_clone = - atl_instruction_accounts.lookup_table_account.clone(); + alt_instruction_accounts.lookup_table_account.clone(); let address_lookup_table_accounts = vec![address_lookup_table_account_clone]; - let account_metas: Vec<_> = atl_instruction_accounts + let account_metas: Vec<_> = alt_instruction_accounts .lookup_table_account .addresses .iter() - .map(|pubkey| AccountMeta::new(*pubkey, false)) + .map(|pubkey| AccountMeta::new_readonly(*pubkey, false)) .collect(); instructions.extend_from_slice(&[Instruction::new_with_bincode( - atl_instruction_accounts.noop_program_id, + alt_instruction_accounts.alt_instruction_program_id, &(), account_metas, )]); diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 1d57651d2ea561..be3d0e48bb0512 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -44,12 +44,12 @@ pub struct InstructionPaddingConfig { } #[derive(Eq, PartialEq, Debug)] -pub struct LookupTableConfig { - // program_id of `noop` program in test cluster; bench-tps uses `noop` program to +pub struct AltInstructionConfig { + // program_id of a sbf program deployed in test cluster, such as `noop`, to // load accounts from ALT - pub noop_program_id: Pubkey, - // number of addresses (up to 256) to be added to ATL for `noop` to load - pub number_addresses: usize, + pub alt_instruction_program_id: Pubkey, + // number of addresses (up to 256) to be added to ATL for program to load + pub alt_instruction_load_accounts_count: usize, } /// Holds the configuration for a single run of the benchmark @@ -83,7 +83,7 @@ pub struct Config { pub num_conflict_groups: Option, pub bind_address: IpAddr, pub client_node_id: Option, - pub load_accounts_from_address_lookup_table: Option, + pub alt_instruction_config: Option, } impl Eq for Config {} @@ -119,7 +119,7 @@ impl Default for Config { num_conflict_groups: None, bind_address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), client_node_id: None, - load_accounts_from_address_lookup_table: None, + alt_instruction_config: None, } } } @@ -598,9 +598,9 @@ pub fn parse_args(matches: &ArgMatches) -> Result { let alt_instruction_program_id = alt_instruction_program_id .parse::() .map_err(|_| "Can't parse pubkey alt_instruction_program_id")?; - args.load_accounts_from_address_lookup_table = Some(LookupTableConfig { - noop_program_id: alt_instruction_program_id, - number_addresses: alt_instruction_load_accounts_count, + args.alt_instruction_config = Some(AltInstructionConfig { + alt_instruction_program_id, + alt_instruction_load_accounts_count, }); } From b57cc4efd06f190f49f95f947b9ed1fcae469fb8 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Fri, 11 Aug 2023 03:04:04 +0000 Subject: [PATCH 14/15] inclusive range --- bench-tps/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index be3d0e48bb0512..9de5955194fb4c 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -411,7 +411,7 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .value_name("ALT_INSTRUCTION_LOAD_ACCOUNTS_COUNT") .takes_value(true) .requires("alt_instruction_program_id") - .validator(|n| is_within_range(n, 0..256)) + .validator(|n| is_within_range(n, 0..=256)) .help("The number of accounts are loaded from address lookup table account by program identified as `alt_instruction_program_id`") ) } From 9a82149a827e28f8830e5e0cc6755252a4b92348 Mon Sep 17 00:00:00 2001 From: Tao Zhu Date: Fri, 11 Aug 2023 03:19:26 +0000 Subject: [PATCH 15/15] to limit total accounts number less than 256 --- bench-tps/src/bench.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index de64087f09abaa..d0c45ffb7a4314 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -406,12 +406,13 @@ where // All bench transfer transactions will include a `alt_instruction_program_id` instruction to load // specified number of accounts from Lookup Table account as writable accounts. let alt_instruction_accounts = alt_instruction_config.map(|alt_instruction_config| { - let lookup_table_account_address = create_address_lookup_table_account( - client.clone(), - &id, - alt_instruction_config.alt_instruction_load_accounts_count, - ) - .unwrap(); + // there are 5 accounts already in transaction: signer, 2 for transfer, compute budget and + // sbf program, need to deduct them from alt size. + const MIN_ACCOUNTS_COUNT: usize = 5; + let alt_size = + alt_instruction_config.alt_instruction_load_accounts_count - MIN_ACCOUNTS_COUNT; + let lookup_table_account_address = + create_address_lookup_table_account(client.clone(), &id, alt_size).unwrap(); let lookup_table_account = client .get_account_with_commitment( &lookup_table_account_address,