Move transaction executor (#19946)
This commit is contained in:
		
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -4560,6 +4560,7 @@ dependencies = [ | |||||||
|  "solana-clap-utils", |  "solana-clap-utils", | ||||||
|  "solana-faucet", |  "solana-faucet", | ||||||
|  "solana-logger 1.9.0", |  "solana-logger 1.9.0", | ||||||
|  |  "solana-measure", | ||||||
|  "solana-net-utils", |  "solana-net-utils", | ||||||
|  "solana-sdk", |  "solana-sdk", | ||||||
|  "solana-transaction-status", |  "solana-transaction-status", | ||||||
|   | |||||||
| @@ -5,10 +5,9 @@ use rand::{thread_rng, Rng}; | |||||||
| use rayon::prelude::*; | use rayon::prelude::*; | ||||||
| use solana_account_decoder::parse_token::spl_token_v2_0_pubkey; | use solana_account_decoder::parse_token::spl_token_v2_0_pubkey; | ||||||
| use solana_clap_utils::input_parsers::pubkey_of; | use solana_clap_utils::input_parsers::pubkey_of; | ||||||
| use solana_client::rpc_client::RpcClient; | use solana_client::{rpc_client::RpcClient, transaction_executor::TransactionExecutor}; | ||||||
| use solana_faucet::faucet::{request_airdrop_transaction, FAUCET_PORT}; | use solana_faucet::faucet::{request_airdrop_transaction, FAUCET_PORT}; | ||||||
| use solana_gossip::gossip_service::discover; | use solana_gossip::gossip_service::discover; | ||||||
| use solana_measure::measure::Measure; |  | ||||||
| use solana_runtime::inline_spl_token_v2_0; | use solana_runtime::inline_spl_token_v2_0; | ||||||
| use solana_sdk::{ | use solana_sdk::{ | ||||||
|     commitment_config::CommitmentConfig, |     commitment_config::CommitmentConfig, | ||||||
| @@ -16,9 +15,8 @@ use solana_sdk::{ | |||||||
|     message::Message, |     message::Message, | ||||||
|     pubkey::Pubkey, |     pubkey::Pubkey, | ||||||
|     rpc_port::DEFAULT_RPC_PORT, |     rpc_port::DEFAULT_RPC_PORT, | ||||||
|     signature::{read_keypair_file, Keypair, Signature, Signer}, |     signature::{read_keypair_file, Keypair, Signer}, | ||||||
|     system_instruction, system_program, |     system_instruction, system_program, | ||||||
|     timing::timestamp, |  | ||||||
|     transaction::Transaction, |     transaction::Transaction, | ||||||
| }; | }; | ||||||
| use solana_streamer::socket::SocketAddrSpace; | use solana_streamer::socket::SocketAddrSpace; | ||||||
| @@ -27,10 +25,10 @@ use std::{ | |||||||
|     net::SocketAddr, |     net::SocketAddr, | ||||||
|     process::exit, |     process::exit, | ||||||
|     sync::{ |     sync::{ | ||||||
|         atomic::{AtomicBool, AtomicU64, Ordering}, |         atomic::{AtomicU64, Ordering}, | ||||||
|         Arc, RwLock, |         Arc, | ||||||
|     }, |     }, | ||||||
|     thread::{sleep, Builder, JoinHandle}, |     thread::sleep, | ||||||
|     time::{Duration, Instant}, |     time::{Duration, Instant}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -97,160 +95,6 @@ pub fn airdrop_lamports( | |||||||
|     true |     true | ||||||
| } | } | ||||||
|  |  | ||||||
| // signature, timestamp, id |  | ||||||
| type PendingQueue = Vec<(Signature, u64, u64)>; |  | ||||||
|  |  | ||||||
| struct TransactionExecutor { |  | ||||||
|     sig_clear_t: JoinHandle<()>, |  | ||||||
|     sigs: Arc<RwLock<PendingQueue>>, |  | ||||||
|     cleared: Arc<RwLock<Vec<u64>>>, |  | ||||||
|     exit: Arc<AtomicBool>, |  | ||||||
|     counter: AtomicU64, |  | ||||||
|     client: RpcClient, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl TransactionExecutor { |  | ||||||
|     fn new(entrypoint_addr: SocketAddr) -> Self { |  | ||||||
|         let sigs = Arc::new(RwLock::new(Vec::new())); |  | ||||||
|         let cleared = Arc::new(RwLock::new(Vec::new())); |  | ||||||
|         let exit = Arc::new(AtomicBool::new(false)); |  | ||||||
|         let sig_clear_t = Self::start_sig_clear_thread(&exit, &sigs, &cleared, entrypoint_addr); |  | ||||||
|         let client = |  | ||||||
|             RpcClient::new_socket_with_commitment(entrypoint_addr, CommitmentConfig::confirmed()); |  | ||||||
|         Self { |  | ||||||
|             sigs, |  | ||||||
|             cleared, |  | ||||||
|             sig_clear_t, |  | ||||||
|             exit, |  | ||||||
|             counter: AtomicU64::new(0), |  | ||||||
|             client, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn num_outstanding(&self) -> usize { |  | ||||||
|         self.sigs.read().unwrap().len() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn push_transactions(&self, txs: Vec<Transaction>) -> Vec<u64> { |  | ||||||
|         let mut ids = vec![]; |  | ||||||
|         let new_sigs = txs.into_iter().filter_map(|tx| { |  | ||||||
|             let id = self.counter.fetch_add(1, Ordering::Relaxed); |  | ||||||
|             ids.push(id); |  | ||||||
|             match self.client.send_transaction(&tx) { |  | ||||||
|                 Ok(sig) => { |  | ||||||
|                     return Some((sig, timestamp(), id)); |  | ||||||
|                 } |  | ||||||
|                 Err(e) => { |  | ||||||
|                     info!("error: {:#?}", e); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             None |  | ||||||
|         }); |  | ||||||
|         let mut sigs_w = self.sigs.write().unwrap(); |  | ||||||
|         sigs_w.extend(new_sigs); |  | ||||||
|         ids |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn drain_cleared(&self) -> Vec<u64> { |  | ||||||
|         std::mem::take(&mut *self.cleared.write().unwrap()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn close(self) { |  | ||||||
|         self.exit.store(true, Ordering::Relaxed); |  | ||||||
|         self.sig_clear_t.join().unwrap(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn start_sig_clear_thread( |  | ||||||
|         exit: &Arc<AtomicBool>, |  | ||||||
|         sigs: &Arc<RwLock<PendingQueue>>, |  | ||||||
|         cleared: &Arc<RwLock<Vec<u64>>>, |  | ||||||
|         entrypoint_addr: SocketAddr, |  | ||||||
|     ) -> JoinHandle<()> { |  | ||||||
|         let sigs = sigs.clone(); |  | ||||||
|         let exit = exit.clone(); |  | ||||||
|         let cleared = cleared.clone(); |  | ||||||
|         Builder::new() |  | ||||||
|             .name("sig_clear".to_string()) |  | ||||||
|             .spawn(move || { |  | ||||||
|                 let client = RpcClient::new_socket_with_commitment( |  | ||||||
|                     entrypoint_addr, |  | ||||||
|                     CommitmentConfig::confirmed(), |  | ||||||
|                 ); |  | ||||||
|                 let mut success = 0; |  | ||||||
|                 let mut error_count = 0; |  | ||||||
|                 let mut timed_out = 0; |  | ||||||
|                 let mut last_log = Instant::now(); |  | ||||||
|                 while !exit.load(Ordering::Relaxed) { |  | ||||||
|                     let sigs_len = sigs.read().unwrap().len(); |  | ||||||
|                     if sigs_len > 0 { |  | ||||||
|                         let mut sigs_w = sigs.write().unwrap(); |  | ||||||
|                         let mut start = Measure::start("sig_status"); |  | ||||||
|                         let statuses: Vec<_> = sigs_w |  | ||||||
|                             .chunks(200) |  | ||||||
|                             .flat_map(|sig_chunk| { |  | ||||||
|                                 let only_sigs: Vec<_> = sig_chunk.iter().map(|s| s.0).collect(); |  | ||||||
|                                 client |  | ||||||
|                                     .get_signature_statuses(&only_sigs) |  | ||||||
|                                     .expect("status fail") |  | ||||||
|                                     .value |  | ||||||
|                             }) |  | ||||||
|                             .collect(); |  | ||||||
|                         let mut num_cleared = 0; |  | ||||||
|                         let start_len = sigs_w.len(); |  | ||||||
|                         let now = timestamp(); |  | ||||||
|                         let mut new_ids = vec![]; |  | ||||||
|                         let mut i = 0; |  | ||||||
|                         let mut j = 0; |  | ||||||
|                         while i != sigs_w.len() { |  | ||||||
|                             let mut retain = true; |  | ||||||
|                             let sent_ts = sigs_w[i].1; |  | ||||||
|                             if let Some(e) = &statuses[j] { |  | ||||||
|                                 debug!("error: {:?}", e); |  | ||||||
|                                 if e.status.is_ok() { |  | ||||||
|                                     success += 1; |  | ||||||
|                                 } else { |  | ||||||
|                                     error_count += 1; |  | ||||||
|                                 } |  | ||||||
|                                 num_cleared += 1; |  | ||||||
|                                 retain = false; |  | ||||||
|                             } else if now - sent_ts > 30_000 { |  | ||||||
|                                 retain = false; |  | ||||||
|                                 timed_out += 1; |  | ||||||
|                             } |  | ||||||
|                             if !retain { |  | ||||||
|                                 new_ids.push(sigs_w.remove(i).2); |  | ||||||
|                             } else { |  | ||||||
|                                 i += 1; |  | ||||||
|                             } |  | ||||||
|                             j += 1; |  | ||||||
|                         } |  | ||||||
|                         let final_sigs_len = sigs_w.len(); |  | ||||||
|                         drop(sigs_w); |  | ||||||
|                         cleared.write().unwrap().extend(new_ids); |  | ||||||
|                         start.stop(); |  | ||||||
|                         debug!( |  | ||||||
|                             "sigs len: {:?} success: {} took: {}ms cleared: {}/{}", |  | ||||||
|                             final_sigs_len, |  | ||||||
|                             success, |  | ||||||
|                             start.as_ms(), |  | ||||||
|                             num_cleared, |  | ||||||
|                             start_len, |  | ||||||
|                         ); |  | ||||||
|                         if last_log.elapsed().as_millis() > 5000 { |  | ||||||
|                             info!( |  | ||||||
|                                 "success: {} error: {} timed_out: {}", |  | ||||||
|                                 success, error_count, timed_out, |  | ||||||
|                             ); |  | ||||||
|                             last_log = Instant::now(); |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     sleep(Duration::from_millis(200)); |  | ||||||
|                 } |  | ||||||
|             }) |  | ||||||
|             .unwrap() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct SeedTracker { | struct SeedTracker { | ||||||
|     max_created: Arc<AtomicU64>, |     max_created: Arc<AtomicU64>, | ||||||
|     max_closed: Arc<AtomicU64>, |     max_closed: Arc<AtomicU64>, | ||||||
| @@ -720,6 +564,7 @@ pub mod test { | |||||||
|         local_cluster::{ClusterConfig, LocalCluster}, |         local_cluster::{ClusterConfig, LocalCluster}, | ||||||
|         validator_configs::make_identical_validator_configs, |         validator_configs::make_identical_validator_configs, | ||||||
|     }; |     }; | ||||||
|  |     use solana_measure::measure::Measure; | ||||||
|     use solana_sdk::poh_config::PohConfig; |     use solana_sdk::poh_config::PohConfig; | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ solana-account-decoder = { path = "../account-decoder", version = "=1.9.0" } | |||||||
| solana-clap-utils = { path = "../clap-utils", version = "=1.9.0" } | solana-clap-utils = { path = "../clap-utils", version = "=1.9.0" } | ||||||
| solana-faucet = { path = "../faucet", version = "=1.9.0" } | solana-faucet = { path = "../faucet", version = "=1.9.0" } | ||||||
| solana-net-utils = { path = "../net-utils", version = "=1.9.0" } | solana-net-utils = { path = "../net-utils", version = "=1.9.0" } | ||||||
|  | solana-measure = { path = "../measure", version = "=1.9.0" } | ||||||
| solana-sdk = { path = "../sdk", version = "=1.9.0" } | solana-sdk = { path = "../sdk", version = "=1.9.0" } | ||||||
| solana-transaction-status = { path = "../transaction-status", version = "=1.9.0" } | solana-transaction-status = { path = "../transaction-status", version = "=1.9.0" } | ||||||
| solana-version = { path = "../version", version = "=1.9.0" } | solana-version = { path = "../version", version = "=1.9.0" } | ||||||
|   | |||||||
| @@ -20,3 +20,4 @@ pub mod rpc_response; | |||||||
| pub mod rpc_sender; | pub mod rpc_sender; | ||||||
| pub mod thin_client; | pub mod thin_client; | ||||||
| pub mod tpu_client; | pub mod tpu_client; | ||||||
|  | pub mod transaction_executor; | ||||||
|   | |||||||
							
								
								
									
										171
									
								
								client/src/transaction_executor.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								client/src/transaction_executor.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | #![allow(clippy::integer_arithmetic)] | ||||||
|  | use crate::rpc_client::RpcClient; | ||||||
|  | use log::*; | ||||||
|  | use solana_measure::measure::Measure; | ||||||
|  | use solana_sdk::{ | ||||||
|  |     commitment_config::CommitmentConfig, signature::Signature, timing::timestamp, | ||||||
|  |     transaction::Transaction, | ||||||
|  | }; | ||||||
|  | use std::{ | ||||||
|  |     net::SocketAddr, | ||||||
|  |     sync::{ | ||||||
|  |         atomic::{AtomicBool, AtomicU64, Ordering}, | ||||||
|  |         Arc, RwLock, | ||||||
|  |     }, | ||||||
|  |     thread::{sleep, Builder, JoinHandle}, | ||||||
|  |     time::{Duration, Instant}, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // signature, timestamp, id | ||||||
|  | type PendingQueue = Vec<(Signature, u64, u64)>; | ||||||
|  |  | ||||||
|  | pub struct TransactionExecutor { | ||||||
|  |     sig_clear_t: JoinHandle<()>, | ||||||
|  |     sigs: Arc<RwLock<PendingQueue>>, | ||||||
|  |     cleared: Arc<RwLock<Vec<u64>>>, | ||||||
|  |     exit: Arc<AtomicBool>, | ||||||
|  |     counter: AtomicU64, | ||||||
|  |     client: RpcClient, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TransactionExecutor { | ||||||
|  |     pub fn new(entrypoint_addr: SocketAddr) -> Self { | ||||||
|  |         let sigs = Arc::new(RwLock::new(Vec::new())); | ||||||
|  |         let cleared = Arc::new(RwLock::new(Vec::new())); | ||||||
|  |         let exit = Arc::new(AtomicBool::new(false)); | ||||||
|  |         let sig_clear_t = Self::start_sig_clear_thread(&exit, &sigs, &cleared, entrypoint_addr); | ||||||
|  |         let client = | ||||||
|  |             RpcClient::new_socket_with_commitment(entrypoint_addr, CommitmentConfig::confirmed()); | ||||||
|  |         Self { | ||||||
|  |             sigs, | ||||||
|  |             cleared, | ||||||
|  |             sig_clear_t, | ||||||
|  |             exit, | ||||||
|  |             counter: AtomicU64::new(0), | ||||||
|  |             client, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn num_outstanding(&self) -> usize { | ||||||
|  |         self.sigs.read().unwrap().len() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn push_transactions(&self, txs: Vec<Transaction>) -> Vec<u64> { | ||||||
|  |         let mut ids = vec![]; | ||||||
|  |         let new_sigs = txs.into_iter().filter_map(|tx| { | ||||||
|  |             let id = self.counter.fetch_add(1, Ordering::Relaxed); | ||||||
|  |             ids.push(id); | ||||||
|  |             match self.client.send_transaction(&tx) { | ||||||
|  |                 Ok(sig) => { | ||||||
|  |                     return Some((sig, timestamp(), id)); | ||||||
|  |                 } | ||||||
|  |                 Err(e) => { | ||||||
|  |                     info!("error: {:#?}", e); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             None | ||||||
|  |         }); | ||||||
|  |         let mut sigs_w = self.sigs.write().unwrap(); | ||||||
|  |         sigs_w.extend(new_sigs); | ||||||
|  |         ids | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn drain_cleared(&self) -> Vec<u64> { | ||||||
|  |         std::mem::take(&mut *self.cleared.write().unwrap()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn close(self) { | ||||||
|  |         self.exit.store(true, Ordering::Relaxed); | ||||||
|  |         self.sig_clear_t.join().unwrap(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn start_sig_clear_thread( | ||||||
|  |         exit: &Arc<AtomicBool>, | ||||||
|  |         sigs: &Arc<RwLock<PendingQueue>>, | ||||||
|  |         cleared: &Arc<RwLock<Vec<u64>>>, | ||||||
|  |         entrypoint_addr: SocketAddr, | ||||||
|  |     ) -> JoinHandle<()> { | ||||||
|  |         let sigs = sigs.clone(); | ||||||
|  |         let exit = exit.clone(); | ||||||
|  |         let cleared = cleared.clone(); | ||||||
|  |         Builder::new() | ||||||
|  |             .name("sig_clear".to_string()) | ||||||
|  |             .spawn(move || { | ||||||
|  |                 let client = RpcClient::new_socket_with_commitment( | ||||||
|  |                     entrypoint_addr, | ||||||
|  |                     CommitmentConfig::confirmed(), | ||||||
|  |                 ); | ||||||
|  |                 let mut success = 0; | ||||||
|  |                 let mut error_count = 0; | ||||||
|  |                 let mut timed_out = 0; | ||||||
|  |                 let mut last_log = Instant::now(); | ||||||
|  |                 while !exit.load(Ordering::Relaxed) { | ||||||
|  |                     let sigs_len = sigs.read().unwrap().len(); | ||||||
|  |                     if sigs_len > 0 { | ||||||
|  |                         let mut sigs_w = sigs.write().unwrap(); | ||||||
|  |                         let mut start = Measure::start("sig_status"); | ||||||
|  |                         let statuses: Vec<_> = sigs_w | ||||||
|  |                             .chunks(200) | ||||||
|  |                             .flat_map(|sig_chunk| { | ||||||
|  |                                 let only_sigs: Vec<_> = sig_chunk.iter().map(|s| s.0).collect(); | ||||||
|  |                                 client | ||||||
|  |                                     .get_signature_statuses(&only_sigs) | ||||||
|  |                                     .expect("status fail") | ||||||
|  |                                     .value | ||||||
|  |                             }) | ||||||
|  |                             .collect(); | ||||||
|  |                         let mut num_cleared = 0; | ||||||
|  |                         let start_len = sigs_w.len(); | ||||||
|  |                         let now = timestamp(); | ||||||
|  |                         let mut new_ids = vec![]; | ||||||
|  |                         let mut i = 0; | ||||||
|  |                         let mut j = 0; | ||||||
|  |                         while i != sigs_w.len() { | ||||||
|  |                             let mut retain = true; | ||||||
|  |                             let sent_ts = sigs_w[i].1; | ||||||
|  |                             if let Some(e) = &statuses[j] { | ||||||
|  |                                 debug!("error: {:?}", e); | ||||||
|  |                                 if e.status.is_ok() { | ||||||
|  |                                     success += 1; | ||||||
|  |                                 } else { | ||||||
|  |                                     error_count += 1; | ||||||
|  |                                 } | ||||||
|  |                                 num_cleared += 1; | ||||||
|  |                                 retain = false; | ||||||
|  |                             } else if now - sent_ts > 30_000 { | ||||||
|  |                                 retain = false; | ||||||
|  |                                 timed_out += 1; | ||||||
|  |                             } | ||||||
|  |                             if !retain { | ||||||
|  |                                 new_ids.push(sigs_w.remove(i).2); | ||||||
|  |                             } else { | ||||||
|  |                                 i += 1; | ||||||
|  |                             } | ||||||
|  |                             j += 1; | ||||||
|  |                         } | ||||||
|  |                         let final_sigs_len = sigs_w.len(); | ||||||
|  |                         drop(sigs_w); | ||||||
|  |                         cleared.write().unwrap().extend(new_ids); | ||||||
|  |                         start.stop(); | ||||||
|  |                         debug!( | ||||||
|  |                             "sigs len: {:?} success: {} took: {}ms cleared: {}/{}", | ||||||
|  |                             final_sigs_len, | ||||||
|  |                             success, | ||||||
|  |                             start.as_ms(), | ||||||
|  |                             num_cleared, | ||||||
|  |                             start_len, | ||||||
|  |                         ); | ||||||
|  |                         if last_log.elapsed().as_millis() > 5000 { | ||||||
|  |                             info!( | ||||||
|  |                                 "success: {} error: {} timed_out: {}", | ||||||
|  |                                 success, error_count, timed_out, | ||||||
|  |                             ); | ||||||
|  |                             last_log = Instant::now(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     sleep(Duration::from_millis(200)); | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .unwrap() | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								programs/bpf/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								programs/bpf/Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -2904,6 +2904,7 @@ dependencies = [ | |||||||
|  "solana-account-decoder", |  "solana-account-decoder", | ||||||
|  "solana-clap-utils", |  "solana-clap-utils", | ||||||
|  "solana-faucet", |  "solana-faucet", | ||||||
|  |  "solana-measure", | ||||||
|  "solana-net-utils", |  "solana-net-utils", | ||||||
|  "solana-sdk", |  "solana-sdk", | ||||||
|  "solana-transaction-status", |  "solana-transaction-status", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user