Skip to content

Commit 4ef9583

Browse files
authored
Update thread retry logic to avoid unnecessary retries (#253)
* Increase the timeout window for threads * Adjust backoff values * Update logic related to thread retries
1 parent 2faa059 commit 4ef9583

1 file changed

Lines changed: 31 additions & 19 deletions

File tree

  • plugin/src/executors

plugin/src/executors/tx.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ use crate::{config::PluginConfig, pool_position::PoolPosition, utils::read_or_ne
3434
use super::AccountGet;
3535

3636
/// Number of slots to wait before checking for a confirmed transaction.
37-
static TRANSACTION_CONFIRMATION_PERIOD: u64 = 10;
37+
static TRANSACTION_CONFIRMATION_PERIOD: u64 = 24;
3838

3939
/// Number of slots to wait before trying to execute a thread while not in the pool.
40-
static THREAD_TIMEOUT_WINDOW: u64 = 8;
40+
static THREAD_TIMEOUT_WINDOW: u64 = 24;
4141

4242
/// Number of times to retry a thread simulation.
4343
static MAX_THREAD_SIMULATION_FAILURES: u32 = 5;
@@ -46,7 +46,7 @@ static MAX_THREAD_SIMULATION_FAILURES: u32 = 5;
4646
static EXPONENTIAL_BACKOFF_CONSTANT: u32 = 2;
4747

4848
/// The number of slots to wait since the last rotation attempt.
49-
static ROTATION_CONFIRMATION_PERIOD: u64 = 9;
49+
static ROTATION_CONFIRMATION_PERIOD: u64 = 16;
5050

5151
/// TxExecutor
5252
pub struct TxExecutor {
@@ -66,7 +66,8 @@ pub struct ExecutableThreadMetadata {
6666

6767
#[derive(Debug)]
6868
pub struct TransactionMetadata {
69-
pub slot_sent: u64,
69+
pub due_slot: u64,
70+
pub sent_slot: u64,
7071
pub signature: Signature,
7172
}
7273

@@ -163,14 +164,16 @@ impl TxExecutor {
163164
) -> PluginResult<()> {
164165
// Get transaction signatures and corresponding threads to check.
165166
struct CheckableTransaction {
167+
due_slot: u64,
166168
thread_pubkey: Pubkey,
167169
signature: Signature,
168170
}
169171
let r_transaction_history = self.transaction_history.read().await;
170172
let checkable_transactions = r_transaction_history
171173
.iter()
172-
.filter(|(_, metadata)| slot > metadata.slot_sent + TRANSACTION_CONFIRMATION_PERIOD)
174+
.filter(|(_, metadata)| slot > metadata.sent_slot + TRANSACTION_CONFIRMATION_PERIOD)
173175
.map(|(pubkey, metadata)| CheckableTransaction {
176+
due_slot: metadata.due_slot,
174177
thread_pubkey: *pubkey,
175178
signature: metadata.signature,
176179
})
@@ -179,7 +182,7 @@ impl TxExecutor {
179182

180183
// Lookup transaction statuses and track which threads are successful / retriable.
181184
let mut failed_threads: HashSet<Pubkey> = HashSet::new();
182-
let mut retriable_threads: HashSet<Pubkey> = HashSet::new();
185+
let mut retriable_threads: HashSet<(Pubkey, u64)> = HashSet::new();
183186
let mut successful_threads: HashSet<Pubkey> = HashSet::new();
184187
for data in checkable_transactions {
185188
match client
@@ -196,7 +199,7 @@ impl TxExecutor {
196199
"Retrying thread: {:?} missing_signature: {:?}",
197200
data.thread_pubkey, data.signature
198201
);
199-
retriable_threads.insert(data.thread_pubkey);
202+
retriable_threads.insert((data.thread_pubkey, data.due_slot));
200203
}
201204
Some(status) => match status {
202205
Err(err) => {
@@ -223,12 +226,12 @@ impl TxExecutor {
223226
for pubkey in failed_threads {
224227
w_transaction_history.remove(&pubkey);
225228
}
226-
for pubkey in retriable_threads {
229+
for (pubkey, due_slot) in retriable_threads {
227230
w_transaction_history.remove(&pubkey);
228231
w_executable_threads.insert(
229232
pubkey,
230233
ExecutableThreadMetadata {
231-
due_slot: slot,
234+
due_slot,
232235
simulation_failures: 0,
233236
},
234237
);
@@ -251,7 +254,7 @@ impl TxExecutor {
251254
let rotation_history = r_rotation_history.as_ref().unwrap();
252255
if slot
253256
> rotation_history
254-
.slot_sent
257+
.sent_slot
255258
.checked_add(ROTATION_CONFIRMATION_PERIOD)
256259
.unwrap()
257260
{
@@ -297,7 +300,8 @@ impl TxExecutor {
297300
self.clone().submit_tx(&tx).await?;
298301
let mut w_rotation_history = self.rotation_history.write().await;
299302
*w_rotation_history = Some(TransactionMetadata {
300-
slot_sent: slot,
303+
due_slot: slot,
304+
sent_slot: slot,
301305
signature: tx.signatures[0],
302306
});
303307
drop(w_rotation_history);
@@ -364,7 +368,7 @@ impl TxExecutor {
364368
))
365369
})
366370
.collect();
367-
let mut executed_threads: HashMap<Pubkey, Signature> = HashMap::new();
371+
let mut executed_threads: HashMap<Pubkey, (Signature, u64)> = HashMap::new();
368372

369373
// Serialize to wire transactions.
370374
let wire_txs = futures::future::join_all(tasks)
@@ -374,8 +378,8 @@ impl TxExecutor {
374378
Err(_err) => None,
375379
Ok(res) => match res {
376380
None => None,
377-
Some((pubkey, tx)) => {
378-
executed_threads.insert(*pubkey, tx.signatures[0]);
381+
Some((pubkey, tx, due_slot)) => {
382+
executed_threads.insert(*pubkey, (tx.signatures[0], *due_slot));
379383
Some(tx)
380384
}
381385
},
@@ -399,12 +403,13 @@ impl TxExecutor {
399403
Ok(()) => {
400404
let mut w_executable_threads = self.executable_threads.write().await;
401405
let mut w_transaction_history = self.transaction_history.write().await;
402-
for (pubkey, signature) in executed_threads {
406+
for (pubkey, (signature, due_slot)) in executed_threads {
403407
w_executable_threads.remove(&pubkey);
404408
w_transaction_history.insert(
405409
pubkey,
406410
TransactionMetadata {
407-
slot_sent: observed_slot,
411+
due_slot,
412+
sent_slot: observed_slot,
408413
signature,
409414
},
410415
);
@@ -423,7 +428,7 @@ impl TxExecutor {
423428
observed_slot: u64,
424429
due_slot: u64,
425430
thread_pubkey: Pubkey,
426-
) -> Option<(Pubkey, Transaction)> {
431+
) -> Option<(Pubkey, Transaction, u64)> {
427432
let thread = match client.clone().get::<VersionedThread>(&thread_pubkey).await {
428433
Err(_err) => {
429434
self.increment_simulation_failure(thread_pubkey).await;
@@ -432,6 +437,13 @@ impl TxExecutor {
432437
Ok(thread) => thread,
433438
};
434439

440+
// Exit early if the thread has been executed after it became due.
441+
if let Some(exec_context) = thread.exec_context() {
442+
if exec_context.last_exec_at.gt(&due_slot) {
443+
return None;
444+
}
445+
}
446+
435447
if let Ok(tx) = crate::builders::build_thread_exec_tx(
436448
client.clone(),
437449
&self.keypair,
@@ -449,7 +461,7 @@ impl TxExecutor {
449461
.await
450462
.is_ok()
451463
{
452-
Some((thread_pubkey, tx))
464+
Some((thread_pubkey, tx, due_slot))
453465
} else {
454466
None
455467
}
@@ -478,7 +490,7 @@ impl TxExecutor {
478490
) -> PluginResult<()> {
479491
let r_transaction_history = self.transaction_history.read().await;
480492
if let Some(metadata) = r_transaction_history.get(&thread_pubkey) {
481-
if metadata.signature.eq(&tx.signatures[0]) && metadata.slot_sent.le(&slot) {
493+
if metadata.signature.eq(&tx.signatures[0]) && metadata.sent_slot.le(&slot) {
482494
return Err(GeyserPluginError::Custom(format!("Transaction signature is a duplicate of a previously submitted transaction").into()));
483495
}
484496
}

0 commit comments

Comments
 (0)