Skip to content

Commit

Permalink
Add skip_preflight setting for solana rpc (#949)
Browse files Browse the repository at this point in the history
In Oracle's we have historically had skip_preflight: true for all txns.
There have been updates to helium-lib that we cannot debug if preflight checks are skipped.
This PR turns it into a setting, so it can toggle when we need better errors.
  • Loading branch information
michaeldjeffrey authored Feb 19, 2025
1 parent 66bf4c1 commit 22d0393
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
16 changes: 14 additions & 2 deletions solana/src/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use async_trait::async_trait;
use helium_crypto::PublicKeyBinary;
use helium_lib::{client, dc, token, TransactionOpts};
use serde::Deserialize;
use solana_client::rpc_config::RpcSendTransactionConfig;
use solana_sdk::{commitment_config::CommitmentConfig, signature::Signature};
use std::str::FromStr;
use std::sync::Arc;
Expand Down Expand Up @@ -38,6 +39,7 @@ pub struct Settings {
payers_to_monitor: Vec<String>,
#[serde(default = "default_min_priority_fee")]
min_priority_fee: u64,
skip_preflight: bool,
}

fn default_min_priority_fee() -> u64 {
Expand All @@ -60,6 +62,7 @@ pub struct SolanaRpc {
keypair: Keypair,
payers_to_monitor: Vec<PublicKeyBinary>,
transaction_opts: TransactionOpts,
skip_preflight: bool,
}

impl SolanaRpc {
Expand All @@ -72,6 +75,7 @@ impl SolanaRpc {

tracing::info!(
min_priority_fee = settings.min_priority_fee,
skip_preflight = settings.skip_preflight,
"initialize solana"
);

Expand All @@ -80,6 +84,7 @@ impl SolanaRpc {
provider,
keypair,
payers_to_monitor: settings.payers_to_monitor()?,
skip_preflight: settings.skip_preflight,
transaction_opts: TransactionOpts {
min_priority_fee: settings.min_priority_fee,
..Default::default()
Expand Down Expand Up @@ -151,7 +156,11 @@ impl SolanaNetwork for SolanaRpc {
tx: &Self::Transaction,
store: &impl sender::TxnStore,
) -> Result<(), SolanaRpcError> {
match sender::send_and_finalize(&self, tx, store).await {
let config = RpcSendTransactionConfig {
skip_preflight: self.skip_preflight,
..Default::default()
};
match sender::send_and_finalize(&self, tx, config, store).await {
Ok(_tracked) => {
let signature = tx.get_signature();
tracing::info!(
Expand Down Expand Up @@ -260,6 +269,7 @@ pub mod test_client {

use helium_crypto::PublicKeyBinary;
use helium_lib::keypair::Signature;
use solana_client::rpc_config::RpcSendTransactionConfig;
use tokio::sync::Mutex;

use crate::{sender, SolanaRpcError, SolanaTransaction, Transaction};
Expand Down Expand Up @@ -368,7 +378,8 @@ pub mod test_client {
panic!("attempting to send transaction");
}
// Test client must attempt to send for changes to take place
sender::send_and_finalize(self, txn, store).await?;
sender::send_and_finalize(self, txn, RpcSendTransactionConfig::default(), store)
.await?;

let signature = txn.get_signature();
if let Some((payer, amount)) = self.txn_sig_to_payer.lock().await.get(signature) {
Expand All @@ -391,6 +402,7 @@ pub mod test_client {
async fn send_txn(
&self,
txn: &Transaction,
_config: RpcSendTransactionConfig,
) -> Result<Signature, sender::SolanaClientError> {
Ok(*txn.get_signature())
}
Expand Down
42 changes: 27 additions & 15 deletions solana/src/sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ impl SenderError {
pub async fn send_and_finalize(
client: &impl SenderClientExt,
txn: &Transaction,
config: RpcSendTransactionConfig,
store: &impl TxnStore,
) -> SenderResult<()> {
let sent_block_height = client.get_block_height().await?;

store.on_prepared(txn).await?;
send_with_retry(client, txn, store).await?;
send_with_retry(client, txn, config, store).await?;
store.on_sent(txn).await;

finalize_signature(client, txn, store, sent_block_height).await?;
Expand All @@ -54,13 +55,14 @@ pub async fn send_and_finalize(
async fn send_with_retry(
client: &impl SenderClientExt,
txn: &Transaction,
config: RpcSendTransactionConfig,
store: &impl TxnStore,
) -> SenderResult<()> {
let backoff = store.make_backoff().into_iter();

for (attempt, duration) in backoff.enumerate() {
let attempt = attempt + 1; // 1-index loop
match client.send_txn(txn).await {
match client.send_txn(txn, config).await {
Ok(_sig) => return Ok(()),
Err(err) => match duration {
Some(duration) => {
Expand Down Expand Up @@ -106,7 +108,11 @@ async fn finalize_signature(

#[async_trait::async_trait]
pub trait SenderClientExt: Send + Sync {
async fn send_txn(&self, txn: &Transaction) -> Result<Signature, SolanaClientError>;
async fn send_txn(
&self,
txn: &Transaction,
config: RpcSendTransactionConfig,
) -> Result<Signature, SolanaClientError>;
async fn finalize_signature(&self, signature: &Signature) -> Result<(), SolanaClientError>;
async fn get_block_height(&self) -> Result<u64, SolanaClientError>;
}
Expand Down Expand Up @@ -138,12 +144,11 @@ pub trait TxnStore: Send + Sync {

#[async_trait::async_trait]
impl<T: AsRef<client::SolanaRpcClient> + Send + Sync> SenderClientExt for T {
async fn send_txn(&self, txn: &Transaction) -> Result<Signature, SolanaClientError> {
let config = RpcSendTransactionConfig {
skip_preflight: true,
..Default::default()
};

async fn send_txn(
&self,
txn: &Transaction,
config: RpcSendTransactionConfig,
) -> Result<Signature, SolanaClientError> {
Ok(self
.as_ref()
.send_transaction_with_config(txn, config)
Expand Down Expand Up @@ -253,7 +258,11 @@ mod tests {

#[async_trait::async_trait]
impl SenderClientExt for MockClient {
async fn send_txn(&self, txn: &Transaction) -> Result<Signature, SolanaClientError> {
async fn send_txn(
&self,
txn: &Transaction,
_config: RpcSendTransactionConfig,
) -> Result<Signature, SolanaClientError> {
let mut attempts = self.sent_attempts.lock().unwrap();
*attempts += 1;

Expand Down Expand Up @@ -298,7 +307,7 @@ mod tests {
let store = MockTxnStore::default();
let client = MockClient::succeed();

send_and_finalize(&client, &tx, &store).await?;
send_and_finalize(&client, &tx, RpcSendTransactionConfig::default(), &store).await?;

let signature = tx.get_signature();
let calls = store.calls.lock().unwrap();
Expand All @@ -320,7 +329,7 @@ mod tests {
let store = MockTxnStore::default();
let client = MockClient::succeed_after(5);

send_and_finalize(&client, &txn, &store).await?;
send_and_finalize(&client, &txn, RpcSendTransactionConfig::default(), &store).await?;

let signature = txn.get_signature();
let calls = store.calls.lock().unwrap();
Expand All @@ -346,7 +355,8 @@ mod tests {
let store = MockTxnStore::default();
let client = MockClient::succeed_after(999);

let res = send_and_finalize(&client, &txn, &store).await;
let res =
send_and_finalize(&client, &txn, RpcSendTransactionConfig::default(), &store).await;
assert!(res.is_err());

let signature = txn.get_signature();
Expand All @@ -373,7 +383,8 @@ mod tests {
let mut client = MockClient::succeed();
client.finalize_success = false;

let res = send_and_finalize(&client, &txn, &store).await;
let res =
send_and_finalize(&client, &txn, RpcSendTransactionConfig::default(), &store).await;
assert!(res.is_err());

let signature = txn.get_signature();
Expand All @@ -396,7 +407,8 @@ mod tests {
let store = MockTxnStore::fail_prepared();
let client = MockClient::succeed();

let res = send_and_finalize(&client, &txn, &store).await;
let res =
send_and_finalize(&client, &txn, RpcSendTransactionConfig::default(), &store).await;
assert!(res.is_err());

let calls = store.calls.lock().unwrap();
Expand Down

0 comments on commit 22d0393

Please sign in to comment.