1pub use crate::nonblocking::tpu_client::TpuSenderError;
2use {
3 crate::nonblocking::tpu_client::TpuClient as NonblockingTpuClient,
4 rayon::iter::{IntoParallelIterator, ParallelIterator},
5 solana_client_traits::AsyncClient,
6 solana_clock::Slot,
7 solana_connection_cache::{
8 client_connection::ClientConnection,
9 connection_cache::{
10 ConnectionCache, ConnectionManager, ConnectionPool, NewConnectionConfig,
11 },
12 },
13 solana_rpc_client::rpc_client::RpcClient,
14 solana_signature::Signature,
15 solana_transaction::{Transaction, versioned::VersionedTransaction},
16 solana_transaction_error::{TransportError, TransportResult},
17 std::{
18 collections::VecDeque,
19 sync::{Arc, RwLock},
20 },
21};
22#[cfg(feature = "spinner")]
23use {
24 solana_message::Message, solana_signer::signers::Signers,
25 solana_transaction_error::TransactionError, tokio::time::Duration,
26};
27
28pub const DEFAULT_VOTE_USE_QUIC: bool = false;
29
30pub const DEFAULT_TPU_CONNECTION_POOL_SIZE: usize = 1;
34
35pub type Result<T> = std::result::Result<T, TpuSenderError>;
36
37#[cfg(feature = "spinner")]
39pub(crate) const SEND_TRANSACTION_INTERVAL: Duration = Duration::from_millis(10);
40#[cfg(feature = "spinner")]
42pub(crate) const TRANSACTION_RESEND_INTERVAL: Duration = Duration::from_secs(4);
43
44pub const DEFAULT_FANOUT_SLOTS: u64 = 12;
46
47pub const MAX_FANOUT_SLOTS: u64 = 100;
49
50#[derive(Clone, Debug)]
52pub struct TpuClientConfig {
53 pub fanout_slots: u64,
56}
57
58impl Default for TpuClientConfig {
59 fn default() -> Self {
60 Self {
61 fanout_slots: DEFAULT_FANOUT_SLOTS,
62 }
63 }
64}
65
66pub struct TpuClient<
69 P, M, C, > {
73 rpc_client: Arc<RpcClient>,
74 tpu_client: Arc<NonblockingTpuClient<P, M, C>>,
75}
76
77impl<P, M, C> TpuClient<P, M, C>
78where
79 P: ConnectionPool<NewConnectionConfig = C>,
80 M: ConnectionManager<ConnectionPool = P, NewConnectionConfig = C>,
81 C: NewConnectionConfig,
82{
83 pub fn send_transaction(&self, transaction: &Transaction) -> bool {
86 self.invoke(self.tpu_client.send_transaction(transaction))
87 }
88
89 pub fn send_wire_transaction(&self, wire_transaction: Vec<u8>) -> bool {
91 self.invoke(self.tpu_client.send_wire_transaction(wire_transaction))
92 }
93
94 pub fn try_send_transaction(&self, transaction: &VersionedTransaction) -> TransportResult<()> {
98 self.invoke(self.tpu_client.try_send_transaction(transaction))
99 }
100
101 pub fn send_transaction_to_upcoming_leaders(
107 &self,
108 transaction: &Transaction,
109 ) -> TransportResult<()> {
110 let wire_transaction =
111 Arc::new(wincode::serialize(&transaction).expect("should serialize transaction"));
112
113 let leaders = self
114 .tpu_client
115 .get_leader_tpu_service()
116 .unique_leader_tpu_sockets(self.tpu_client.get_fanout_slots());
117
118 let mut last_error: Option<TransportError> = None;
119 let mut some_success = false;
120 for tpu_address in &leaders {
121 let cache = self.tpu_client.get_connection_cache();
122 let conn = cache.get_connection(tpu_address);
123 if let Err(err) = conn.send_data_async(wire_transaction.clone()) {
124 last_error = Some(err);
125 } else {
126 some_success = true;
127 }
128 }
129
130 if let Some(err) = last_error {
131 Err(err)
132 } else if !some_success {
133 Err(std::io::Error::other("No sends attempted").into())
134 } else {
135 Ok(())
136 }
137 }
138
139 pub fn try_send_transaction_batch(
143 &self,
144 transactions: &[VersionedTransaction],
145 ) -> TransportResult<()> {
146 let wire_transactions = transactions
147 .into_par_iter()
148 .map(|tx| wincode::serialize(&tx).expect("serialize Transaction in send_batch"))
149 .collect::<Vec<_>>();
150 self.invoke(
151 self.tpu_client
152 .try_send_wire_transaction_batch(wire_transactions),
153 )
154 }
155
156 pub fn try_send_wire_transaction(&self, wire_transaction: Vec<u8>) -> TransportResult<()> {
159 self.invoke(self.tpu_client.try_send_wire_transaction(wire_transaction))
160 }
161
162 pub fn try_send_wire_transaction_batch(
163 &self,
164 wire_transactions: Vec<Vec<u8>>,
165 ) -> TransportResult<()> {
166 self.invoke(
167 self.tpu_client
168 .try_send_wire_transaction_batch(wire_transactions),
169 )
170 }
171
172 pub fn new(
174 name: &'static str,
175 rpc_client: Arc<RpcClient>,
176 websocket_url: &str,
177 config: TpuClientConfig,
178 connection_manager: M,
179 ) -> Result<Self> {
180 let create_tpu_client = NonblockingTpuClient::new(
181 name,
182 rpc_client.get_inner_client().clone(),
183 websocket_url,
184 config,
185 connection_manager,
186 );
187 let tpu_client =
188 tokio::task::block_in_place(|| rpc_client.runtime().block_on(create_tpu_client))?;
189
190 Ok(Self {
191 rpc_client,
192 tpu_client: Arc::new(tpu_client),
193 })
194 }
195
196 pub fn new_with_connection_cache(
198 rpc_client: Arc<RpcClient>,
199 websocket_url: &str,
200 config: TpuClientConfig,
201 connection_cache: Arc<ConnectionCache<P, M, C>>,
202 ) -> Result<Self> {
203 let create_tpu_client = NonblockingTpuClient::new_with_connection_cache(
204 rpc_client.get_inner_client().clone(),
205 websocket_url,
206 config,
207 connection_cache,
208 );
209 let tpu_client =
210 tokio::task::block_in_place(|| rpc_client.runtime().block_on(create_tpu_client))?;
211
212 Ok(Self {
213 rpc_client,
214 tpu_client: Arc::new(tpu_client),
215 })
216 }
217
218 #[cfg(feature = "spinner")]
219 pub fn send_and_confirm_messages_with_spinner<T: Signers + ?Sized>(
220 &self,
221 messages: &[Message],
222 signers: &T,
223 ) -> Result<Vec<Option<TransactionError>>> {
224 self.invoke(
225 self.tpu_client
226 .send_and_confirm_messages_with_spinner(messages, signers),
227 )
228 }
229
230 pub fn rpc_client(&self) -> &RpcClient {
231 &self.rpc_client
232 }
233
234 fn invoke<T, F: std::future::Future<Output = T>>(&self, f: F) -> T {
235 tokio::task::block_in_place(move || self.rpc_client.runtime().block_on(f))
239 }
240}
241
242impl<P, M, C> AsyncClient for TpuClient<P, M, C>
245where
246 P: ConnectionPool<NewConnectionConfig = C>,
247 M: ConnectionManager<ConnectionPool = P, NewConnectionConfig = C>,
248 C: NewConnectionConfig,
249{
250 fn async_send_versioned_transaction(
251 &self,
252 transaction: VersionedTransaction,
253 ) -> TransportResult<Signature> {
254 let wire_transaction =
255 wincode::serialize(&transaction).expect("serialize Transaction in send_batch");
256 self.send_wire_transaction(wire_transaction);
257 Ok(transaction.signatures[0])
258 }
259
260 fn async_send_versioned_transaction_batch(
261 &self,
262 batch: Vec<VersionedTransaction>,
263 ) -> TransportResult<()> {
264 let buffers = batch
265 .into_par_iter()
266 .map(|tx| wincode::serialize(&tx).expect("serialize Transaction in send_batch"))
267 .collect::<Vec<_>>();
268 self.try_send_wire_transaction_batch(buffers)?;
269 Ok(())
270 }
271}
272
273const MAX_SLOT_SKIP_DISTANCE: u64 = 48;
275
276#[derive(Clone, Debug)]
277pub(crate) struct RecentLeaderSlots(Arc<RwLock<VecDeque<Slot>>>);
278impl RecentLeaderSlots {
279 pub(crate) fn new(current_slot: Slot) -> Self {
280 let mut recent_slots = VecDeque::new();
281 recent_slots.push_back(current_slot);
282 Self(Arc::new(RwLock::new(recent_slots)))
283 }
284
285 pub(crate) fn record_slot(&self, current_slot: Slot) {
286 let mut recent_slots = self.0.write().unwrap();
287 recent_slots.push_back(current_slot);
288 while recent_slots.len() > 12 {
291 recent_slots.pop_front();
292 }
293 }
294
295 pub(crate) fn estimated_current_slot(&self) -> Slot {
297 let mut recent_slots: Vec<Slot> = self.0.read().unwrap().iter().cloned().collect();
298 assert!(!recent_slots.is_empty());
299 recent_slots.sort_unstable();
300
301 let max_index = recent_slots.len() - 1;
304 let median_index = max_index / 2;
305 let median_recent_slot = recent_slots[median_index];
306 let expected_current_slot = median_recent_slot + (max_index - median_index) as u64;
307 let max_reasonable_current_slot = expected_current_slot + MAX_SLOT_SKIP_DISTANCE;
308
309 recent_slots
312 .into_iter()
313 .rev()
314 .find(|slot| *slot <= max_reasonable_current_slot)
315 .unwrap()
316 }
317}
318
319#[cfg(test)]
320impl From<Vec<Slot>> for RecentLeaderSlots {
321 fn from(recent_slots: Vec<Slot>) -> Self {
322 assert!(!recent_slots.is_empty());
323 Self(Arc::new(RwLock::new(recent_slots.into_iter().collect())))
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 fn assert_slot(recent_slots: RecentLeaderSlots, expected_slot: Slot) {
332 assert_eq!(recent_slots.estimated_current_slot(), expected_slot);
333 }
334
335 #[test]
336 fn test_recent_leader_slots() {
337 assert_slot(RecentLeaderSlots::new(0), 0);
338
339 let mut recent_slots: Vec<Slot> = (1..=12).collect();
340 assert_slot(RecentLeaderSlots::from(recent_slots.clone()), 12);
341
342 recent_slots.reverse();
343 assert_slot(RecentLeaderSlots::from(recent_slots), 12);
344
345 assert_slot(
346 RecentLeaderSlots::from(vec![0, 1 + MAX_SLOT_SKIP_DISTANCE]),
347 1 + MAX_SLOT_SKIP_DISTANCE,
348 );
349 assert_slot(
350 RecentLeaderSlots::from(vec![0, 2 + MAX_SLOT_SKIP_DISTANCE]),
351 0,
352 );
353
354 assert_slot(RecentLeaderSlots::from(vec![1]), 1);
355 assert_slot(RecentLeaderSlots::from(vec![1, 100]), 1);
356 assert_slot(RecentLeaderSlots::from(vec![1, 2, 100]), 2);
357 assert_slot(RecentLeaderSlots::from(vec![1, 2, 3, 100]), 3);
358 assert_slot(RecentLeaderSlots::from(vec![1, 2, 3, 99, 100]), 3);
359 }
360}