2023-05-11 04:45:49 -07:00
<!DOCTYPE html> < html lang = "en" > < head > < meta charset = "utf-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < meta name = "generator" content = "rustdoc" > < meta name = "description" content = "Source of the Rust file `lib/client/src/util.rs`." > < title > util.rs - source< / title > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/SourceSerif4-Regular-46f98efaafac5295.ttf.woff2" > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/FiraSans-Regular-018c141bf0843ffd.woff2" > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/FiraSans-Medium-8f9a781e4970d388.woff2" > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2" > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2" > < link rel = "preload" as = "font" type = "font/woff2" crossorigin href = "../../static.files/SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2" > < link rel = "stylesheet" href = "../../static.files/normalize-76eba96aa4d2e634.css" > < link rel = "stylesheet" href = "../../static.files/rustdoc-c4dbdcde0fbd8430.css" id = "mainThemeStyle" > < link rel = "stylesheet" id = "themeStyle" href = "../../static.files/light-db279b6232be9c13.css" > < link rel = "stylesheet" disabled href = "../../static.files/dark-cf923f49f397b216.css" > < link rel = "stylesheet" disabled href = "../../static.files/ayu-be46fdc453a55015.css" > < script src = "../../static.files/storage-3891ce972e3a2bf8.js" > < / script > < script defer src = "../../static.files/source-script-1b95b7cca98b26e5.js" > < / script > < script defer src = "../../source-files.js" > < / script > < script defer src = "../../static.files/main-98a684e84ae5b08b.js" > < / script > < noscript > < link rel = "stylesheet" href = "../../static.files/noscript-13285aec31fa243e.css" > < / noscript > < link rel = "alternate icon" type = "image/png" href = "../../static.files/favicon-16x16-8b506e7a72182f1c.png" > < link rel = "alternate icon" type = "image/png" href = "../../static.files/favicon-32x32-422f7d1d52889060.png" > < link rel = "icon" type = "image/svg+xml" href = "../../static.files/favicon-2c020d218678b618.svg" > < / head > < body class = "rustdoc source" > <!-- [if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif] --> < nav class = "sidebar" > < / nav > < main > < nav class = "sub" > < a class = "sub-logo-container" href = "../../mango_v4_client/index.html" > < img class = "rust-logo" src = "../../static.files/rust-logo-151179464ae7ed46.svg" alt = "logo" > < / a > < form class = "search-form" > < span > < / span > < input class = "search-input" name = "search" aria-label = "Run search in the documentation" autocomplete = "off" spellcheck = "false" placeholder = "Click or press ‘ S’ to search, ‘ ?’ for more options…" type = "search" > < div id = "help-button" title = "help" tabindex = "-1" > < a href = "../../help.html" > ?< / a > < / div > < div id = "settings-menu" tabindex = "-1" > < a href = "../../settings.html" title = "settings" > < img width = "22" height = "22" alt = "Change settings" src = "../../static.files/wheel-7b819b6101059cd0.svg" > < / a > < / div > < / form > < / nav > < section id = "main-content" class = "content" > < div class = "example-wrap" > < pre class = "src-line-numbers" > < a href = "#1" id = "1" > 1< / a >
< a href = "#2" id = "2" > 2< / a >
< a href = "#3" id = "3" > 3< / a >
< a href = "#4" id = "4" > 4< / a >
< a href = "#5" id = "5" > 5< / a >
< a href = "#6" id = "6" > 6< / a >
< a href = "#7" id = "7" > 7< / a >
< a href = "#8" id = "8" > 8< / a >
< a href = "#9" id = "9" > 9< / a >
< a href = "#10" id = "10" > 10< / a >
< a href = "#11" id = "11" > 11< / a >
< a href = "#12" id = "12" > 12< / a >
< a href = "#13" id = "13" > 13< / a >
< a href = "#14" id = "14" > 14< / a >
< a href = "#15" id = "15" > 15< / a >
< a href = "#16" id = "16" > 16< / a >
< a href = "#17" id = "17" > 17< / a >
< a href = "#18" id = "18" > 18< / a >
< a href = "#19" id = "19" > 19< / a >
< a href = "#20" id = "20" > 20< / a >
< a href = "#21" id = "21" > 21< / a >
< a href = "#22" id = "22" > 22< / a >
< a href = "#23" id = "23" > 23< / a >
< a href = "#24" id = "24" > 24< / a >
< a href = "#25" id = "25" > 25< / a >
< a href = "#26" id = "26" > 26< / a >
< a href = "#27" id = "27" > 27< / a >
< a href = "#28" id = "28" > 28< / a >
< a href = "#29" id = "29" > 29< / a >
< a href = "#30" id = "30" > 30< / a >
< a href = "#31" id = "31" > 31< / a >
< a href = "#32" id = "32" > 32< / a >
< a href = "#33" id = "33" > 33< / a >
< a href = "#34" id = "34" > 34< / a >
< a href = "#35" id = "35" > 35< / a >
< a href = "#36" id = "36" > 36< / a >
< a href = "#37" id = "37" > 37< / a >
< a href = "#38" id = "38" > 38< / a >
< a href = "#39" id = "39" > 39< / a >
< a href = "#40" id = "40" > 40< / a >
< a href = "#41" id = "41" > 41< / a >
< a href = "#42" id = "42" > 42< / a >
< a href = "#43" id = "43" > 43< / a >
< a href = "#44" id = "44" > 44< / a >
< a href = "#45" id = "45" > 45< / a >
< a href = "#46" id = "46" > 46< / a >
< a href = "#47" id = "47" > 47< / a >
< a href = "#48" id = "48" > 48< / a >
< a href = "#49" id = "49" > 49< / a >
< a href = "#50" id = "50" > 50< / a >
< a href = "#51" id = "51" > 51< / a >
< a href = "#52" id = "52" > 52< / a >
< a href = "#53" id = "53" > 53< / a >
< a href = "#54" id = "54" > 54< / a >
< a href = "#55" id = "55" > 55< / a >
< a href = "#56" id = "56" > 56< / a >
< a href = "#57" id = "57" > 57< / a >
< a href = "#58" id = "58" > 58< / a >
< a href = "#59" id = "59" > 59< / a >
< a href = "#60" id = "60" > 60< / a >
< a href = "#61" id = "61" > 61< / a >
< a href = "#62" id = "62" > 62< / a >
< a href = "#63" id = "63" > 63< / a >
< a href = "#64" id = "64" > 64< / a >
< a href = "#65" id = "65" > 65< / a >
< a href = "#66" id = "66" > 66< / a >
< a href = "#67" id = "67" > 67< / a >
< a href = "#68" id = "68" > 68< / a >
< a href = "#69" id = "69" > 69< / a >
< a href = "#70" id = "70" > 70< / a >
< a href = "#71" id = "71" > 71< / a >
< a href = "#72" id = "72" > 72< / a >
< a href = "#73" id = "73" > 73< / a >
< a href = "#74" id = "74" > 74< / a >
< a href = "#75" id = "75" > 75< / a >
< a href = "#76" id = "76" > 76< / a >
< a href = "#77" id = "77" > 77< / a >
< a href = "#78" id = "78" > 78< / a >
< a href = "#79" id = "79" > 79< / a >
< a href = "#80" id = "80" > 80< / a >
< a href = "#81" id = "81" > 81< / a >
< a href = "#82" id = "82" > 82< / a >
< a href = "#83" id = "83" > 83< / a >
< a href = "#84" id = "84" > 84< / a >
< a href = "#85" id = "85" > 85< / a >
< a href = "#86" id = "86" > 86< / a >
< a href = "#87" id = "87" > 87< / a >
< a href = "#88" id = "88" > 88< / a >
< a href = "#89" id = "89" > 89< / a >
< a href = "#90" id = "90" > 90< / a >
< a href = "#91" id = "91" > 91< / a >
< a href = "#92" id = "92" > 92< / a >
< a href = "#93" id = "93" > 93< / a >
< a href = "#94" id = "94" > 94< / a >
< a href = "#95" id = "95" > 95< / a >
< a href = "#96" id = "96" > 96< / a >
< a href = "#97" id = "97" > 97< / a >
< a href = "#98" id = "98" > 98< / a >
< a href = "#99" id = "99" > 99< / a >
< a href = "#100" id = "100" > 100< / a >
< a href = "#101" id = "101" > 101< / a >
< a href = "#102" id = "102" > 102< / a >
< a href = "#103" id = "103" > 103< / a >
< a href = "#104" id = "104" > 104< / a >
< a href = "#105" id = "105" > 105< / a >
< a href = "#106" id = "106" > 106< / a >
< a href = "#107" id = "107" > 107< / a >
< a href = "#108" id = "108" > 108< / a >
< a href = "#109" id = "109" > 109< / a >
< a href = "#110" id = "110" > 110< / a >
< a href = "#111" id = "111" > 111< / a >
< a href = "#112" id = "112" > 112< / a >
< a href = "#113" id = "113" > 113< / a >
< a href = "#114" id = "114" > 114< / a >
< a href = "#115" id = "115" > 115< / a >
< a href = "#116" id = "116" > 116< / a >
2023-02-11 06:48:57 -08:00
< / pre > < pre class = "rust" > < code > < span class = "kw" > use < / span > solana_client::{
client_error::Result < span class = "kw" > as < / span > ClientResult, rpc_client::RpcClient, rpc_request::RpcError,
};
< span class = "kw" > use < / span > solana_sdk::transaction::Transaction;
< span class = "kw" > use < / span > solana_sdk::{
2023-02-15 06:27:01 -08:00
clock::Slot, commitment_config::CommitmentConfig, signature::Signature,
2023-02-11 06:48:57 -08:00
transaction::uses_durable_nonce,
};
< span class = "kw" > use < / span > std::{thread, time};
< span class = "comment" > // #[allow(dead_code)]
// pub fn retry< T> (request: impl Fn() -> Result< T, anchor_client::ClientError> ) -> anyhow::Result< T> {
// for _i in 0..5 {
// match request() {
// Ok(res) => return Ok(res),
// Err(err) => {
// // TODO: only retry for recoverable errors
// log::error!(" {:#?}" , err);
// continue;
// }
// }
// }
// Err(anyhow!(" Retry failed" ))
// }
2023-02-15 06:27:01 -08:00
< / span > < span class = "doccomment" > /// Some Result< > types don' t convert to anyhow::Result nicely. Force them through stringification.
< / span > < span class = "kw" > pub trait < / span > AnyhowWrap {
< span class = "kw" > type < / span > Value;
< span class = "kw" > fn < / span > map_err_anyhow(< span class = "self" > self< / span > ) -> anyhow::Result< < span class = "self" > Self< / span > ::Value> ;
2023-02-11 06:48:57 -08:00
}
2023-02-15 06:27:01 -08:00
< span class = "kw" > impl< / span > < T, E: std::fmt::Debug> AnyhowWrap < span class = "kw" > for < / span > < span class = "prelude-ty" > Result< / span > < T, E> {
< span class = "kw" > type < / span > Value = T;
< span class = "kw" > fn < / span > map_err_anyhow(< span class = "self" > self< / span > ) -> anyhow::Result< < span class = "self" > Self< / span > ::Value> {
< span class = "self" > self< / span > .map_err(|err| < span class = "macro" > anyhow::anyhow!< / span > (< span class = "string" > " {:?}" < / span > , err))
}
}
< span class = "doccomment" > /// Push to an async_channel::Sender and ignore if the channel is full
< / span > < span class = "kw" > pub trait < / span > AsyncChannelSendUnlessFull< T> {
< span class = "doccomment" > /// Send a message if the channel isn' t full
< / span > < span class = "kw" > fn < / span > send_unless_full(< span class = "kw-2" > & < / span > < span class = "self" > self< / span > , msg: T) -> < span class = "prelude-ty" > Result< / span > < (), async_channel::SendError< T> > ;
}
< span class = "kw" > impl< / span > < T> AsyncChannelSendUnlessFull< T> < span class = "kw" > for < / span > async_channel::Sender< T> {
< span class = "kw" > fn < / span > send_unless_full(< span class = "kw-2" > & < / span > < span class = "self" > self< / span > , msg: T) -> < span class = "prelude-ty" > Result< / span > < (), async_channel::SendError< T> > {
< span class = "kw" > use < / span > async_channel::< span class = "kw-2" > *< / span > ;
< span class = "kw" > match < / span > < span class = "self" > self< / span > .try_send(msg) {
< span class = "prelude-val" > Ok< / span > (()) => < span class = "prelude-val" > Ok< / span > (()),
< span class = "prelude-val" > Err< / span > (TrySendError::Closed(msg)) => < span class = "prelude-val" > Err< / span > (async_channel::SendError(msg)),
< span class = "prelude-val" > Err< / span > (TrySendError::Full(< span class = "kw" > _< / span > )) => < span class = "prelude-val" > Ok< / span > (()),
}
2023-02-11 06:48:57 -08:00
}
}
< span class = "doccomment" > /// A copy of RpcClient::send_and_confirm_transaction that returns the slot the
/// transaction confirmed in.
< / span > < span class = "kw" > pub fn < / span > send_and_confirm_transaction(
rpc_client: < span class = "kw-2" > & < / span > RpcClient,
transaction: < span class = "kw-2" > & < / span > Transaction,
) -> ClientResult< (Signature, Slot)> {
< span class = "kw" > const < / span > SEND_RETRIES: usize = < span class = "number" > 1< / span > ;
< span class = "kw" > const < / span > GET_STATUS_RETRIES: usize = usize::MAX;
< span class = "lifetime" > ' sending< / span > : < span class = "kw" > for _ in < / span > < span class = "number" > 0< / span > ..SEND_RETRIES {
< span class = "kw" > let < / span > signature = rpc_client.send_transaction(transaction)< span class = "question-mark" > ?< / span > ;
< span class = "kw" > let < / span > recent_blockhash = < span class = "kw" > if < / span > uses_durable_nonce(transaction).is_some() {
< span class = "kw" > let < / span > (recent_blockhash, ..) =
rpc_client.get_latest_blockhash_with_commitment(CommitmentConfig::processed())< span class = "question-mark" > ?< / span > ;
recent_blockhash
} < span class = "kw" > else < / span > {
transaction.message.recent_blockhash
};
< span class = "kw" > for < / span > status_retry < span class = "kw" > in < / span > < span class = "number" > 0< / span > ..GET_STATUS_RETRIES {
< span class = "kw" > let < / span > response = rpc_client.get_signature_statuses(< span class = "kw-2" > & < / span > [signature])< span class = "question-mark" > ?< / span > .value;
< span class = "kw" > match < / span > response[< span class = "number" > 0< / span > ]
.clone()
.filter(|result| result.satisfies_commitment(rpc_client.commitment()))
{
< span class = "prelude-val" > Some< / span > (tx_status) => {
< span class = "kw" > return if let < / span > < span class = "prelude-val" > Some< / span > (e) = tx_status.err {
< span class = "prelude-val" > Err< / span > (e.into())
} < span class = "kw" > else < / span > {
< span class = "prelude-val" > Ok< / span > ((signature, tx_status.slot))
};
}
< span class = "prelude-val" > None < / span > => {
< span class = "kw" > if < / span > !rpc_client
.is_blockhash_valid(< span class = "kw-2" > & < / span > recent_blockhash, CommitmentConfig::processed())< span class = "question-mark" > ?
< / span > {
< span class = "comment" > // Block hash is not found by some reason
< / span > < span class = "kw" > break < / span > < span class = "lifetime" > ' sending< / span > ;
} < span class = "kw" > else if < / span > < span class = "macro" > cfg!< / span > (not(test))
< span class = "comment" > // Ignore sleep at last step.
< / span > & & status_retry < GET_STATUS_RETRIES
{
< span class = "comment" > // Retry twice a second
< / span > thread::sleep(time::Duration::from_millis(< span class = "number" > 500< / span > ));
< span class = "kw" > continue< / span > ;
}
}
}
}
}
< span class = "prelude-val" > Err< / span > (RpcError::ForUser(
< span class = "string" > " unable to confirm transaction. \
This can happen in situations such as transaction expiration \
and insufficient fee-payer funds"
< / span > .to_string(),
)
.into())
}
< / code > < / pre > < / div >
2023-05-11 04:45:49 -07:00
< / section > < / main > < div id = "rustdoc-vars" data-root-path = "../../" data-static-root-path = "../../static.files/" data-current-crate = "mango_v4_client" data-themes = "" data-resource-suffix = "" data-rustdoc-version = "1.69.0 (84c898d65 2023-04-16)" data-search-js = "search-8a59a8356673ec1f.js" data-settings-js = "settings-f0c5c39777a9a2f6.js" data-settings-css = "settings-0bcba95ff279c1db.css" > < / div > < / body > < / html >