@ -1,20 +1,161 @@
|
||||
use crate::rpc_request;
|
||||
use solana_sdk::{signature::SignerError, transaction::TransactionError};
|
||||
use std::{fmt, io};
|
||||
use solana_sdk::{
|
||||
signature::SignerError, transaction::TransactionError, transport::TransportError,
|
||||
};
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ClientError {
|
||||
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("Custom: {0}")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for ClientError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "solana client error")
|
||||
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 Into<TransportError> for ClientErrorKind {
|
||||
fn into(self) -> TransportError {
|
||||
match self {
|
||||
Self::Io(err) => TransportError::IoError(err),
|
||||
Self::TransactionError(err) => TransportError::TransactionError(err),
|
||||
Self::Reqwest(err) => TransportError::Custom(format!("{:?}", err)),
|
||||
Self::RpcError(err) => TransportError::Custom(format!("{:?}", err)),
|
||||
Self::SerdeJson(err) => TransportError::Custom(format!("{:?}", err)),
|
||||
Self::SigningError(err) => TransportError::Custom(format!("{:?}", err)),
|
||||
Self::Custom(err) => TransportError::Custom(format!("{:?}", err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{kind}")]
|
||||
pub struct ClientError {
|
||||
command: Option<&'static str>,
|
||||
#[source]
|
||||
#[error(transparent)]
|
||||
kind: ClientErrorKind,
|
||||
}
|
||||
|
||||
impl ClientError {
|
||||
pub fn new_with_command(kind: ClientErrorKind, command: &'static str) -> Self {
|
||||
Self {
|
||||
command: Some(command),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_with_command(self, command: &'static str) -> Self {
|
||||
Self {
|
||||
command: Some(command),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(&self) -> Option<&'static str> {
|
||||
self.command
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> &ClientErrorKind {
|
||||
&self.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClientErrorKind> for ClientError {
|
||||
fn from(kind: ClientErrorKind) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransportError> for ClientError {
|
||||
fn from(err: TransportError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<TransportError> for ClientError {
|
||||
fn into(self) -> TransportError {
|
||||
self.kind.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for ClientError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for ClientError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rpc_request::RpcError> for ClientError {
|
||||
fn from(err: rpc_request::RpcError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::error::Error> for ClientError {
|
||||
fn from(err: serde_json::error::Error) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignerError> for ClientError {
|
||||
fn from(err: SignerError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for ClientError {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
Self {
|
||||
command: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, ClientError>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{client_error::ClientError, rpc_request::RpcRequest};
|
||||
use crate::{client_error::Result, rpc_request::RpcRequest};
|
||||
|
||||
pub(crate) trait GenericRpcClientRequest {
|
||||
fn send(
|
||||
@ -6,5 +6,5 @@ pub(crate) trait GenericRpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: serde_json::Value,
|
||||
retries: usize,
|
||||
) -> Result<serde_json::Value, ClientError>;
|
||||
) -> Result<serde_json::Value>;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
client_error::ClientError,
|
||||
client_error::Result,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{Response, RpcResponseContext},
|
||||
@ -41,7 +41,7 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: serde_json::Value,
|
||||
_retries: usize,
|
||||
) -> Result<serde_json::Value, ClientError> {
|
||||
) -> Result<serde_json::Value> {
|
||||
if let Some(value) = self.mocks.write().unwrap().remove(request) {
|
||||
return Ok(value);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
client_error::ClientError,
|
||||
client_error::Result,
|
||||
generic_rpc_client_request::GenericRpcClientRequest,
|
||||
rpc_request::{RpcError, RpcRequest},
|
||||
};
|
||||
@ -34,7 +34,7 @@ impl GenericRpcClientRequest for RpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: serde_json::Value,
|
||||
mut retries: usize,
|
||||
) -> Result<serde_json::Value, ClientError> {
|
||||
) -> Result<serde_json::Value> {
|
||||
// Concurrent requests are not supported so reuse the same request id for all requests
|
||||
let request_id = 1;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde_json::{json, Value};
|
||||
use std::{error, fmt};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum RpcRequest {
|
||||
@ -95,26 +95,16 @@ impl RpcRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RpcError {
|
||||
#[error("rpc reques error: {0}")]
|
||||
RpcRequestError(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for RpcError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "invalid")
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for RpcError {
|
||||
fn description(&self) -> &str {
|
||||
"invalid"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn error::Error> {
|
||||
// Generic error, underlying cause isn't tracked.
|
||||
None
|
||||
}
|
||||
#[error("parse error: expected {0}")]
|
||||
ParseError(String), /* "expected" */
|
||||
// Anything in a `ForUser` needs to die. The caller should be
|
||||
// deciding what to tell their user
|
||||
#[error("{0}")]
|
||||
ForUser(String), /* "direct-to-user message" */
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::rpc_request::RpcError;
|
||||
use crate::{client_error, rpc_request::RpcError};
|
||||
use bincode::serialize;
|
||||
use jsonrpc_core::Result as JsonResult;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock::{Epoch, Slot},
|
||||
@ -9,10 +8,9 @@ use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
transaction::{Result, Transaction},
|
||||
};
|
||||
use std::{collections::HashMap, io, net::SocketAddr, str::FromStr};
|
||||
use std::{collections::HashMap, net::SocketAddr, str::FromStr};
|
||||
|
||||
pub type RpcResponseIn<T> = JsonResult<Response<T>>;
|
||||
pub type RpcResponse<T> = io::Result<Response<T>>;
|
||||
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RpcResponseContext {
|
||||
|
@ -188,7 +188,7 @@ impl ThinClient {
|
||||
transaction: &mut Transaction,
|
||||
tries: usize,
|
||||
min_confirmed_blocks: usize,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
self.send_and_confirm_transaction(&[keypair], transaction, tries, min_confirmed_blocks)
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ impl ThinClient {
|
||||
keypair: &Keypair,
|
||||
transaction: &mut Transaction,
|
||||
tries: usize,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
self.send_and_confirm_transaction(&[keypair], transaction, tries, 0)
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ impl ThinClient {
|
||||
transaction: &mut Transaction,
|
||||
tries: usize,
|
||||
pending_confirmations: usize,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
for x in 0..tries {
|
||||
let now = Instant::now();
|
||||
let mut buf = vec![0; serialized_size(&transaction).unwrap() as usize];
|
||||
@ -243,13 +243,14 @@ impl ThinClient {
|
||||
}
|
||||
}
|
||||
info!("{} tries failed transfer to {}", x, self.tpu_addr());
|
||||
let (blockhash, _fee_calculator) = self.rpc_client().get_recent_blockhash()?;
|
||||
let (blockhash, _fee_calculator) = self.get_recent_blockhash()?;
|
||||
transaction.sign(keypairs, blockhash);
|
||||
}
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("retry_transfer failed in {} retries", tries),
|
||||
))
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
pub fn poll_balance_with_timeout_and_commitment(
|
||||
@ -258,13 +259,15 @@ impl ThinClient {
|
||||
polling_frequency: &Duration,
|
||||
timeout: &Duration,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> io::Result<u64> {
|
||||
self.rpc_client().poll_balance_with_timeout_and_commitment(
|
||||
pubkey,
|
||||
polling_frequency,
|
||||
timeout,
|
||||
commitment_config,
|
||||
)
|
||||
) -> TransportResult<u64> {
|
||||
self.rpc_client()
|
||||
.poll_balance_with_timeout_and_commitment(
|
||||
pubkey,
|
||||
polling_frequency,
|
||||
timeout,
|
||||
commitment_config,
|
||||
)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn poll_balance_with_timeout(
|
||||
@ -272,8 +275,8 @@ impl ThinClient {
|
||||
pubkey: &Pubkey,
|
||||
polling_frequency: &Duration,
|
||||
timeout: &Duration,
|
||||
) -> io::Result<u64> {
|
||||
self.rpc_client().poll_balance_with_timeout_and_commitment(
|
||||
) -> TransportResult<u64> {
|
||||
self.poll_balance_with_timeout_and_commitment(
|
||||
pubkey,
|
||||
polling_frequency,
|
||||
timeout,
|
||||
@ -281,18 +284,18 @@ impl ThinClient {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn poll_get_balance(&self, pubkey: &Pubkey) -> io::Result<u64> {
|
||||
self.rpc_client()
|
||||
.poll_get_balance_with_commitment(pubkey, CommitmentConfig::default())
|
||||
pub fn poll_get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
|
||||
self.poll_get_balance_with_commitment(pubkey, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
pub fn poll_get_balance_with_commitment(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> io::Result<u64> {
|
||||
) -> TransportResult<u64> {
|
||||
self.rpc_client()
|
||||
.poll_get_balance_with_commitment(pubkey, commitment_config)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn wait_for_balance(&self, pubkey: &Pubkey, expected_balance: Option<u64>) -> Option<u64> {
|
||||
@ -321,9 +324,9 @@ impl ThinClient {
|
||||
signature: &Signature,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> TransportResult<()> {
|
||||
Ok(self
|
||||
.rpc_client()
|
||||
.poll_for_signature_with_commitment(signature, commitment_config)?)
|
||||
self.rpc_client()
|
||||
.poll_for_signature_with_commitment(signature, commitment_config)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Check a signature in the bank. This method blocks
|
||||
@ -332,16 +335,17 @@ impl ThinClient {
|
||||
self.rpc_client().check_signature(signature)
|
||||
}
|
||||
|
||||
pub fn validator_exit(&self) -> io::Result<bool> {
|
||||
self.rpc_client().validator_exit()
|
||||
pub fn validator_exit(&self) -> TransportResult<bool> {
|
||||
self.rpc_client().validator_exit().map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn get_num_blocks_since_signature_confirmation(
|
||||
&mut self,
|
||||
sig: &Signature,
|
||||
) -> io::Result<usize> {
|
||||
) -> TransportResult<usize> {
|
||||
self.rpc_client()
|
||||
.get_num_blocks_since_signature_confirmation(sig)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,14 +404,14 @@ impl SyncClient for ThinClient {
|
||||
pubkey: &Pubkey,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> TransportResult<Option<Account>> {
|
||||
Ok(self
|
||||
.rpc_client()
|
||||
.get_account_with_commitment(pubkey, commitment_config)?
|
||||
.value)
|
||||
self.rpc_client()
|
||||
.get_account_with_commitment(pubkey, commitment_config)
|
||||
.map_err(|e| e.into())
|
||||
.map(|r| r.value)
|
||||
}
|
||||
|
||||
fn get_balance(&self, pubkey: &Pubkey) -> TransportResult<u64> {
|
||||
Ok(self.rpc_client().get_balance(pubkey)?)
|
||||
self.rpc_client().get_balance(pubkey).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn get_balance_with_commitment(
|
||||
@ -415,10 +419,10 @@ impl SyncClient for ThinClient {
|
||||
pubkey: &Pubkey,
|
||||
commitment_config: CommitmentConfig,
|
||||
) -> TransportResult<u64> {
|
||||
let balance = self
|
||||
.rpc_client()
|
||||
.get_balance_with_commitment(pubkey, commitment_config)?;
|
||||
Ok(balance.value)
|
||||
self.rpc_client()
|
||||
.get_balance_with_commitment(pubkey, commitment_config)
|
||||
.map_err(|e| e.into())
|
||||
.map(|r| r.value)
|
||||
}
|
||||
|
||||
fn get_recent_blockhash(&self) -> TransportResult<(Hash, FeeCalculator)> {
|
||||
@ -449,15 +453,16 @@ impl SyncClient for ThinClient {
|
||||
&self,
|
||||
blockhash: &Hash,
|
||||
) -> TransportResult<Option<FeeCalculator>> {
|
||||
let fee_calculator = self
|
||||
.rpc_client()
|
||||
.get_fee_calculator_for_blockhash(blockhash)?;
|
||||
Ok(fee_calculator)
|
||||
self.rpc_client()
|
||||
.get_fee_calculator_for_blockhash(blockhash)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn get_fee_rate_governor(&self) -> TransportResult<FeeRateGovernor> {
|
||||
let fee_rate_governor = self.rpc_client().get_fee_rate_governor()?;
|
||||
Ok(fee_rate_governor.value)
|
||||
self.rpc_client()
|
||||
.get_fee_rate_governor()
|
||||
.map_err(|e| e.into())
|
||||
.map(|r| r.value)
|
||||
}
|
||||
|
||||
fn get_signature_status(
|
||||
@ -555,23 +560,26 @@ impl SyncClient for ThinClient {
|
||||
signature: &Signature,
|
||||
min_confirmed_blocks: usize,
|
||||
) -> TransportResult<usize> {
|
||||
Ok(self
|
||||
.rpc_client()
|
||||
.poll_for_signature_confirmation(signature, min_confirmed_blocks)?)
|
||||
self.rpc_client()
|
||||
.poll_for_signature_confirmation(signature, min_confirmed_blocks)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn poll_for_signature(&self, signature: &Signature) -> TransportResult<()> {
|
||||
Ok(self.rpc_client().poll_for_signature(signature)?)
|
||||
self.rpc_client()
|
||||
.poll_for_signature(signature)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn get_new_blockhash(&self, blockhash: &Hash) -> TransportResult<(Hash, FeeCalculator)> {
|
||||
let new_blockhash = self.rpc_client().get_new_blockhash(blockhash)?;
|
||||
Ok(new_blockhash)
|
||||
self.rpc_client()
|
||||
.get_new_blockhash(blockhash)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncClient for ThinClient {
|
||||
fn async_send_transaction(&self, transaction: Transaction) -> io::Result<Signature> {
|
||||
fn async_send_transaction(&self, transaction: Transaction) -> TransportResult<Signature> {
|
||||
let mut buf = vec![0; serialized_size(&transaction).unwrap() as usize];
|
||||
let mut wr = std::io::Cursor::new(&mut buf[..]);
|
||||
serialize_into(&mut wr, &transaction)
|
||||
@ -586,7 +594,7 @@ impl AsyncClient for ThinClient {
|
||||
keypairs: &T,
|
||||
message: Message,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
let transaction = Transaction::new(keypairs, message, recent_blockhash);
|
||||
self.async_send_transaction(transaction)
|
||||
}
|
||||
@ -595,7 +603,7 @@ impl AsyncClient for ThinClient {
|
||||
keypair: &Keypair,
|
||||
instruction: Instruction,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
let message = Message::new(&[instruction]);
|
||||
self.async_send_message(&[keypair], message, recent_blockhash)
|
||||
}
|
||||
@ -605,7 +613,7 @@ impl AsyncClient for ThinClient {
|
||||
keypair: &Keypair,
|
||||
pubkey: &Pubkey,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> TransportResult<Signature> {
|
||||
let transfer_instruction =
|
||||
system_instruction::transfer(&keypair.pubkey(), pubkey, lamports);
|
||||
self.async_send_instruction(keypair, transfer_instruction, recent_blockhash)
|
||||
|
Reference in New Issue
Block a user