Split up solana-client (#27246)

* Move thin-client to new crate

* Move tpu client and varieties to new crate

* Move pubsub-client to new crate

* Move rpc-client to new crate

* Add client-common crate to avoid circular dependencies

* Move rpc_cache and make less pub

* Remove unused unpub modules

* Add nonce-client

* Remove unused dependencies

* Fix rpc_client docs

* Move spinner to calling clients

* Rename client-common to rpc-client-api

* Remove unnecessary rpc_ prefix

* Remove unused ClientErrorKind variant

* Remove unnecessary Client prefix

* Move mod declarations into lib.rs and remove unnecessary files

* Rename nonce-client and remove redundant module name

* Restore mock_sender_for_cli in solana-client
This commit is contained in:
Tyera Eulberg 2022-08-23 22:34:35 -07:00 committed by GitHub
parent efa6201eda
commit c24eaa36f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 1703 additions and 1450 deletions

196
Cargo.lock generated
View File

@ -4884,6 +4884,7 @@ dependencies = [
"solana-logger 1.12.0",
"solana-program-runtime",
"solana-remote-wallet",
"solana-rpc-client",
"solana-sdk 1.12.0",
"solana-streamer",
"solana-test-validator",
@ -4942,58 +4943,15 @@ dependencies = [
name = "solana-client"
version = "1.12.0"
dependencies = [
"anyhow",
"assert_matches",
"async-mutex",
"async-trait",
"base64 0.13.0",
"bincode",
"bs58",
"bytes",
"clap 2.33.3",
"crossbeam-channel",
"enum_dispatch",
"futures 0.3.23",
"futures-util",
"indexmap",
"indicatif",
"itertools",
"jsonrpc-core",
"jsonrpc-http-server",
"lazy_static",
"log",
"quinn",
"quinn-proto",
"quinn-udp",
"rand 0.7.3",
"rand_chacha 0.2.2",
"rayon",
"reqwest",
"rustls 0.20.6",
"semver 1.0.13",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-clap-utils",
"solana-faucet",
"solana-logger 1.12.0",
"solana-measure",
"solana-metrics",
"solana-net-utils",
"solana-perf",
"solana-pubsub-client",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-rpc-client-nonce-utils",
"solana-sdk 1.12.0",
"solana-streamer",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
"spl-token-2022",
"thiserror",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tungstenite",
"url 2.2.2",
"solana-thin-client",
"solana-tpu-client",
]
[[package]]
@ -5911,6 +5869,29 @@ dependencies = [
"tokio",
]
[[package]]
name = "solana-pubsub-client"
version = "1.12.0"
dependencies = [
"crossbeam-channel",
"futures-util",
"log",
"reqwest",
"semver 1.0.13",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"thiserror",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tungstenite",
"url 2.2.2",
]
[[package]]
name = "solana-rayon-threadlimit"
version = "1.12.0"
@ -5992,6 +5973,72 @@ dependencies = [
"tokio-util 0.6.9",
]
[[package]]
name = "solana-rpc-client"
version = "1.12.0"
dependencies = [
"assert_matches",
"async-trait",
"base64 0.13.0",
"bincode",
"bs58",
"crossbeam-channel",
"futures 0.3.23",
"indicatif",
"jsonrpc-core",
"jsonrpc-http-server",
"log",
"reqwest",
"semver 1.0.13",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
"tokio",
]
[[package]]
name = "solana-rpc-client-api"
version = "1.12.0"
dependencies = [
"base64 0.13.0",
"bs58",
"jsonrpc-core",
"reqwest",
"semver 1.0.13",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-sdk 1.12.0",
"solana-transaction-status",
"solana-version",
"spl-token-2022",
"thiserror",
]
[[package]]
name = "solana-rpc-client-nonce-utils"
version = "1.12.0"
dependencies = [
"anyhow",
"clap 2.33.3",
"futures 0.3.23",
"serde_json",
"solana-account-decoder",
"solana-clap-utils",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"thiserror",
"tokio",
]
[[package]]
name = "solana-rpc-test"
version = "1.12.0"
@ -6389,6 +6436,20 @@ dependencies = [
"tokio",
]
[[package]]
name = "solana-thin-client"
version = "1.12.0"
dependencies = [
"bincode",
"log",
"rayon",
"solana-logger 1.12.0",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-tpu-client",
]
[[package]]
name = "solana-tokens"
version = "1.12.0"
@ -6420,6 +6481,43 @@ dependencies = [
"thiserror",
]
[[package]]
name = "solana-tpu-client"
version = "1.12.0"
dependencies = [
"async-mutex",
"async-trait",
"bincode",
"crossbeam-channel",
"enum_dispatch",
"futures 0.3.23",
"futures-util",
"indexmap",
"indicatif",
"itertools",
"lazy_static",
"log",
"quinn",
"quinn-proto",
"quinn-udp",
"rand 0.7.3",
"rand_chacha 0.2.2",
"rayon",
"rustls 0.20.6",
"solana-logger 1.12.0",
"solana-measure",
"solana-metrics",
"solana-net-utils",
"solana-perf",
"solana-pubsub-client",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-streamer",
"thiserror",
"tokio",
]
[[package]]
name = "solana-transaction-dos"
version = "1.12.0"

View File

@ -58,10 +58,14 @@ members = [
"programs/stake",
"programs/vote",
"programs/zk-token-proof",
"pubsub-client",
"rayon-threadlimit",
"rbpf-cli",
"remote-wallet",
"rpc",
"rpc-client",
"rpc-client-api",
"rpc-client-nonce-utils",
"rpc-test",
"runtime",
"runtime/store-tool",
@ -78,7 +82,9 @@ members = [
"streamer",
"sys-tuner",
"test-validator",
"thin-client",
"tokens",
"tpu-client",
"transaction-dos",
"transaction-status",
"upload-perf",

View File

@ -39,6 +39,7 @@ solana-faucet = { path = "../faucet", version = "=1.12.0" }
solana-logger = { path = "../logger", version = "=1.12.0" }
solana-program-runtime = { path = "../program-runtime", version = "=1.12.0" }
solana-remote-wallet = { path = "../remote-wallet", version = "=1.12.0" }
solana-rpc-client = { path = "../rpc-client", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.12.0" }
solana-version = { path = "../version", version = "=1.12.0" }

View File

@ -1713,10 +1713,10 @@ mod tests {
serde_json::{json, Value},
solana_client::{
blockhash_query,
mock_sender_for_cli::SIGNATURE,
rpc_request::RpcRequest,
rpc_response::{Response, RpcResponseContext},
},
solana_rpc_client::mock_sender_for_cli::SIGNATURE,
solana_sdk::{
pubkey::Pubkey,
signature::{

View File

@ -10,60 +10,17 @@ license = "Apache-2.0"
edition = "2021"
[dependencies]
async-mutex = "1.4.0"
async-trait = "0.1.57"
base64 = "0.13.0"
bincode = "1.3.3"
bs58 = "0.4.0"
bytes = "1.2.1"
clap = "2.33.0"
crossbeam-channel = "0.5"
enum_dispatch = "0.3.8"
futures = "0.3"
futures-util = "0.3.21"
indexmap = "1.9.1"
indicatif = "0.17.0"
itertools = "0.10.2"
jsonrpc-core = "18.0.0"
lazy_static = "1.4.0"
log = "0.4.17"
quinn = "0.8.4"
quinn-proto = "0.8.4"
quinn-udp = "0.1.3"
rand = "0.7.0"
rand_chacha = "0.2.2"
rayon = "1.5.3"
reqwest = { version = "0.11.11", default-features = false, features = ["blocking", "brotli", "deflate", "gzip", "rustls-tls", "json"] }
rustls = { version = "0.20.6", features = ["dangerous_configuration"] }
semver = "1.0.13"
serde = "1.0.143"
serde_derive = "1.0.103"
serde_json = "1.0.83"
solana-account-decoder = { path = "../account-decoder", version = "=1.12.0" }
solana-clap-utils = { path = "../clap-utils", version = "=1.12.0" }
solana-faucet = { path = "../faucet", version = "=1.12.0" }
solana-measure = { path = "../measure", version = "=1.12.0" }
solana-metrics = { path = "../metrics", version = "=1.12.0" }
solana-net-utils = { path = "../net-utils", version = "=1.12.0" }
solana-pubsub-client = { path = "../pubsub-client", version = "=1.12.0" }
solana-rpc-client = { path = "../rpc-client", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
solana-rpc-client-nonce-utils = { path = "../rpc-client-nonce-utils", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-streamer = { path = "../streamer", version = "=1.12.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.12.0" }
solana-version = { path = "../version", version = "=1.12.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.12.0" }
spl-token-2022 = { version = "=0.4.3", features = ["no-entrypoint"] }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1.9"
tokio-tungstenite = { version = "0.17.2", features = ["rustls-tls-webpki-roots"] }
tungstenite = { version = "0.17.2", features = ["rustls-tls-webpki-roots"] }
url = "2.2.2"
solana-thin-client = { path = "../thin-client", version = "=1.12.0" }
solana-tpu-client = { path = "../tpu-client", version = "=1.12.0" }
[dev-dependencies]
anyhow = "1.0.58"
assert_matches = "1.5.0"
jsonrpc-http-server = "18.0.0"
solana-logger = { path = "../logger", version = "=1.12.0" }
solana-perf = { path = "../perf", version = "=1.12.0" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,212 +0,0 @@
pub use reqwest;
use {
crate::{nonblocking::quic_client::QuicError, rpc_request, rpc_response},
quinn::ConnectError,
solana_faucet::faucet::FaucetError,
solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
},
std::io,
thiserror::Error,
}; // export `reqwest` for clients
#[derive(Error, Debug)]
pub enum ClientErrorKind {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
RpcError(#[from] rpc_request::RpcError),
#[error(transparent)]
SerdeJson(#[from] serde_json::error::Error),
#[error(transparent)]
SigningError(#[from] SignerError),
#[error(transparent)]
TransactionError(#[from] TransactionError),
#[error(transparent)]
FaucetError(#[from] FaucetError),
#[error("Custom: {0}")]
Custom(String),
}
impl ClientErrorKind {
pub fn get_transaction_error(&self) -> Option<TransactionError> {
match self {
Self::RpcError(rpc_request::RpcError::RpcResponseError {
data:
rpc_request::RpcResponseErrorData::SendTransactionPreflightFailure(
rpc_response::RpcSimulateTransactionResult {
err: Some(tx_err), ..
},
),
..
}) => Some(tx_err.clone()),
Self::TransactionError(tx_err) => Some(tx_err.clone()),
_ => None,
}
}
}
impl From<TransportError> for ClientErrorKind {
fn from(err: TransportError) -> Self {
match err {
TransportError::IoError(err) => Self::Io(err),
TransportError::TransactionError(err) => Self::TransactionError(err),
TransportError::Custom(err) => Self::Custom(err),
}
}
}
impl From<ClientErrorKind> for TransportError {
fn from(client_error_kind: ClientErrorKind) -> Self {
match client_error_kind {
ClientErrorKind::Io(err) => Self::IoError(err),
ClientErrorKind::TransactionError(err) => Self::TransactionError(err),
ClientErrorKind::Reqwest(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::RpcError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::SerdeJson(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::SigningError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::FaucetError(err) => Self::Custom(format!("{:?}", err)),
ClientErrorKind::Custom(err) => Self::Custom(format!("{:?}", err)),
}
}
}
impl From<QuicError> for ClientErrorKind {
fn from(quic_error: QuicError) -> Self {
Self::Custom(format!("{:?}", quic_error))
}
}
impl From<ConnectError> for ClientErrorKind {
fn from(connect_error: ConnectError) -> Self {
Self::Custom(format!("{:?}", connect_error))
}
}
#[derive(Error, Debug)]
#[error("{kind}")]
pub struct ClientError {
pub request: Option<rpc_request::RpcRequest>,
#[source]
pub kind: ClientErrorKind,
}
impl ClientError {
pub fn new_with_request(kind: ClientErrorKind, request: rpc_request::RpcRequest) -> Self {
Self {
request: Some(request),
kind,
}
}
pub fn into_with_request(self, request: rpc_request::RpcRequest) -> Self {
Self {
request: Some(request),
..self
}
}
pub fn request(&self) -> Option<&rpc_request::RpcRequest> {
self.request.as_ref()
}
pub fn kind(&self) -> &ClientErrorKind {
&self.kind
}
pub fn get_transaction_error(&self) -> Option<TransactionError> {
self.kind.get_transaction_error()
}
}
impl From<ClientErrorKind> for ClientError {
fn from(kind: ClientErrorKind) -> Self {
Self {
request: None,
kind,
}
}
}
impl From<TransportError> for ClientError {
fn from(err: TransportError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<ClientError> for TransportError {
fn from(client_error: ClientError) -> Self {
client_error.kind.into()
}
}
impl From<std::io::Error> for ClientError {
fn from(err: std::io::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<reqwest::Error> for ClientError {
fn from(err: reqwest::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<rpc_request::RpcError> for ClientError {
fn from(err: rpc_request::RpcError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<serde_json::error::Error> for ClientError {
fn from(err: serde_json::error::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<SignerError> for ClientError {
fn from(err: SignerError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<TransactionError> for ClientError {
fn from(err: TransactionError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<FaucetError> for ClientError {
fn from(err: FaucetError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
pub type Result<T> = std::result::Result<T, ClientError>;

View File

@ -1,38 +1,120 @@
#![allow(clippy::integer_arithmetic)]
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate solana_metrics;
pub mod blockhash_query;
pub mod client_error;
pub mod connection_cache;
pub(crate) mod http_sender;
pub(crate) mod mock_sender;
pub mod nonblocking;
pub mod nonce_utils;
pub mod pubsub_client;
pub mod quic_client;
pub mod rpc_cache;
pub mod rpc_client;
pub mod rpc_config;
pub mod rpc_custom_error;
pub mod rpc_deprecated_config;
pub mod rpc_filter;
pub mod rpc_request;
pub mod rpc_response;
pub mod rpc_sender;
pub mod spinner;
pub mod thin_client;
pub mod tpu_client;
pub mod tpu_connection;
pub mod transaction_executor;
pub mod udp_client;
pub mod mock_sender_for_cli {
/// Magic `SIGNATURE` value used by `solana-cli` unit tests.
/// Please don't use this constant.
pub const SIGNATURE: &str =
"43yNSFC6fYTuPgTNFFhF4axw7AfWxB2BPdurme8yrsWEYwm8299xh8n6TAHjGymiSub1XtyxTNyd9GBfY2hxoBw8";
pub use solana_rpc_client::mock_sender_for_cli;
pub mod blockhash_query {
pub use solana_rpc_client_nonce_utils::blockhash_query::*;
}
pub mod client_error {
pub use solana_rpc_client_api::client_error::{
reqwest, Error as ClientError, ErrorKind as ClientErrorKind, Result,
};
}
pub mod connection_cache {
pub use solana_tpu_client::connection_cache::*;
}
pub mod nonblocking {
pub mod blockhash_query {
pub use solana_rpc_client_nonce_utils::nonblocking::blockhash_query::*;
}
/// Durable transaction nonce helpers.
pub mod nonce_utils {
pub use solana_rpc_client_nonce_utils::nonblocking::*;
}
pub mod pubsub_client {
pub use solana_pubsub_client::nonblocking::pubsub_client::*;
}
/// Simple nonblocking client that connects to a given UDP port with the QUIC protocol
/// and provides an interface for sending transactions which is restricted by the
/// server's flow control.
pub mod quic_client {
pub use solana_tpu_client::nonblocking::quic_client::*;
}
/// Communication with a Solana node over RPC asynchronously .
///
/// Software that interacts with the Solana blockchain, whether querying its
/// state or submitting transactions, communicates with a Solana node over
/// [JSON-RPC], using the [`RpcClient`] type.
///
/// [JSON-RPC]: https://www.jsonrpc.org/specification
pub mod rpc_client {
pub use solana_rpc_client::nonblocking::rpc_client::*;
}
pub mod tpu_client {
pub use solana_tpu_client::nonblocking::tpu_client::*;
}
/// Trait defining async send functions, to be used for UDP or QUIC sending
pub mod tpu_connection {
pub use solana_tpu_client::nonblocking::tpu_connection::*;
}
/// Simple UDP client that communicates with the given UDP port with UDP and provides
/// an interface for sending transactions
pub mod udp_client {
pub use solana_tpu_client::nonblocking::udp_client::*;
}
}
/// Durable transaction nonce helpers.
pub mod nonce_utils {
pub use solana_rpc_client_nonce_utils::*;
}
pub mod pubsub_client {
pub use solana_pubsub_client::pubsub_client::*;
}
/// Simple client that connects to a given UDP port with the QUIC protocol and provides
/// an interface for sending transactions which is restricted by the server's flow control.
pub mod quic_client {
pub use solana_tpu_client::quic_client::*;
}
/// Communication with a Solana node over RPC.
///
/// Software that interacts with the Solana blockchain, whether querying its
/// state or submitting transactions, communicates with a Solana node over
/// [JSON-RPC], using the [`RpcClient`] type.
///
/// [JSON-RPC]: https://www.jsonrpc.org/specification
pub mod rpc_client {
pub use solana_rpc_client::rpc_client::*;
}
pub mod rpc_config {
pub use solana_rpc_client_api::config::*;
}
/// Implementation defined RPC server errors
pub mod rpc_custom_error {
pub use solana_rpc_client_api::custom_error::*;
}
pub mod rpc_deprecated_config {
pub use solana_rpc_client_api::deprecated_config::*;
}
pub mod rpc_filter {
pub use solana_rpc_client_api::filter::*;
}
pub mod rpc_request {
pub use solana_rpc_client_api::request::*;
}
pub mod rpc_response {
pub use solana_rpc_client_api::response::*;
}
/// A transport for RPC calls.
pub mod rpc_sender {
pub use solana_rpc_client::rpc_sender::*;
}
/// The `thin_client` module is a client-side object that interfaces with
/// a server-side TPU. Client code should use this object instead of writing
/// messages to the network directly. The binary encoding of its messages are
/// unstable and may change in future releases.
pub mod thin_client {
pub use solana_thin_client::thin_client::*;
}
pub mod tpu_client {
pub use solana_tpu_client::tpu_client::*;
}
pub mod tpu_connection {
pub use solana_tpu_client::tpu_connection::*;
}
/// Simple TPU client that communicates with the given UDP port with UDP and provides
/// an interface for sending transactions
pub mod udp_client {
pub use solana_tpu_client::udp_client::*;
}

View File

@ -1,8 +0,0 @@
pub mod blockhash_query;
pub mod nonce_utils;
pub mod pubsub_client;
pub mod quic_client;
pub mod rpc_client;
pub mod tpu_client;
pub mod tpu_connection;
pub mod udp_client;

View File

@ -1,40 +0,0 @@
//! Spinner creator
use {
indicatif::{ProgressBar, ProgressStyle},
std::time::Duration,
};
pub(crate) fn new_progress_bar() -> ProgressBar {
let progress_bar = ProgressBar::new(42);
progress_bar.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {wide_msg}")
.expect("ProgresStyle::template direct input to be correct"),
);
progress_bar.enable_steady_tick(Duration::from_millis(100));
progress_bar
}
pub(crate) fn set_message_for_confirmed_transactions(
progress_bar: &ProgressBar,
confirmed_transactions: u32,
total_transactions: usize,
block_height: Option<u64>,
last_valid_block_height: u64,
status: &str,
) {
progress_bar.set_message(format!(
"{:>5.1}% | {:<40}{}",
confirmed_transactions as f64 * 100. / total_transactions as f64,
status,
match block_height {
Some(block_height) => format!(
" [block height {}; re-sign in {} blocks]",
block_height,
last_valid_block_height.saturating_sub(block_height),
),
None => String::new(),
},
));
}

View File

@ -1,8 +1,8 @@
#![allow(clippy::integer_arithmetic)]
use {
crate::rpc_client::RpcClient,
log::*,
solana_measure::measure::Measure,
solana_rpc_client::rpc_client::RpcClient,
solana_sdk::{
commitment_config::CommitmentConfig, signature::Signature, timing::timestamp,
transaction::Transaction,

173
programs/bpf/Cargo.lock generated
View File

@ -4649,53 +4649,15 @@ dependencies = [
name = "solana-client"
version = "1.12.0"
dependencies = [
"async-mutex",
"async-trait",
"base64 0.13.0",
"bincode",
"bs58",
"bytes",
"clap 2.33.3",
"crossbeam-channel",
"enum_dispatch",
"futures 0.3.23",
"futures-util",
"indexmap",
"indicatif",
"itertools",
"jsonrpc-core",
"lazy_static",
"log",
"quinn",
"quinn-proto",
"quinn-udp",
"rand 0.7.3",
"rand_chacha 0.2.2",
"rayon",
"reqwest",
"rustls 0.20.6",
"semver",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-clap-utils",
"solana-faucet",
"solana-measure",
"solana-metrics",
"solana-net-utils",
"solana-pubsub-client",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-rpc-client-nonce-utils",
"solana-sdk 1.12.0",
"solana-streamer",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
"spl-token-2022",
"thiserror",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tungstenite",
"url 2.2.2",
"solana-thin-client",
"solana-tpu-client",
]
[[package]]
@ -5312,6 +5274,29 @@ dependencies = [
"tokio",
]
[[package]]
name = "solana-pubsub-client"
version = "1.12.0"
dependencies = [
"crossbeam-channel",
"futures-util",
"log",
"reqwest",
"semver",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"thiserror",
"tokio",
"tokio-stream",
"tokio-tungstenite",
"tungstenite",
"url 2.2.2",
]
[[package]]
name = "solana-rayon-threadlimit"
version = "1.12.0"
@ -5388,6 +5373,61 @@ dependencies = [
"tokio-util 0.6.9",
]
[[package]]
name = "solana-rpc-client"
version = "1.12.0"
dependencies = [
"async-trait",
"base64 0.13.0",
"bincode",
"bs58",
"indicatif",
"log",
"reqwest",
"semver",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-transaction-status",
"solana-version",
"solana-vote-program",
"tokio",
]
[[package]]
name = "solana-rpc-client-api"
version = "1.12.0"
dependencies = [
"base64 0.13.0",
"bs58",
"jsonrpc-core",
"reqwest",
"semver",
"serde",
"serde_derive",
"serde_json",
"solana-account-decoder",
"solana-sdk 1.12.0",
"solana-transaction-status",
"solana-version",
"spl-token-2022",
"thiserror",
]
[[package]]
name = "solana-rpc-client-nonce-utils"
version = "1.12.0"
dependencies = [
"clap 2.33.3",
"solana-clap-utils",
"solana-rpc-client",
"solana-sdk 1.12.0",
"thiserror",
]
[[package]]
name = "solana-runtime"
version = "1.12.0"
@ -5719,6 +5759,51 @@ dependencies = [
"tokio",
]
[[package]]
name = "solana-thin-client"
version = "1.12.0"
dependencies = [
"bincode",
"log",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-tpu-client",
]
[[package]]
name = "solana-tpu-client"
version = "1.12.0"
dependencies = [
"async-mutex",
"async-trait",
"bincode",
"enum_dispatch",
"futures 0.3.23",
"futures-util",
"indexmap",
"indicatif",
"itertools",
"lazy_static",
"log",
"quinn",
"quinn-proto",
"quinn-udp",
"rand 0.7.3",
"rayon",
"rustls 0.20.6",
"solana-measure",
"solana-metrics",
"solana-net-utils",
"solana-pubsub-client",
"solana-rpc-client",
"solana-rpc-client-api",
"solana-sdk 1.12.0",
"solana-streamer",
"thiserror",
"tokio",
]
[[package]]
name = "solana-transaction-status"
version = "1.12.0"

34
pubsub-client/Cargo.toml Normal file
View File

@ -0,0 +1,34 @@
[package]
name = "solana-pubsub-client"
version = "1.12.0"
description = "Solana Pubsub Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-pubsub-client"
edition = "2021"
[dependencies]
crossbeam-channel = "0.5"
futures-util = "0.3.21"
log = "0.4.17"
reqwest = { version = "0.11.11", default-features = false, features = ["blocking", "brotli", "deflate", "gzip", "rustls-tls", "json"] }
semver = "1.0.13"
serde = "1.0.143"
serde_derive = "1.0.103"
serde_json = "1.0.83"
solana-account-decoder = { path = "../account-decoder", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1.9"
tokio-tungstenite = { version = "0.17.2", features = ["rustls-tls-webpki-roots"] }
tungstenite = { version = "0.17.2", features = ["rustls-tls-webpki-roots"] }
url = "2.2.2"
[dev-dependencies]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

4
pubsub-client/src/lib.rs Normal file
View File

@ -0,0 +1,4 @@
#![allow(clippy::integer_arithmetic)]
pub mod nonblocking;
pub mod pubsub_client;

View File

@ -0,0 +1 @@
pub mod pubsub_client;

View File

@ -1,17 +1,4 @@
use {
crate::{
http_sender::RpcErrorObject,
rpc_config::{
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
},
rpc_filter::maybe_map_filters,
rpc_response::{
Response as RpcResponse, RpcBlockUpdate, RpcKeyedAccount, RpcLogsResponse,
RpcSignatureResult, RpcVersionInfo, RpcVote, SlotInfo, SlotUpdate,
},
},
futures_util::{
future::{ready, BoxFuture, FutureExt},
sink::SinkExt,
@ -21,6 +8,19 @@ use {
serde::de::DeserializeOwned,
serde_json::{json, Map, Value},
solana_account_decoder::UiAccount,
solana_rpc_client_api::{
config::{
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
},
error_object::RpcErrorObject,
filter::maybe_map_filters,
response::{
Response as RpcResponse, RpcBlockUpdate, RpcKeyedAccount, RpcLogsResponse,
RpcSignatureResult, RpcVersionInfo, RpcVote, SlotInfo, SlotUpdate,
},
},
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
std::collections::BTreeMap,
thiserror::Error,

View File

@ -1,17 +1,5 @@
pub use crate::nonblocking::pubsub_client::PubsubClientError;
use {
crate::{
rpc_config::{
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
},
rpc_filter,
rpc_response::{
Response as RpcResponse, RpcBlockUpdate, RpcKeyedAccount, RpcLogsResponse,
RpcSignatureResult, RpcVote, SlotInfo, SlotUpdate,
},
},
crossbeam_channel::{unbounded, Receiver, Sender},
log::*,
serde::de::DeserializeOwned,
@ -21,6 +9,18 @@ use {
Map, Value,
},
solana_account_decoder::UiAccount,
solana_rpc_client_api::{
config::{
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
RpcTransactionLogsFilter,
},
filter,
response::{
Response as RpcResponse, RpcBlockUpdate, RpcKeyedAccount, RpcLogsResponse,
RpcSignatureResult, RpcVote, SlotInfo, SlotUpdate,
},
},
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
std::{
marker::PhantomData,
@ -396,7 +396,7 @@ impl PubsubClient {
let node_version = PubsubProgramClientSubscription::get_version(&socket_clone).ok();
// If node does not support the pubsub `getVersion` method, assume version is old
// and filters should be mapped (node_version.is_none()).
rpc_filter::maybe_map_filters(node_version, filters)
filter::maybe_map_filters(node_version, filters)
.map_err(PubsubClientError::RequestError)?;
}
}

31
rpc-client-api/Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
name = "solana-rpc-client-api"
version = "1.12.0"
description = "Solana Client Common Utilities"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-rpc-client-api"
edition = "2021"
[dependencies]
base64 = "0.13.0"
bs58 = "0.4.0"
jsonrpc-core = "18.0.0"
reqwest = { version = "0.11.11", default-features = false, features = ["blocking", "brotli", "deflate", "gzip", "rustls-tls", "json"] }
semver = "1.0.13"
serde = "1.0.143"
serde_derive = "1.0.103"
serde_json = "1.0.83"
solana-account-decoder = { path = "../account-decoder", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.12.0" }
solana-version = { path = "../version", version = "=1.12.0" }
spl-token-2022 = { version = "=0.4.3", features = ["no-entrypoint"] }
thiserror = "1.0"
[dev-dependencies]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -0,0 +1,186 @@
pub use reqwest;
use {
crate::{request, response},
solana_sdk::{
signature::SignerError, transaction::TransactionError, transport::TransportError,
},
std::io,
thiserror::Error as ThisError,
};
#[derive(ThisError, Debug)]
pub enum ErrorKind {
#[error(transparent)]
Io(#[from] io::Error),
#[error(transparent)]
Reqwest(#[from] reqwest::Error),
#[error(transparent)]
RpcError(#[from] request::RpcError),
#[error(transparent)]
SerdeJson(#[from] serde_json::error::Error),
#[error(transparent)]
SigningError(#[from] SignerError),
#[error(transparent)]
TransactionError(#[from] TransactionError),
#[error("Custom: {0}")]
Custom(String),
}
impl ErrorKind {
pub fn get_transaction_error(&self) -> Option<TransactionError> {
match self {
Self::RpcError(request::RpcError::RpcResponseError {
data:
request::RpcResponseErrorData::SendTransactionPreflightFailure(
response::RpcSimulateTransactionResult {
err: Some(tx_err), ..
},
),
..
}) => Some(tx_err.clone()),
Self::TransactionError(tx_err) => Some(tx_err.clone()),
_ => None,
}
}
}
impl From<TransportError> for ErrorKind {
fn from(err: TransportError) -> Self {
match err {
TransportError::IoError(err) => Self::Io(err),
TransportError::TransactionError(err) => Self::TransactionError(err),
TransportError::Custom(err) => Self::Custom(err),
}
}
}
impl From<ErrorKind> for TransportError {
fn from(client_error_kind: ErrorKind) -> Self {
match client_error_kind {
ErrorKind::Io(err) => Self::IoError(err),
ErrorKind::TransactionError(err) => Self::TransactionError(err),
ErrorKind::Reqwest(err) => Self::Custom(format!("{:?}", err)),
ErrorKind::RpcError(err) => Self::Custom(format!("{:?}", err)),
ErrorKind::SerdeJson(err) => Self::Custom(format!("{:?}", err)),
ErrorKind::SigningError(err) => Self::Custom(format!("{:?}", err)),
ErrorKind::Custom(err) => Self::Custom(format!("{:?}", err)),
}
}
}
#[derive(ThisError, Debug)]
#[error("{kind}")]
pub struct Error {
pub request: Option<request::RpcRequest>,
#[source]
pub kind: ErrorKind,
}
impl Error {
pub fn new_with_request(kind: ErrorKind, request: request::RpcRequest) -> Self {
Self {
request: Some(request),
kind,
}
}
pub fn into_with_request(self, request: request::RpcRequest) -> Self {
Self {
request: Some(request),
..self
}
}
pub fn request(&self) -> Option<&request::RpcRequest> {
self.request.as_ref()
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn get_transaction_error(&self) -> Option<TransactionError> {
self.kind.get_transaction_error()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self {
request: None,
kind,
}
}
}
impl From<TransportError> for Error {
fn from(err: TransportError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<Error> for TransportError {
fn from(client_error: Error) -> Self {
client_error.kind.into()
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<request::RpcError> for Error {
fn from(err: request::RpcError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<serde_json::error::Error> for Error {
fn from(err: serde_json::error::Error) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<SignerError> for Error {
fn from(err: SignerError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
impl From<TransactionError> for Error {
fn from(err: TransactionError) -> Self {
Self {
request: None,
kind: err.into(),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;

View File

@ -1,5 +1,5 @@
use {
crate::rpc_filter::RpcFilterType,
crate::filter::RpcFilterType,
solana_account_decoder::{UiAccountEncoding, UiDataSliceConfig},
solana_sdk::{
clock::{Epoch, Slot},

View File

@ -1,6 +1,6 @@
//! Implementation defined RPC server errors
use {
crate::rpc_response::RpcSimulateTransactionResult,
crate::response::RpcSimulateTransactionResult,
jsonrpc_core::{Error, ErrorCode},
solana_sdk::clock::Slot,
solana_transaction_status::EncodeError,

View File

@ -1,6 +1,6 @@
#![allow(deprecated)]
use {
crate::rpc_config::{
crate::config::{
EncodingConfig, RpcBlockConfig, RpcEncodingConfigWrapper, RpcTransactionConfig,
},
solana_sdk::{clock::Slot, commitment_config::CommitmentConfig},

View File

@ -0,0 +1,5 @@
#[derive(Deserialize, Debug)]
pub struct RpcErrorObject {
pub code: i64,
pub message: String,
}

View File

@ -259,7 +259,7 @@ impl From<RpcMemcmp> for Memcmp {
}
}
pub(crate) fn maybe_map_filters(
pub fn maybe_map_filters(
node_version: Option<semver::Version>,
filters: &mut [RpcFilterType],
) -> Result<(), String> {

13
rpc-client-api/src/lib.rs Normal file
View File

@ -0,0 +1,13 @@
#![allow(clippy::integer_arithmetic)]
pub mod client_error;
pub mod config;
pub mod custom_error;
pub mod deprecated_config;
pub mod error_object;
pub mod filter;
pub mod request;
pub mod response;
#[macro_use]
extern crate serde_derive;

View File

@ -1,5 +1,5 @@
use {
crate::rpc_response::RpcSimulateTransactionResult,
crate::response::RpcSimulateTransactionResult,
serde_json::{json, Value},
solana_sdk::{clock::Slot, pubkey::Pubkey},
std::fmt,
@ -208,7 +208,7 @@ pub const MAX_GET_SLOT_LEADERS: usize = 5000;
pub const DELINQUENT_VALIDATOR_SLOT_DISTANCE: u64 = 128;
impl RpcRequest {
pub(crate) fn build_request_json(self, id: u64, params: Value) -> Value {
pub fn build_request_json(self, id: u64, params: Value) -> Value {
let jsonrpc = "2.0";
json!({
"jsonrpc": jsonrpc,
@ -274,7 +274,7 @@ pub enum TokenAccountsFilter {
mod tests {
use {
super::*,
crate::rpc_config::RpcTokenAccountsFilter,
crate::config::RpcTokenAccountsFilter,
solana_sdk::commitment_config::{CommitmentConfig, CommitmentLevel},
};

View File

@ -0,0 +1,28 @@
[package]
name = "solana-rpc-client-nonce-utils"
version = "1.12.0"
description = "Solana RPC Client Nonce Utilities"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-nonce-client"
edition = "2021"
[dependencies]
clap = "2.33.0"
solana-clap-utils = { path = "../clap-utils", version = "=1.12.0" }
solana-rpc-client = { path = "../rpc-client", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
thiserror = "1.0"
[dev-dependencies]
anyhow = "1.0.58"
futures = "0.3"
serde_json = "1.0.83"
solana-account-decoder = { path = "../account-decoder", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
tokio = { version = "1", features = ["full"] }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,11 +1,11 @@
use {
crate::{nonce_utils, rpc_client::RpcClient},
clap::ArgMatches,
solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
nonce::*,
offline::*,
},
solana_rpc_client::rpc_client::RpcClient,
solana_sdk::{
commitment_config::CommitmentConfig, fee_calculator::FeeCalculator, hash::Hash,
pubkey::Pubkey,
@ -35,8 +35,8 @@ impl Source {
}
Self::NonceAccount(ref pubkey) => {
#[allow(clippy::redundant_closure)]
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| nonce_utils::data_from_account(a))?;
let data = crate::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| crate::data_from_account(a))?;
Ok((data.blockhash(), data.fee_calculator))
}
}
@ -61,8 +61,8 @@ impl Source {
Ok(res)
}
Self::NonceAccount(ref pubkey) => {
let res = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)?;
let res = nonce_utils::data_from_account(&res)?;
let res = crate::get_account_with_commitment(rpc_client, pubkey, commitment)?;
let res = crate::data_from_account(&res)?;
Ok(Some(res)
.filter(|d| d.blockhash() == *blockhash)
.map(|d| d.fee_calculator))
@ -82,8 +82,8 @@ impl Source {
}
Self::NonceAccount(ref pubkey) => {
#[allow(clippy::redundant_closure)]
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| nonce_utils::data_from_account(a))?;
let data = crate::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| crate::data_from_account(a))?;
Ok(data.blockhash())
}
}
@ -99,8 +99,8 @@ impl Source {
Self::Cluster => rpc_client.is_blockhash_valid(blockhash, commitment)?,
Self::NonceAccount(ref pubkey) => {
#[allow(clippy::redundant_closure)]
let _ = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| nonce_utils::data_from_account(a))?;
let _ = crate::get_account_with_commitment(rpc_client, pubkey, commitment)
.and_then(|ref a| crate::data_from_account(a))?;
true
}
})
@ -185,14 +185,14 @@ impl Default for BlockhashQuery {
mod tests {
use {
super::*,
crate::{
blockhash_query,
rpc_request::RpcRequest,
rpc_response::{Response, RpcFeeCalculator, RpcFees, RpcResponseContext},
},
crate::blockhash_query,
clap::App,
serde_json::{self, json},
solana_account_decoder::{UiAccount, UiAccountEncoding},
solana_rpc_client_api::{
request::RpcRequest,
response::{Response, RpcFeeCalculator, RpcFees, RpcResponseContext},
},
solana_sdk::{
account::Account,
hash::hash,

View File

@ -1,10 +1,13 @@
//! Durable transaction nonce helpers.
pub use crate::nonblocking::nonce_utils::{
pub mod blockhash_query;
pub mod nonblocking;
pub use crate::nonblocking::{
account_identity_ok, data_from_account, data_from_state, state_from_account, Error,
};
use {
crate::rpc_client::RpcClient,
solana_rpc_client::rpc_client::RpcClient,
solana_sdk::{account::Account, commitment_config::CommitmentConfig, pubkey::Pubkey},
};

View File

@ -1,11 +1,12 @@
use {
crate::nonblocking::{nonce_utils, rpc_client::RpcClient},
crate::nonblocking,
clap::ArgMatches,
solana_clap_utils::{
input_parsers::{pubkey_of, value_of},
nonce::*,
offline::*,
},
solana_rpc_client::nonblocking::rpc_client::RpcClient,
solana_sdk::{commitment_config::CommitmentConfig, hash::Hash, pubkey::Pubkey},
};
@ -30,9 +31,9 @@ impl Source {
}
Self::NonceAccount(ref pubkey) => {
#[allow(clippy::redundant_closure)]
let data = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
let data = nonblocking::get_account_with_commitment(rpc_client, pubkey, commitment)
.await
.and_then(|ref a| nonce_utils::data_from_account(a))?;
.and_then(|ref a| nonblocking::data_from_account(a))?;
Ok(data.blockhash())
}
}
@ -48,9 +49,9 @@ impl Source {
Self::Cluster => rpc_client.is_blockhash_valid(blockhash, commitment).await?,
Self::NonceAccount(ref pubkey) => {
#[allow(clippy::redundant_closure)]
let _ = nonce_utils::get_account_with_commitment(rpc_client, pubkey, commitment)
let _ = nonblocking::get_account_with_commitment(rpc_client, pubkey, commitment)
.await
.and_then(|ref a| nonce_utils::data_from_account(a))?;
.and_then(|ref a| nonblocking::data_from_account(a))?;
true
}
})
@ -115,14 +116,14 @@ impl Default for BlockhashQuery {
mod tests {
use {
super::*,
crate::{
nonblocking::blockhash_query,
rpc_request::RpcRequest,
rpc_response::{Response, RpcBlockhash, RpcResponseContext},
},
crate::nonblocking::blockhash_query,
clap::App,
serde_json::{self, json},
solana_account_decoder::{UiAccount, UiAccountEncoding},
solana_rpc_client_api::{
request::RpcRequest,
response::{Response, RpcBlockhash, RpcResponseContext},
},
solana_sdk::{
account::Account,
fee_calculator::FeeCalculator,

View File

@ -1,7 +1,9 @@
//! Durable transaction nonce helpers.
pub mod blockhash_query;
use {
crate::nonblocking::rpc_client::RpcClient,
solana_rpc_client::nonblocking::rpc_client::RpcClient,
solana_sdk::{
account::{Account, ReadableAccount},
account_utils::StateMut,
@ -97,10 +99,8 @@ pub fn account_identity_ok<T: ReadableAccount>(account: &T) -> Result<(), Error>
/// Determine if a nonce account is initialized:
///
/// ```no_run
/// use solana_client::nonblocking::{
/// rpc_client::RpcClient,
/// nonce_utils,
/// };
/// use solana_rpc_client_nonce_utils::nonblocking;
/// use solana_rpc_client::nonblocking::rpc_client::RpcClient;
/// use solana_sdk::{
/// nonce::State,
/// pubkey::Pubkey,
@ -116,7 +116,7 @@ pub fn account_identity_ok<T: ReadableAccount>(account: &T) -> Result<(), Error>
/// // Sign the tx with nonce_account's `blockhash` instead of the
/// // network's latest blockhash.
/// let nonce_account = client.get_account(nonce_account_pubkey).await?;
/// let nonce_state = nonce_utils::state_from_account(&nonce_account)?;
/// let nonce_state = nonblocking::state_from_account(&nonce_account)?;
///
/// Ok(!matches!(nonce_state, State::Uninitialized))
/// }
@ -149,10 +149,8 @@ pub fn state_from_account<T: ReadableAccount + StateMut<Versions>>(
/// Create and sign a transaction with a durable nonce:
///
/// ```no_run
/// use solana_client::nonblocking::{
/// rpc_client::RpcClient,
/// nonce_utils,
/// };
/// use solana_rpc_client_nonce_utils::nonblocking;
/// use solana_rpc_client::nonblocking::rpc_client::RpcClient;
/// use solana_sdk::{
/// message::Message,
/// pubkey::Pubkey,
@ -201,7 +199,7 @@ pub fn state_from_account<T: ReadableAccount + StateMut<Versions>>(
/// // Sign the tx with nonce_account's `blockhash` instead of the
/// // network's latest blockhash.
/// let nonce_account = client.get_account(nonce_account_pubkey).await?;
/// let nonce_data = nonce_utils::data_from_account(&nonce_account)?;
/// let nonce_data = nonblocking::data_from_account(&nonce_account)?;
/// let blockhash = nonce_data.blockhash();
///
/// tx.try_sign(&[payer], blockhash)?;

40
rpc-client/Cargo.toml Normal file
View File

@ -0,0 +1,40 @@
[package]
name = "solana-rpc-client"
version = "1.12.0"
description = "Solana RPC Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-rpc-client"
edition = "2021"
[dependencies]
async-trait = "0.1.57"
base64 = "0.13.0"
bincode = "1.3.3"
bs58 = "0.4.0"
indicatif = "0.17.0"
log = "0.4.17"
reqwest = { version = "0.11.11", default-features = false, features = ["blocking", "brotli", "deflate", "gzip", "rustls-tls", "json"] }
semver = "1.0.13"
serde = "1.0.143"
serde_derive = "1.0.103"
serde_json = "1.0.83"
solana-account-decoder = { path = "../account-decoder", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-transaction-status = { path = "../transaction-status", version = "=1.12.0" }
solana-version = { path = "../version", version = "=1.12.0" }
solana-vote-program = { path = "../programs/vote", version = "=1.12.0" }
tokio = { version = "1", features = ["full"] }
[dev-dependencies]
assert_matches = "1.5.0"
crossbeam-channel = "0.5"
futures = "0.3"
jsonrpc-core = "18.0.0"
jsonrpc-http-server = "18.0.0"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,13 +1,7 @@
//! Nonblocking [`RpcSender`] over HTTP.
use {
crate::{
client_error::Result,
rpc_custom_error,
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData},
rpc_response::RpcSimulateTransactionResult,
rpc_sender::*,
},
crate::rpc_sender::*,
async_trait::async_trait,
log::*,
reqwest::{
@ -15,6 +9,13 @@ use {
header::{self, CONTENT_TYPE, RETRY_AFTER},
StatusCode,
},
solana_rpc_client_api::{
client_error::Result,
custom_error,
error_object::RpcErrorObject,
request::{RpcError, RpcRequest, RpcResponseErrorData},
response::RpcSimulateTransactionResult,
},
std::{
sync::{
atomic::{AtomicU64, Ordering},
@ -72,12 +73,6 @@ impl HttpSender {
}
}
#[derive(Deserialize, Debug)]
pub(crate) struct RpcErrorObject {
pub code: i64,
pub message: String,
}
struct StatsUpdater<'a> {
stats: &'a RwLock<RpcTransportStats>,
request_start_time: Instant,
@ -169,7 +164,7 @@ impl RpcSender for HttpSender {
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone()) {
Ok(rpc_error_object) => {
let data = match rpc_error_object.code {
rpc_custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
Err(err) => {
@ -178,9 +173,9 @@ impl RpcSender for HttpSender {
}
}
},
rpc_custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
match serde_json::from_value::<rpc_custom_error::NodeUnhealthyErrorData>(json["error"]["data"].clone()) {
Ok(rpc_custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
match serde_json::from_value::<custom_error::NodeUnhealthyErrorData>(json["error"]["data"].clone()) {
Ok(custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
Err(_err) => {
RpcResponseErrorData::Empty
}

15
rpc-client/src/lib.rs Normal file
View File

@ -0,0 +1,15 @@
#![allow(clippy::integer_arithmetic)]
pub mod http_sender;
pub mod mock_sender;
pub mod nonblocking;
pub mod rpc_client;
pub mod rpc_sender;
pub mod spinner;
pub mod mock_sender_for_cli {
/// Magic `SIGNATURE` value used by `solana-cli` unit tests.
/// Please don't use this constant.
pub const SIGNATURE: &str =
"43yNSFC6fYTuPgTNFFhF4axw7AfWxB2BPdurme8yrsWEYwm8299xh8n6TAHjGymiSub1XtyxTNyd9GBfY2hxoBw8";
}

View File

@ -1,11 +1,15 @@
//! A nonblocking [`RpcSender`] used for unit testing [`RpcClient`](crate::rpc_client::RpcClient).
use {
crate::{
crate::rpc_sender::*,
async_trait::async_trait,
serde_json::{json, Number, Value},
solana_account_decoder::{UiAccount, UiAccountEncoding},
solana_rpc_client_api::{
client_error::Result,
rpc_config::RpcBlockProductionConfig,
rpc_request::RpcRequest,
rpc_response::{
config::RpcBlockProductionConfig,
request::RpcRequest,
response::{
Response, RpcAccountBalance, RpcBlockProduction, RpcBlockProductionRange, RpcBlockhash,
RpcConfirmedTransactionStatusWithSignature, RpcContactInfo, RpcFees, RpcIdentity,
RpcInflationGovernor, RpcInflationRate, RpcInflationReward, RpcKeyedAccount,
@ -13,11 +17,7 @@ use {
RpcStakeActivation, RpcSupply, RpcVersionInfo, RpcVoteAccountInfo,
RpcVoteAccountStatus, StakeActivationState,
},
rpc_sender::*,
},
async_trait::async_trait,
serde_json::{json, Number, Value},
solana_account_decoder::{UiAccount, UiAccountEncoding},
solana_sdk::{
account::Account,
clock::{Slot, UnixTimestamp},

View File

@ -0,0 +1 @@
pub mod rpc_client;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
//! A transport for RPC calls.
use {
crate::{client_error::Result, rpc_request::RpcRequest},
async_trait::async_trait,
solana_rpc_client_api::{client_error::Result, request::RpcRequest},
std::time::Duration,
};

17
rpc-client/src/spinner.rs Normal file
View File

@ -0,0 +1,17 @@
//! Spinner creator
use {
indicatif::{ProgressBar, ProgressStyle},
std::time::Duration,
};
pub fn new_progress_bar() -> ProgressBar {
let progress_bar = ProgressBar::new(42);
progress_bar.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {wide_msg}")
.expect("ProgresStyle::template direct input to be correct"),
);
progress_bar.enable_steady_tick(Duration::from_millis(100));
progress_bar
}

View File

@ -4,6 +4,7 @@ pub mod max_slots;
pub mod optimistically_confirmed_bank_tracker;
pub mod parsed_token_accounts;
pub mod rpc;
mod rpc_cache;
pub mod rpc_completed_slots_service;
pub mod rpc_health;
pub mod rpc_pubsub;

View File

@ -3,7 +3,7 @@
use {
crate::{
max_slots::MaxSlots, optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
parsed_token_accounts::*, rpc_health::*,
parsed_token_accounts::*, rpc_cache::LargestAccountsCache, rpc_health::*,
},
bincode::{config::Options, serialize},
crossbeam_channel::{unbounded, Receiver, Sender},
@ -16,7 +16,6 @@ use {
},
solana_client::{
connection_cache::ConnectionCache,
rpc_cache::LargestAccountsCache,
rpc_config::*,
rpc_custom_error::RpcCustomError,
rpc_deprecated_config::*,

View File

@ -1,5 +1,5 @@
use {
crate::{rpc_config::RpcLargestAccountsFilter, rpc_response::RpcAccountBalance},
solana_client::{rpc_config::RpcLargestAccountsFilter, rpc_response::RpcAccountBalance},
std::{
collections::HashMap,
time::{Duration, SystemTime},
@ -20,14 +20,14 @@ struct LargestAccountsCacheValue {
}
impl LargestAccountsCache {
pub fn new(duration: u64) -> Self {
pub(crate) fn new(duration: u64) -> Self {
Self {
duration,
cache: HashMap::new(),
}
}
pub fn get_largest_accounts(
pub(crate) fn get_largest_accounts(
&self,
filter: &Option<RpcLargestAccountsFilter>,
) -> Option<(u64, Vec<RpcAccountBalance>)> {
@ -41,7 +41,7 @@ impl LargestAccountsCache {
})
}
pub fn set_largest_accounts(
pub(crate) fn set_largest_accounts(
&mut self,
filter: &Option<RpcLargestAccountsFilter>,
slot: u64,

View File

@ -9,6 +9,7 @@ use {
rpc_accounts::*, rpc_bank::*, rpc_deprecated_v1_7::*, rpc_deprecated_v1_9::*,
rpc_full::*, rpc_minimal::*, rpc_obsolete_v1_7::*, *,
},
rpc_cache::LargestAccountsCache,
rpc_health::*,
},
crossbeam_channel::unbounded,
@ -18,7 +19,7 @@ use {
RequestMiddlewareAction, ServerBuilder,
},
regex::Regex,
solana_client::{connection_cache::ConnectionCache, rpc_cache::LargestAccountsCache},
solana_client::connection_cache::ConnectionCache,
solana_gossip::cluster_info::ClusterInfo,
solana_ledger::{
bigtable_upload::ConfirmedBlockUploadConfig,

25
thin-client/Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
[package]
name = "solana-thin-client"
version = "1.12.0"
description = "Solana Thin Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-thin-client"
edition = "2021"
[dependencies]
bincode = "1.3.3"
log = "0.4.17"
solana-rpc-client = { path = "../rpc-client", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-tpu-client = { path = "../tpu-client", version = "=1.12.0" }
[dev-dependencies]
rayon = "1.5.3"
solana-logger = { path = "../logger", version = "=1.12.0" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

3
thin-client/src/lib.rs Normal file
View File

@ -0,0 +1,3 @@
#![allow(clippy::integer_arithmetic)]
pub mod thin_client;

View File

@ -4,12 +4,9 @@
//! unstable and may change in future releases.
use {
crate::{
connection_cache::ConnectionCache, rpc_client::RpcClient,
rpc_config::RpcProgramAccountsConfig, rpc_response::Response,
tpu_connection::TpuConnection,
},
log::*,
solana_rpc_client::rpc_client::RpcClient,
solana_rpc_client_api::{config::RpcProgramAccountsConfig, response::Response},
solana_sdk::{
account::Account,
client::{AsyncClient, Client, SyncClient},
@ -28,6 +25,7 @@ use {
transaction::{self, Transaction, VersionedTransaction},
transport::Result as TransportResult,
},
solana_tpu_client::{connection_cache::ConnectionCache, tpu_connection::TpuConnection},
std::{
io,
net::SocketAddr,

2
tpu-client/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target/
/farf/

48
tpu-client/Cargo.toml Normal file
View File

@ -0,0 +1,48 @@
[package]
name = "solana-tpu-client"
version = "1.12.0"
description = "Solana TPU Client"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-tpu-client"
edition = "2021"
[dependencies]
async-mutex = "1.4.0"
async-trait = "0.1.57"
bincode = "1.3.3"
enum_dispatch = "0.3.8"
futures = "0.3"
futures-util = "0.3.21"
indexmap = "1.9.1"
indicatif = "0.17.0"
itertools = "0.10.2"
lazy_static = "1.4.0"
log = "0.4.17"
quinn = "0.8.4"
quinn-proto = "0.8.4"
quinn-udp = "0.1.3"
rand = "0.7.0"
rayon = "1.5.3"
rustls = { version = "0.20.6", features = ["dangerous_configuration"] }
solana-measure = { path = "../measure", version = "=1.12.0" }
solana-metrics = { path = "../metrics", version = "=1.12.0" }
solana-net-utils = { path = "../net-utils", version = "=1.12.0" }
solana-pubsub-client = { path = "../pubsub-client", version = "=1.12.0" }
solana-rpc-client = { path = "../rpc-client", version = "=1.12.0" }
solana-rpc-client-api = { path = "../rpc-client-api", version = "=1.12.0" }
solana-sdk = { path = "../sdk", version = "=1.12.0" }
solana-streamer = { path = "../streamer", version = "=1.12.0" }
thiserror = "1.0"
tokio = { version = "1", features = ["full"] }
[dev-dependencies]
crossbeam-channel = "0.5"
rand_chacha = "0.2.2"
solana-logger = { path = "../logger", version = "=1.12.0" }
solana-perf = { path = "../perf", version = "=1.12.0" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

11
tpu-client/src/lib.rs Normal file
View File

@ -0,0 +1,11 @@
#![allow(clippy::integer_arithmetic)]
pub mod connection_cache;
pub mod nonblocking;
pub mod quic_client;
pub mod tpu_client;
pub mod tpu_connection;
pub mod udp_client;
#[macro_use]
extern crate solana_metrics;

View File

@ -0,0 +1,4 @@
pub mod quic_client;
pub mod tpu_client;
pub mod tpu_connection;
pub mod udp_client;

View File

@ -3,8 +3,8 @@
//! server's flow control.
use {
crate::{
client_error::ClientErrorKind, connection_cache::ConnectionCacheStats,
nonblocking::tpu_connection::TpuConnection, tpu_connection::ClientStats,
connection_cache::ConnectionCacheStats, nonblocking::tpu_connection::TpuConnection,
tpu_connection::ClientStats,
},
async_mutex::Mutex,
async_trait::async_trait,
@ -17,6 +17,7 @@ use {
},
solana_measure::measure::Measure,
solana_net_utils::VALIDATOR_PORT_RANGE,
solana_rpc_client_api::client_error::ErrorKind as ClientErrorKind,
solana_sdk::{
quic::{
QUIC_CONNECTION_HANDSHAKE_TIMEOUT_MS, QUIC_KEEP_ALIVE_MS, QUIC_MAX_TIMEOUT_MS,
@ -82,6 +83,12 @@ pub enum QuicError {
ConnectError(#[from] ConnectError),
}
impl From<QuicError> for ClientErrorKind {
fn from(quic_error: QuicError) -> Self {
Self::Custom(format!("{:?}", quic_error))
}
}
impl QuicLazyInitializedEndpoint {
pub fn new(client_certificate: Arc<QuicClientCertificate>) -> Self {
Self {
@ -439,7 +446,8 @@ impl QuicClient {
T: AsRef<[u8]>,
{
self._send_buffer(data.as_ref(), stats, connection_stats)
.await?;
.await
.map_err(Into::<ClientErrorKind>::into)?;
Ok(())
}
@ -483,7 +491,8 @@ impl QuicClient {
}
let connection = self
._send_buffer(buffers[0].as_ref(), stats, connection_stats)
.await?;
.await
.map_err(Into::<ClientErrorKind>::into)?;
// Used to avoid dereferencing the Arc multiple times below
// by just getting a reference to the NewConnection once
@ -504,7 +513,10 @@ impl QuicClient {
.collect();
for f in futures {
f.await.into_iter().try_for_each(|res| res)?;
f.await
.into_iter()
.try_for_each(|res| res)
.map_err(Into::<ClientErrorKind>::into)?;
}
Ok(())
}

View File

@ -1,15 +1,7 @@
use {
crate::{
client_error::{ClientError, Result as ClientResult},
connection_cache::ConnectionCache,
nonblocking::{
pubsub_client::{PubsubClient, PubsubClientError},
rpc_client::RpcClient,
tpu_connection::TpuConnection,
},
rpc_request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
rpc_response::{RpcContactInfo, SlotUpdate},
spinner,
nonblocking::tpu_connection::TpuConnection,
tpu_client::{
RecentLeaderSlots, TpuClientConfig, MAX_FANOUT_SLOTS, SEND_TRANSACTION_INTERVAL,
TRANSACTION_RESEND_INTERVAL,
@ -17,7 +9,15 @@ use {
},
bincode::serialize,
futures_util::{future::join_all, stream::StreamExt},
indicatif::ProgressBar,
log::*,
solana_pubsub_client::nonblocking::pubsub_client::{PubsubClient, PubsubClientError},
solana_rpc_client::{nonblocking::rpc_client::RpcClient, spinner},
solana_rpc_client_api::{
client_error::{Error as ClientError, Result as ClientResult},
request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
response::{RpcContactInfo, SlotUpdate},
},
solana_sdk::{
clock::Slot,
commitment_config::CommitmentConfig,
@ -366,7 +366,7 @@ impl TpuClient {
if !self.send_transaction(transaction).await {
let _result = self.rpc_client.send_transaction(transaction).await.ok();
}
spinner::set_message_for_confirmed_transactions(
set_message_for_confirmed_transactions(
&progress_bar,
confirmed_transactions,
total_transactions,
@ -381,7 +381,7 @@ impl TpuClient {
// Wait for the next block before checking for transaction statuses
let mut block_height_refreshes = 10;
spinner::set_message_for_confirmed_transactions(
set_message_for_confirmed_transactions(
&progress_bar,
confirmed_transactions,
total_transactions,
@ -430,7 +430,7 @@ impl TpuClient {
}
}
}
spinner::set_message_for_confirmed_transactions(
set_message_for_confirmed_transactions(
&progress_bar,
confirmed_transactions,
total_transactions,
@ -666,3 +666,26 @@ async fn maybe_fetch_cache_info(
maybe_slot_leaders,
}
}
fn set_message_for_confirmed_transactions(
progress_bar: &ProgressBar,
confirmed_transactions: u32,
total_transactions: usize,
block_height: Option<u64>,
last_valid_block_height: u64,
status: &str,
) {
progress_bar.set_message(format!(
"{:>5.1}% | {:<40}{}",
confirmed_transactions as f64 * 100. / total_transactions as f64,
status,
match block_height {
Some(block_height) => format!(
" [block height {}; re-sign in {} blocks]",
block_height,
last_valid_block_height.saturating_sub(block_height),
),
None => String::new(),
},
));
}

View File

@ -2,8 +2,9 @@ pub use crate::nonblocking::tpu_client::TpuSenderError;
use {
crate::{
connection_cache::ConnectionCache,
nonblocking::tpu_client::TpuClient as NonblockingTpuClient, rpc_client::RpcClient,
nonblocking::tpu_client::TpuClient as NonblockingTpuClient,
},
solana_rpc_client::rpc_client::RpcClient,
solana_sdk::{
clock::Slot,
message::Message,

View File

@ -2,13 +2,13 @@
mod tests {
use {
crossbeam_channel::{unbounded, Receiver},
solana_client::{
connection_cache::ConnectionCacheStats,
nonblocking::quic_client::QuicLazyInitializedEndpoint,
},
solana_perf::packet::PacketBatch,
solana_sdk::{packet::PACKET_DATA_SIZE, signature::Keypair},
solana_streamer::{quic::StreamStats, streamer::StakedNodes},
solana_tpu_client::{
connection_cache::ConnectionCacheStats,
nonblocking::quic_client::QuicLazyInitializedEndpoint,
},
std::{
net::{IpAddr, SocketAddr, UdpSocket},
sync::{
@ -62,7 +62,7 @@ mod tests {
#[test]
fn test_quic_client_multiple_writes() {
use solana_client::{quic_client::QuicTpuConnection, tpu_connection::TpuConnection};
use solana_tpu_client::{quic_client::QuicTpuConnection, tpu_connection::TpuConnection};
solana_logger::setup();
let (sender, receiver) = unbounded();
let staked_nodes = Arc::new(RwLock::new(StakedNodes::default()));
@ -105,7 +105,7 @@ mod tests {
#[tokio::test]
async fn test_nonblocking_quic_client_multiple_writes() {
use solana_client::nonblocking::{
use solana_tpu_client::nonblocking::{
quic_client::QuicTpuConnection, tpu_connection::TpuConnection,
};
solana_logger::setup();