parent
4bbf09f582
commit
fbf2dd1672
|
@ -3792,6 +3792,7 @@ dependencies = [
|
|||
"rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-remote-wallet 1.1.0",
|
||||
"solana-sdk 1.1.0",
|
||||
"thiserror 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tiny-bip39 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
|
@ -612,6 +612,7 @@ impl Archiver {
|
|||
ErrorKind::Other,
|
||||
"setup_mining_account: signature not found",
|
||||
),
|
||||
TransportError::Custom(e) => io::Error::new(ErrorKind::Other, e),
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -13,6 +13,7 @@ clap = "2.33.0"
|
|||
rpassword = "4.0"
|
||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.1.0" }
|
||||
solana-sdk = { path = "../sdk", version = "1.1.0" }
|
||||
thiserror = "1.0.11"
|
||||
tiny-bip39 = "0.7.0"
|
||||
url = "2.1.0"
|
||||
chrono = "0.4"
|
||||
|
|
|
@ -12,7 +12,7 @@ use std::str::FromStr;
|
|||
pub fn is_pubkey(string: String) -> Result<(), String> {
|
||||
match string.parse::<Pubkey>() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ pub fn is_pubkey(string: String) -> Result<(), String> {
|
|||
pub fn is_hash(string: String) -> Result<(), String> {
|
||||
match string.parse::<Hash>() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ pub fn is_hash(string: String) -> Result<(), String> {
|
|||
pub fn is_keypair(string: String) -> Result<(), String> {
|
||||
read_keypair_file(&string)
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{:?}", err))
|
||||
.map_err(|err| format!("{}", err))
|
||||
}
|
||||
|
||||
// Return an error if a keypair file cannot be parsed
|
||||
|
@ -38,7 +38,7 @@ pub fn is_keypair_or_ask_keyword(string: String) -> Result<(), String> {
|
|||
}
|
||||
read_keypair_file(&string)
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{:?}", err))
|
||||
.map_err(|err| format!("{}", err))
|
||||
}
|
||||
|
||||
// Return an error if string cannot be parsed as pubkey string or keypair file location
|
||||
|
@ -73,10 +73,10 @@ pub fn is_pubkey_sig(string: String) -> Result<(), String> {
|
|||
.ok_or_else(|| "Malformed signer string".to_string())?,
|
||||
) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,20 +90,20 @@ pub fn is_url(string: String) -> Result<(), String> {
|
|||
Err("no host provided".to_string())
|
||||
}
|
||||
}
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
Err(err) => Err(format!("{}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_slot(slot: String) -> Result<(), String> {
|
||||
slot.parse::<Slot>()
|
||||
.map(|_| ())
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
.map_err(|e| format!("{}", e))
|
||||
}
|
||||
|
||||
pub fn is_port(port: String) -> Result<(), String> {
|
||||
port.parse::<u16>()
|
||||
.map(|_| ())
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
.map_err(|e| format!("{}", e))
|
||||
}
|
||||
|
||||
pub fn is_valid_percentage(percentage: String) -> Result<(), String> {
|
||||
|
@ -111,7 +111,7 @@ pub fn is_valid_percentage(percentage: String) -> Result<(), String> {
|
|||
.parse::<u8>()
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"Unable to parse input percentage, provided: {}, err: {:?}",
|
||||
"Unable to parse input percentage, provided: {}, err: {}",
|
||||
percentage, e
|
||||
)
|
||||
})
|
||||
|
@ -141,7 +141,7 @@ pub fn is_amount(amount: String) -> Result<(), String> {
|
|||
pub fn is_rfc3339_datetime(value: String) -> Result<(), String> {
|
||||
DateTime::parse_from_rfc3339(&value)
|
||||
.map(|_| ())
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
.map_err(|e| format!("{}", e))
|
||||
}
|
||||
|
||||
pub fn is_derivation(value: String) -> Result<(), String> {
|
||||
|
@ -152,7 +152,7 @@ pub fn is_derivation(value: String) -> Result<(), String> {
|
|||
.parse::<u32>()
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"Unable to parse derivation, provided: {}, err: {:?}",
|
||||
"Unable to parse derivation, provided: {}, err: {}",
|
||||
account, e
|
||||
)
|
||||
})
|
||||
|
@ -160,7 +160,7 @@ pub fn is_derivation(value: String) -> Result<(), String> {
|
|||
if let Some(change) = parts.next() {
|
||||
change.parse::<u32>().map_err(|e| {
|
||||
format!(
|
||||
"Unable to parse derivation, provided: {}, err: {:?}",
|
||||
"Unable to parse derivation, provided: {}, err: {}",
|
||||
change, e
|
||||
)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{input_parsers::pubkeys_sigs_of, offline::SIGNER_ARG, ArgConstant};
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
use clap::{ArgMatches, Error, ErrorKind};
|
||||
use clap::ArgMatches;
|
||||
use rpassword::prompt_password_stderr;
|
||||
use solana_remote_wallet::{
|
||||
remote_keypair::generate_remote_keypair,
|
||||
|
@ -72,9 +72,9 @@ pub fn signer_from_path(
|
|||
)?))
|
||||
}
|
||||
KeypairUrl::Filepath(path) => match read_keypair_file(&path) {
|
||||
Err(e) => Err(Error::with_description(
|
||||
&format!("Couldn't find keypair file: {:?} error: {:?}", path, e),
|
||||
ErrorKind::InvalidValue,
|
||||
Err(e) => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("could not find keypair file: {} error: {}", path, e),
|
||||
)
|
||||
.into()),
|
||||
Ok(file) => Ok(Box::new(file)),
|
||||
|
@ -102,9 +102,9 @@ pub fn signer_from_path(
|
|||
if let Some(presigner) = presigner {
|
||||
Ok(Box::new(presigner))
|
||||
} else {
|
||||
Err(Error::with_description(
|
||||
"Missing signature for supplied pubkey",
|
||||
ErrorKind::MissingRequiredArgument,
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"missing signature for supplied pubkey".to_string(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use thiserror::Error;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! version {
|
||||
() => {
|
||||
|
@ -23,6 +25,23 @@ pub struct ArgConstant<'a> {
|
|||
pub help: &'a str,
|
||||
}
|
||||
|
||||
/// Error type for forwarding Errors out of `main()` of a `clap` app
|
||||
/// and still using the `Display` formatter
|
||||
#[derive(Error)]
|
||||
#[error("{0}")]
|
||||
pub struct DisplayError(Box<dyn std::error::Error>);
|
||||
impl DisplayError {
|
||||
pub fn new_as_boxed(inner: Box<dyn std::error::Error>) -> Box<Self> {
|
||||
DisplayError(inner).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for DisplayError {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(fmt, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod input_parsers;
|
||||
pub mod input_validators;
|
||||
pub mod keypair;
|
||||
|
|
|
@ -18,7 +18,10 @@ use solana_clap_utils::{
|
|||
input_parsers::*, input_validators::*, keypair::signer_from_path, offline::SIGN_ONLY_ARG,
|
||||
ArgConstant,
|
||||
};
|
||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||
use solana_client::{
|
||||
client_error::{ClientErrorKind, Result as ClientResult},
|
||||
rpc_client::RpcClient,
|
||||
};
|
||||
#[cfg(not(test))]
|
||||
use solana_faucet::faucet::request_airdrop_transaction;
|
||||
#[cfg(test)]
|
||||
|
@ -47,14 +50,15 @@ use solana_stake_program::{
|
|||
use solana_storage_program::storage_instruction::StorageAccountType;
|
||||
use solana_vote_program::vote_state::VoteAuthorize;
|
||||
use std::{
|
||||
error,
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
net::{IpAddr, SocketAddr},
|
||||
sync::Arc,
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
{error, fmt},
|
||||
};
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
pub type CliSigners = Vec<Box<dyn Signer>>;
|
||||
|
@ -409,46 +413,34 @@ pub struct CliCommandInfo {
|
|||
pub signers: CliSigners,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
pub enum CliError {
|
||||
#[error("bad parameter: {0}")]
|
||||
BadParameter(String),
|
||||
#[error("command not recognized: {0}")]
|
||||
CommandNotRecognized(String),
|
||||
#[error("insuficient funds for fee")]
|
||||
InsufficientFundsForFee,
|
||||
#[error(transparent)]
|
||||
InvalidNonce(CliNonceError),
|
||||
#[error("dynamic program error: {0}")]
|
||||
DynamicProgramError(String),
|
||||
#[error("rpc request error: {0}")]
|
||||
RpcRequestError(String),
|
||||
#[error("keypair file not found: {0}")]
|
||||
KeypairFileNotFound(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for CliError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "invalid")
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CliError {
|
||||
fn description(&self) -> &str {
|
||||
"invalid"
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn error::Error> {
|
||||
// Generic error, underlying cause isn't tracked.
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<dyn error::Error>> for CliError {
|
||||
fn from(error: Box<dyn error::Error>) -> Self {
|
||||
CliError::DynamicProgramError(format!("{:?}", error))
|
||||
CliError::DynamicProgramError(error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CliNonceError> for CliError {
|
||||
fn from(error: CliNonceError) -> Self {
|
||||
match error {
|
||||
CliNonceError::Client(client_error) => {
|
||||
Self::RpcRequestError(format!("{:?}", client_error))
|
||||
}
|
||||
CliNonceError::Client(client_error) => Self::RpcRequestError(client_error),
|
||||
_ => Self::InvalidNonce(error),
|
||||
}
|
||||
}
|
||||
|
@ -721,7 +713,7 @@ pub fn parse_command(
|
|||
.parse()
|
||||
.or_else(|err| {
|
||||
Err(CliError::BadParameter(format!(
|
||||
"Invalid faucet port: {:?}",
|
||||
"Invalid faucet port: {}",
|
||||
err
|
||||
)))
|
||||
})?;
|
||||
|
@ -729,7 +721,7 @@ pub fn parse_command(
|
|||
let faucet_host = if let Some(faucet_host) = matches.value_of("faucet_host") {
|
||||
Some(solana_net_utils::parse_host(faucet_host).or_else(|err| {
|
||||
Err(CliError::BadParameter(format!(
|
||||
"Invalid faucet host: {:?}",
|
||||
"Invalid faucet host: {}",
|
||||
err
|
||||
)))
|
||||
})?)
|
||||
|
@ -1141,13 +1133,13 @@ fn process_confirm(rpc_client: &RpcClient, signature: &Signature) -> ProcessResu
|
|||
if let Some(result) = status {
|
||||
match result {
|
||||
Ok(_) => Ok("Confirmed".to_string()),
|
||||
Err(err) => Ok(format!("Transaction failed with error {:?}", err)),
|
||||
Err(err) => Ok(format!("Transaction failed with error: {}", err)),
|
||||
}
|
||||
} else {
|
||||
Ok("Not found".to_string())
|
||||
}
|
||||
}
|
||||
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {:?}", err)).into()),
|
||||
Err(err) => Err(CliError::RpcRequestError(format!("Unable to confirm: {}", err)).into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2118,18 +2110,18 @@ pub fn request_and_confirm_airdrop(
|
|||
log_instruction_custom_error::<SystemError>(result)
|
||||
}
|
||||
|
||||
pub fn log_instruction_custom_error<E>(result: Result<String, ClientError>) -> ProcessResult
|
||||
pub fn log_instruction_custom_error<E>(result: ClientResult<String>) -> ProcessResult
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||
{
|
||||
match result {
|
||||
Err(err) => {
|
||||
if let ClientError::TransactionError(TransactionError::InstructionError(
|
||||
if let ClientErrorKind::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::CustomError(code),
|
||||
)) = err
|
||||
)) = err.kind()
|
||||
{
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(code) {
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(*code) {
|
||||
error!("{}::{:?}", E::type_of(), specific_error);
|
||||
eprintln!(
|
||||
"Program Error ({}::{:?}): {}",
|
||||
|
@ -3332,7 +3324,7 @@ mod tests {
|
|||
assert_eq!(
|
||||
process_command(&config).unwrap(),
|
||||
format!(
|
||||
"Transaction failed with error {:?}",
|
||||
"Transaction failed with error: {}",
|
||||
TransactionError::AccountInUse
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1011,7 +1011,7 @@ pub fn process_live_slots(url: &str) -> ProcessResult {
|
|||
current = Some(new_info);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("disconnected: {:?}", err);
|
||||
eprintln!("disconnected: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use clap::{crate_description, crate_name, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||
use console::style;
|
||||
|
||||
use solana_clap_utils::{input_validators::is_url, keypair::SKIP_SEED_PHRASE_VALIDATION_ARG};
|
||||
use solana_clap_utils::{
|
||||
input_validators::is_url, keypair::SKIP_SEED_PHRASE_VALIDATION_ARG, DisplayError,
|
||||
};
|
||||
use solana_cli::{
|
||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners},
|
||||
display::{println_name_value, println_name_value_or},
|
||||
|
@ -230,6 +232,10 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
)
|
||||
.get_matches();
|
||||
|
||||
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
|
||||
}
|
||||
|
||||
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
||||
if parse_settings(&matches)? {
|
||||
let wallet_manager = maybe_wallet_manager()?;
|
||||
|
||||
|
@ -237,6 +243,6 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
||||
let result = process_command(&config)?;
|
||||
println!("{}", result);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -238,7 +238,7 @@ pub fn get_account(
|
|||
) -> Result<Account, CliNonceError> {
|
||||
rpc_client
|
||||
.get_account(nonce_pubkey)
|
||||
.map_err(|e| CliNonceError::Client(format!("{:?}", e)))
|
||||
.map_err(|e| CliNonceError::Client(format!("{}", e)))
|
||||
.and_then(|a| match account_identity_ok(&a) {
|
||||
Ok(()) => Ok(a),
|
||||
Err(e) => Err(e),
|
||||
|
|
|
@ -1300,7 +1300,7 @@ pub fn process_show_stake_account(
|
|||
Ok("".to_string())
|
||||
}
|
||||
Err(err) => Err(CliError::RpcRequestError(format!(
|
||||
"Account data could not be deserialized to stake state: {:?}",
|
||||
"Account data could not be deserialized to stake state: {}",
|
||||
err
|
||||
))
|
||||
.into()),
|
||||
|
@ -1396,11 +1396,11 @@ pub fn process_delegate_stake(
|
|||
}
|
||||
};
|
||||
|
||||
if sanity_check_result.is_err() {
|
||||
if let Err(err) = &sanity_check_result {
|
||||
if !force {
|
||||
sanity_check_result?;
|
||||
} else {
|
||||
println!("--force supplied, ignoring: {:?}", sanity_check_result);
|
||||
println!("--force supplied, ignoring: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -266,7 +266,7 @@ pub fn process_show_storage_account(
|
|||
|
||||
use solana_storage_program::storage_contract::StorageContract;
|
||||
let storage_contract: StorageContract = account.state().map_err(|err| {
|
||||
CliError::RpcRequestError(format!("Unable to deserialize storage account: {:?}", err))
|
||||
CliError::RpcRequestError(format!("Unable to deserialize storage account: {}", err))
|
||||
})?;
|
||||
println!("{:#?}", storage_contract);
|
||||
println!("Account Lamports: {}", account.lamports);
|
||||
|
|
|
@ -274,7 +274,7 @@ pub fn process_set_validator_info(
|
|||
println!("--force supplied, ignoring: {:?}", result);
|
||||
} else {
|
||||
result.map_err(|err| {
|
||||
CliError::BadParameter(format!("Invalid validator keybase username: {:?}", err))
|
||||
CliError::BadParameter(format!("Invalid validator keybase username: {}", err))
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -11,6 +11,7 @@ use solana_clap_utils::{
|
|||
keypair_from_seed_phrase, prompt_passphrase, signer_from_path,
|
||||
SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||
},
|
||||
DisplayError,
|
||||
};
|
||||
use solana_cli_config::{Config, CONFIG_FILE};
|
||||
use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager};
|
||||
|
@ -378,6 +379,11 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
|
||||
}
|
||||
|
||||
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
||||
let config = if let Some(config_file) = matches.value_of("config_file") {
|
||||
Config::load(config_file).unwrap_or_default()
|
||||
} else {
|
||||
|
|
|
@ -262,7 +262,7 @@ pub fn kill_entry_and_spend_and_verify_rest(
|
|||
);
|
||||
match sig {
|
||||
Err(e) => {
|
||||
result = Err(TransportError::IoError(e));
|
||||
result = Err(e);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use solana_sdk::{
|
|||
signature::{Keypair, Signer},
|
||||
system_transaction,
|
||||
transaction::Transaction,
|
||||
transport::Result as TransportResult,
|
||||
};
|
||||
use solana_stake_program::{
|
||||
config as stake_config, stake_instruction,
|
||||
|
@ -607,7 +608,7 @@ impl LocalCluster {
|
|||
storage_keypair: &Keypair,
|
||||
from_keypair: &Arc<Keypair>,
|
||||
archiver: bool,
|
||||
) -> Result<()> {
|
||||
) -> TransportResult<()> {
|
||||
let storage_account_type = if archiver {
|
||||
StorageAccountType::Archiver
|
||||
} else {
|
||||
|
|
|
@ -36,7 +36,7 @@ impl Client for BankClient {
|
|||
}
|
||||
|
||||
impl AsyncClient for BankClient {
|
||||
fn async_send_transaction(&self, transaction: Transaction) -> io::Result<Signature> {
|
||||
fn async_send_transaction(&self, transaction: Transaction) -> Result<Signature> {
|
||||
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
|
||||
let transaction_sender = self.transaction_sender.lock().unwrap();
|
||||
transaction_sender.send(transaction).unwrap();
|
||||
|
@ -48,7 +48,7 @@ impl AsyncClient for BankClient {
|
|||
keypairs: &T,
|
||||
message: Message,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> Result<Signature> {
|
||||
let transaction = Transaction::new(keypairs, message, recent_blockhash);
|
||||
self.async_send_transaction(transaction)
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ impl AsyncClient for BankClient {
|
|||
keypair: &Keypair,
|
||||
instruction: Instruction,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> Result<Signature> {
|
||||
let message = Message::new(&[instruction]);
|
||||
self.async_send_message(&[keypair], message, recent_blockhash)
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ impl AsyncClient for BankClient {
|
|||
keypair: &Keypair,
|
||||
pubkey: &Pubkey,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature> {
|
||||
) -> Result<Signature> {
|
||||
let transfer_instruction =
|
||||
system_instruction::transfer(&keypair.pubkey(), pubkey, lamports);
|
||||
self.async_send_instruction(keypair, transfer_instruction, recent_blockhash)
|
||||
|
|
|
@ -21,7 +21,6 @@ use crate::{
|
|||
transaction,
|
||||
transport::Result,
|
||||
};
|
||||
use std::io;
|
||||
|
||||
pub trait Client: SyncClient + AsyncClient {
|
||||
fn tpu_addr(&self) -> String;
|
||||
|
@ -122,10 +121,7 @@ pub trait SyncClient {
|
|||
|
||||
pub trait AsyncClient {
|
||||
/// Send a signed transaction, but don't wait to see if the server accepted it.
|
||||
fn async_send_transaction(
|
||||
&self,
|
||||
transaction: transaction::Transaction,
|
||||
) -> io::Result<Signature>;
|
||||
fn async_send_transaction(&self, transaction: transaction::Transaction) -> Result<Signature>;
|
||||
|
||||
/// Create a transaction from the given message, and send it to the
|
||||
/// server, but don't wait for to see if the server accepted it.
|
||||
|
@ -134,7 +130,7 @@ pub trait AsyncClient {
|
|||
keypairs: &T,
|
||||
message: Message,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature>;
|
||||
) -> Result<Signature>;
|
||||
|
||||
/// Create a transaction from a single instruction that only requires
|
||||
/// a single signer. Then send it to the server, but don't wait for a reply.
|
||||
|
@ -143,7 +139,7 @@ pub trait AsyncClient {
|
|||
keypair: &Keypair,
|
||||
instruction: Instruction,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature>;
|
||||
) -> Result<Signature>;
|
||||
|
||||
/// Attempt to transfer lamports from `keypair` to `pubkey`, but don't wait to confirm.
|
||||
fn async_transfer(
|
||||
|
@ -152,5 +148,5 @@ pub trait AsyncClient {
|
|||
keypair: &Keypair,
|
||||
pubkey: &Pubkey,
|
||||
recent_blockhash: Hash,
|
||||
) -> io::Result<Signature>;
|
||||
) -> Result<Signature>;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{convert::TryFrom, fmt, mem, str::FromStr};
|
||||
use thiserror::Error;
|
||||
|
||||
pub const HASH_BYTES: usize = 32;
|
||||
#[derive(Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
|
@ -47,9 +48,11 @@ impl fmt::Display for Hash {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum ParseHashError {
|
||||
#[error("string decoded to wrong size for hash")]
|
||||
WrongSize,
|
||||
#[error("failed to decoded string to hash")]
|
||||
Invalid,
|
||||
}
|
||||
|
||||
|
|
|
@ -3,96 +3,124 @@
|
|||
use crate::{pubkey::Pubkey, short_vec, system_instruction::SystemError};
|
||||
use bincode::serialize;
|
||||
use serde::Serialize;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Reasons the runtime might have rejected an instruction.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Error, PartialEq, Eq, Clone)]
|
||||
pub enum InstructionError {
|
||||
/// Deprecated! Use CustomError instead!
|
||||
/// The program instruction returned an error
|
||||
#[error("generic instruction error")]
|
||||
GenericError,
|
||||
|
||||
/// The arguments provided to a program instruction where invalid
|
||||
/// The arguments provided to a program were invalid
|
||||
#[error("invalid program argument")]
|
||||
InvalidArgument,
|
||||
|
||||
/// An instruction's data contents was invalid
|
||||
/// An instruction's data contents were invalid
|
||||
#[error("invalid instruction data")]
|
||||
InvalidInstructionData,
|
||||
|
||||
/// An account's data contents was invalid
|
||||
#[error("invalid account data for instruction")]
|
||||
InvalidAccountData,
|
||||
|
||||
/// An account's data was too small
|
||||
#[error("account data too small for instruction")]
|
||||
AccountDataTooSmall,
|
||||
|
||||
/// An account's balance was too small to complete the instruction
|
||||
#[error("insufficient funds for instruction")]
|
||||
InsufficientFunds,
|
||||
|
||||
/// The account did not have the expected program id
|
||||
#[error("incorrect program id for instruction")]
|
||||
IncorrectProgramId,
|
||||
|
||||
/// A signature was required but not found
|
||||
#[error("missing required signature for instruction")]
|
||||
MissingRequiredSignature,
|
||||
|
||||
/// An initialize instruction was sent to an account that has already been initialized.
|
||||
#[error("instruction requires an uninitialized account")]
|
||||
AccountAlreadyInitialized,
|
||||
|
||||
/// An attempt to operate on an account that hasn't been initialized.
|
||||
#[error("instruction requires an initialized account")]
|
||||
UninitializedAccount,
|
||||
|
||||
/// Program's instruction lamport balance does not equal the balance after the instruction
|
||||
#[error("sum of account balances before and after instruction do not match")]
|
||||
UnbalancedInstruction,
|
||||
|
||||
/// Program modified an account's program id
|
||||
#[error("instruction modified the program id of an account")]
|
||||
ModifiedProgramId,
|
||||
|
||||
/// Program spent the lamports of an account that doesn't belong to it
|
||||
#[error("instruction spent from the balance of an account it does not own")]
|
||||
ExternalAccountLamportSpend,
|
||||
|
||||
/// Program modified the data of an account that doesn't belong to it
|
||||
#[error("instruction modified data of an account it does not own")]
|
||||
ExternalAccountDataModified,
|
||||
|
||||
/// Read-only account modified lamports
|
||||
#[error("instruction changed balance of a read-only account")]
|
||||
ReadonlyLamportChange,
|
||||
|
||||
/// Read-only account modified data
|
||||
#[error("instruction modified data of a read-only account")]
|
||||
ReadonlyDataModified,
|
||||
|
||||
/// An account was referenced more than once in a single instruction
|
||||
// Deprecated, instructions can now contain duplicate accounts
|
||||
#[error("instruction contains duplicate accounts")]
|
||||
DuplicateAccountIndex,
|
||||
|
||||
/// Executable bit on account changed, but shouldn't have
|
||||
#[error("instruction changed executable bit of an account")]
|
||||
ExecutableModified,
|
||||
|
||||
/// Rent_epoch account changed, but shouldn't have
|
||||
#[error("instruction modified rent epoch of an account")]
|
||||
RentEpochModified,
|
||||
|
||||
/// The instruction expected additional account keys
|
||||
#[error("insufficient account key count for instruction")]
|
||||
NotEnoughAccountKeys,
|
||||
|
||||
/// A non-system program changed the size of the account data
|
||||
#[error("non-system instruction changed account size")]
|
||||
AccountDataSizeChanged,
|
||||
|
||||
/// The instruction expected an executable account
|
||||
#[error("instruction expected an executable account")]
|
||||
AccountNotExecutable,
|
||||
|
||||
/// Failed to borrow a reference to account data, already borrowed
|
||||
#[error("instruction tries to borrow reference for an account which is already borrowed")]
|
||||
AccountBorrowFailed,
|
||||
|
||||
/// Account data has an outstanding reference after a program's execution
|
||||
#[error("instruction left account with an outstanding reference borrowed")]
|
||||
AccountBorrowOutstanding,
|
||||
|
||||
/// The same account was multiply passed to an on-chain program's entrypoint, but the program
|
||||
/// modified them differently. A program can only modify one instance of the account because
|
||||
/// the runtime cannot determine which changes to pick or how to merge them if both are modified
|
||||
#[error("instruction modifications of multiply-passed account differ")]
|
||||
DuplicateAccountOutOfSync,
|
||||
|
||||
/// Allows on-chain programs to implement program-specific error types and see them returned
|
||||
/// by the Solana runtime. A program-specific error may be any type that is represented as
|
||||
/// or serialized to a u32 integer.
|
||||
#[error("program error: {0}")]
|
||||
CustomError(u32),
|
||||
|
||||
/// The return value from the program was invalid. Valid errors are either a defined builtin
|
||||
/// error value or a user-defined error in the lower 32 bits.
|
||||
#[error("program returned invalid error code")]
|
||||
InvalidError,
|
||||
}
|
||||
|
||||
|
|
|
@ -107,9 +107,11 @@ impl Into<[u8; 64]> for Signature {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum ParseSignatureError {
|
||||
#[error("string decoded to wrong size for signature")]
|
||||
WrongSize,
|
||||
#[error("failed to decode string to signature")]
|
||||
Invalid,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
use crate::transaction::TransactionError;
|
||||
use std::{error, fmt, io};
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TransportError {
|
||||
IoError(io::Error),
|
||||
TransactionError(TransactionError),
|
||||
}
|
||||
|
||||
impl error::Error for TransportError {}
|
||||
impl fmt::Display for TransportError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TransportError::IoError(err) => write!(formatter, "{:?}", err),
|
||||
TransportError::TransactionError(err) => write!(formatter, "{:?}", err),
|
||||
}
|
||||
}
|
||||
#[error("transport io error: {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
#[error("transport transaction error: {0}")]
|
||||
TransactionError(#[from] TransactionError),
|
||||
#[error("transport custom error: {0}")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl TransportError {
|
||||
|
@ -27,16 +22,4 @@ impl TransportError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for TransportError {
|
||||
fn from(err: io::Error) -> TransportError {
|
||||
TransportError::IoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for TransportError {
|
||||
fn from(err: TransactionError) -> TransportError {
|
||||
TransportError::TransactionError(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, TransportError>;
|
||||
|
|
|
@ -9,10 +9,12 @@ use solana_clap_utils::{
|
|||
input_parsers::pubkeys_of,
|
||||
input_validators::{is_pubkey_or_keypair, is_url},
|
||||
};
|
||||
use solana_client::{rpc_client::RpcClient, rpc_response::RpcVoteAccountStatus};
|
||||
use solana_client::{
|
||||
client_error::Result as ClientResult, rpc_client::RpcClient, rpc_response::RpcVoteAccountStatus,
|
||||
};
|
||||
use solana_metrics::{datapoint_error, datapoint_info};
|
||||
use solana_sdk::{hash::Hash, native_token::lamports_to_sol, pubkey::Pubkey};
|
||||
use std::{error, io, str::FromStr, thread::sleep, time::Duration};
|
||||
use std::{error, str::FromStr, thread::sleep, time::Duration};
|
||||
|
||||
struct Config {
|
||||
interval: Duration,
|
||||
|
@ -115,7 +117,7 @@ fn get_config() -> Config {
|
|||
config
|
||||
}
|
||||
|
||||
fn get_cluster_info(rpc_client: &RpcClient) -> io::Result<(u64, Hash, RpcVoteAccountStatus)> {
|
||||
fn get_cluster_info(rpc_client: &RpcClient) -> ClientResult<(u64, Hash, RpcVoteAccountStatus)> {
|
||||
let transaction_count = rpc_client.get_transaction_count()?;
|
||||
let recent_blockhash = rpc_client.get_recent_blockhash()?.0;
|
||||
let vote_accounts = rpc_client.get_vote_accounts()?;
|
||||
|
|
Loading…
Reference in New Issue