7
Cargo.lock
generated
7
Cargo.lock
generated
@ -2338,6 +2338,8 @@ dependencies = [
|
||||
"bincode 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-runtime 0.14.0",
|
||||
@ -2650,6 +2652,8 @@ dependencies = [
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2713,6 +2717,8 @@ version = "0.14.0"
|
||||
dependencies = [
|
||||
"bincode 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana-logger 0.14.0",
|
||||
@ -2787,6 +2793,7 @@ dependencies = [
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"solana 0.14.0",
|
||||
"solana-budget-api 0.14.0",
|
||||
|
50
client/src/client_error.rs
Normal file
50
client/src/client_error.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use crate::rpc_request;
|
||||
use solana_sdk::transaction::TransactionError;
|
||||
use std::{fmt, io};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ClientError {
|
||||
Io(io::Error),
|
||||
Reqwest(reqwest::Error),
|
||||
RpcError(rpc_request::RpcError),
|
||||
SerdeJson(serde_json::error::Error),
|
||||
TransactionError(TransactionError),
|
||||
}
|
||||
|
||||
impl fmt::Display for ClientError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "solana client error")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ClientError {}
|
||||
|
||||
impl From<io::Error> for ClientError {
|
||||
fn from(err: io::Error) -> ClientError {
|
||||
ClientError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for ClientError {
|
||||
fn from(err: reqwest::Error) -> ClientError {
|
||||
ClientError::Reqwest(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rpc_request::RpcError> for ClientError {
|
||||
fn from(err: rpc_request::RpcError) -> ClientError {
|
||||
ClientError::RpcError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::error::Error> for ClientError {
|
||||
fn from(err: serde_json::error::Error) -> ClientError {
|
||||
ClientError::SerdeJson(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for ClientError {
|
||||
fn from(err: TransactionError) -> ClientError {
|
||||
ClientError::TransactionError(err)
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
use crate::client_error::ClientError;
|
||||
use crate::rpc_request::RpcRequest;
|
||||
|
||||
pub(crate) trait GenericRpcClientRequest {
|
||||
@ -6,5 +7,5 @@ pub(crate) trait GenericRpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: Option<serde_json::Value>,
|
||||
retries: usize,
|
||||
) -> Result<serde_json::Value, Box<dyn std::error::Error>>;
|
||||
) -> Result<serde_json::Value, ClientError>;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod client_error;
|
||||
mod generic_rpc_client_request;
|
||||
pub mod mock_rpc_client_request;
|
||||
pub mod rpc_client;
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::client_error::ClientError;
|
||||
use crate::generic_rpc_client_request::GenericRpcClientRequest;
|
||||
use crate::rpc_request::RpcRequest;
|
||||
use serde_json::{Number, Value};
|
||||
@ -23,7 +24,7 @@ impl GenericRpcClientRequest for MockRpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: Option<serde_json::Value>,
|
||||
_retries: usize,
|
||||
) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
|
||||
) -> Result<serde_json::Value, ClientError> {
|
||||
if self.url == "fails" {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::client_error::ClientError;
|
||||
use crate::generic_rpc_client_request::GenericRpcClientRequest;
|
||||
use crate::mock_rpc_client_request::MockRpcClientRequest;
|
||||
use crate::rpc_client_request::RpcClientRequest;
|
||||
@ -46,10 +47,7 @@ impl RpcClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_transaction(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
) -> Result<String, Box<dyn error::Error>> {
|
||||
pub fn send_transaction(&self, transaction: &Transaction) -> Result<String, ClientError> {
|
||||
let serialized = serialize(transaction).unwrap();
|
||||
let params = json!([serialized]);
|
||||
let signature = self
|
||||
@ -67,7 +65,7 @@ impl RpcClient {
|
||||
pub fn get_signature_status(
|
||||
&self,
|
||||
signature: &str,
|
||||
) -> Result<Option<transaction::Result<()>>, Box<dyn error::Error>> {
|
||||
) -> Result<Option<transaction::Result<()>>, ClientError> {
|
||||
let params = json!([signature.to_string()]);
|
||||
let signature_status =
|
||||
self.client
|
||||
@ -81,7 +79,7 @@ impl RpcClient {
|
||||
&self,
|
||||
transaction: &mut Transaction,
|
||||
signer: &T,
|
||||
) -> Result<String, Box<dyn error::Error>> {
|
||||
) -> Result<String, ClientError> {
|
||||
let mut send_retries = 5;
|
||||
loop {
|
||||
let mut status_retries = 4;
|
||||
@ -117,6 +115,9 @@ impl RpcClient {
|
||||
send_retries - 1
|
||||
};
|
||||
if send_retries == 0 {
|
||||
if status.is_some() {
|
||||
status.unwrap()?
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Transaction {:?} failed: {:?}", signature_str, status),
|
||||
@ -124,6 +125,7 @@ impl RpcClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_and_confirm_transactions(
|
||||
&self,
|
||||
@ -201,7 +203,7 @@ impl RpcClient {
|
||||
&self,
|
||||
tx: &mut Transaction,
|
||||
signer_key: &T,
|
||||
) -> Result<(), Box<dyn error::Error>> {
|
||||
) -> Result<(), ClientError> {
|
||||
let blockhash = self.get_new_blockhash(&tx.message().recent_blockhash)?;
|
||||
tx.sign(&[signer_key], blockhash);
|
||||
Ok(())
|
||||
@ -482,7 +484,7 @@ impl RpcClient {
|
||||
)
|
||||
.map_err(|error| {
|
||||
debug!(
|
||||
"Response get_num_blocks_since_signature_confirmation: {}",
|
||||
"Response get_num_blocks_since_signature_confirmation: {:?}",
|
||||
error
|
||||
);
|
||||
io::Error::new(
|
||||
@ -526,7 +528,7 @@ impl RpcClient {
|
||||
request: &RpcRequest,
|
||||
params: Option<Value>,
|
||||
retries: usize,
|
||||
) -> Result<Value, Box<dyn error::Error>> {
|
||||
) -> Result<Value, ClientError> {
|
||||
self.client.send(request, params, retries)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::client_error::ClientError;
|
||||
use crate::generic_rpc_client_request::GenericRpcClientRequest;
|
||||
use crate::rpc_request::{RpcError, RpcRequest};
|
||||
use log::*;
|
||||
@ -36,7 +37,7 @@ impl GenericRpcClientRequest for RpcClientRequest {
|
||||
request: &RpcRequest,
|
||||
params: Option<serde_json::Value>,
|
||||
mut retries: usize,
|
||||
) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
|
||||
) -> Result<serde_json::Value, ClientError> {
|
||||
// Concurrent requests are not supported so reuse the same request id for all requests
|
||||
let request_id = 1;
|
||||
|
||||
|
@ -221,7 +221,7 @@ impl SyncClient for ThinClient {
|
||||
.map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("send_transaction failed with error {}", err),
|
||||
format!("send_transaction failed with error {:?}", err),
|
||||
)
|
||||
})?;
|
||||
Ok(status)
|
||||
|
@ -12,6 +12,8 @@ edition = "2018"
|
||||
bincode = "1.1.3"
|
||||
chrono = { version = "0.4.0", features = ["serde"] }
|
||||
log = "0.4.2"
|
||||
num-derive = "0.2"
|
||||
num-traits = "0.2"
|
||||
serde = "1.0.90"
|
||||
serde_derive = "1.0.90"
|
||||
solana-sdk = { path = "../../sdk", version = "0.14.0" }
|
||||
|
@ -1,14 +1,29 @@
|
||||
//! budget state
|
||||
use crate::budget_expr::BudgetExpr;
|
||||
use bincode::{self, deserialize, serialize_into};
|
||||
use num_derive::FromPrimitive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use solana_sdk::instruction::InstructionError;
|
||||
use solana_sdk::instruction_processor_utils::DecodeError;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, FromPrimitive)]
|
||||
pub enum BudgetError {
|
||||
DestinationMissing,
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for BudgetError {
|
||||
fn type_of(&self) -> &'static str {
|
||||
"BudgetError"
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BudgetError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "error")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for BudgetError {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
|
||||
pub struct BudgetState {
|
||||
pub initialized: bool,
|
||||
|
@ -11,6 +11,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
bincode = "1.1.3"
|
||||
log = "0.4.2"
|
||||
num-derive = "0.2"
|
||||
num-traits = "0.2"
|
||||
serde = "1.0.90"
|
||||
serde_derive = "1.0.90"
|
||||
solana-logger = { path = "../../logger", version = "0.14.0" }
|
||||
|
@ -1,15 +1,23 @@
|
||||
use log::*;
|
||||
use num_derive::FromPrimitive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use solana_sdk::account::KeyedAccount;
|
||||
use solana_sdk::instruction_processor_utils::DecodeError;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
#[derive(Serialize, Debug, PartialEq)]
|
||||
#[derive(Serialize, Debug, PartialEq, FromPrimitive)]
|
||||
pub enum TokenError {
|
||||
InvalidArgument,
|
||||
InsufficentFunds,
|
||||
NotOwner,
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for TokenError {
|
||||
fn type_of(&self) -> &'static str {
|
||||
"TokenError"
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TokenError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "error")
|
||||
|
@ -18,6 +18,8 @@ chrono = { version = "0.4.0", features = ["serde"] }
|
||||
generic-array = { version = "0.13.0", default-features = false, features = ["serde"] }
|
||||
itertools = "0.8.0"
|
||||
log = "0.4.2"
|
||||
num-derive = "0.2"
|
||||
num-traits = "0.2"
|
||||
rand = "0.6.5"
|
||||
rayon = "1.0.0"
|
||||
sha2 = "0.8.0"
|
||||
|
@ -2,6 +2,7 @@ use crate::account::{Account, KeyedAccount};
|
||||
use crate::instruction::InstructionError;
|
||||
use crate::pubkey::Pubkey;
|
||||
use bincode::ErrorKind;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
// All native programs export a symbol named process()
|
||||
pub const ENTRYPOINT: &str = "process";
|
||||
@ -64,3 +65,39 @@ where
|
||||
self.account.set_state(state)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait DecodeError<E> {
|
||||
fn decode_custom_error_to_enum(int: u32) -> Option<E>
|
||||
where
|
||||
E: FromPrimitive,
|
||||
{
|
||||
E::from_u32(int)
|
||||
}
|
||||
fn type_of(&self) -> &'static str;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use num_derive::FromPrimitive;
|
||||
|
||||
#[test]
|
||||
fn test_decode_custom_error_to_enum() {
|
||||
#[derive(Debug, FromPrimitive, PartialEq)]
|
||||
enum TestEnum {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
}
|
||||
impl<T> DecodeError<T> for TestEnum {
|
||||
fn type_of(&self) -> &'static str {
|
||||
"TestEnum"
|
||||
}
|
||||
}
|
||||
assert_eq!(TestEnum::decode_custom_error_to_enum(0), Some(TestEnum::A));
|
||||
assert_eq!(TestEnum::decode_custom_error_to_enum(1), Some(TestEnum::B));
|
||||
assert_eq!(TestEnum::decode_custom_error_to_enum(2), Some(TestEnum::C));
|
||||
let option: Option<TestEnum> = TestEnum::decode_custom_error_to_enum(3);
|
||||
assert_eq!(option, None);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,29 @@
|
||||
use crate::instruction::{AccountMeta, Instruction};
|
||||
use crate::instruction_processor_utils::DecodeError;
|
||||
use crate::pubkey::Pubkey;
|
||||
use crate::system_program;
|
||||
use num_derive::FromPrimitive;
|
||||
|
||||
#[derive(Serialize, Debug, Clone, PartialEq)]
|
||||
#[derive(Serialize, Debug, Clone, PartialEq, FromPrimitive)]
|
||||
pub enum SystemError {
|
||||
AccountAlreadyInUse,
|
||||
ResultWithNegativeLamports,
|
||||
SourceNotSystemAccount,
|
||||
}
|
||||
|
||||
impl<T> DecodeError<T> for SystemError {
|
||||
fn type_of(&self) -> &'static str {
|
||||
"SystemError"
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SystemError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "error")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for SystemError {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub enum SystemInstruction {
|
||||
/// Create a new account
|
||||
|
@ -15,6 +15,7 @@ clap = "2.33.0"
|
||||
chrono = { version = "0.4.0", features = ["serde"] }
|
||||
dirs = "1.0.5"
|
||||
log = "0.4.2"
|
||||
num-traits = "0.2"
|
||||
serde_json = "1.0.39"
|
||||
solana-budget-api = { path = "../programs/budget_api", version = "0.14.0" }
|
||||
solana-client = { path = "../client", version = "0.14.0" }
|
||||
|
@ -2,10 +2,13 @@ use bs58;
|
||||
use chrono::prelude::*;
|
||||
use clap::ArgMatches;
|
||||
use log::*;
|
||||
use num_traits::FromPrimitive;
|
||||
use serde_json;
|
||||
use serde_json::json;
|
||||
use solana_budget_api;
|
||||
use solana_budget_api::budget_instruction;
|
||||
use solana_budget_api::budget_state::BudgetError;
|
||||
use solana_client::client_error::ClientError;
|
||||
use solana_client::rpc_client::{get_rpc_request_str, RpcClient};
|
||||
#[cfg(not(test))]
|
||||
use solana_drone::drone::request_airdrop_transaction;
|
||||
@ -14,12 +17,15 @@ use solana_drone::drone::DRONE_PORT;
|
||||
use solana_drone::drone_mock::request_airdrop_transaction;
|
||||
use solana_sdk::bpf_loader;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::instruction::InstructionError;
|
||||
use solana_sdk::instruction_processor_utils::DecodeError;
|
||||
use solana_sdk::loader_instruction;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::rpc_port::DEFAULT_RPC_PORT;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||
use solana_sdk::system_instruction::SystemError;
|
||||
use solana_sdk::system_transaction;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use solana_sdk::transaction::{Transaction, TransactionError};
|
||||
use solana_vote_api::vote_instruction;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
@ -448,9 +454,8 @@ fn process_deploy(
|
||||
0,
|
||||
);
|
||||
trace!("Creating program account");
|
||||
rpc_client
|
||||
.send_and_confirm_transaction(&mut tx, &config.keypair)
|
||||
.map_err(|_| {
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
log_instruction_custom_error::<SystemError>(result).map_err(|_| {
|
||||
WalletError::DynamicProgramError("Program allocate space failed".to_string())
|
||||
})?;
|
||||
|
||||
@ -499,7 +504,8 @@ fn process_pay(
|
||||
|
||||
if timestamp == None && *witnesses == None {
|
||||
let mut tx = system_transaction::transfer(&config.keypair, to, lamports, blockhash, 0);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<SystemError>(result)?;
|
||||
Ok(signature_str.to_string())
|
||||
} else if *witnesses == None {
|
||||
let dt = timestamp.unwrap();
|
||||
@ -521,7 +527,8 @@ fn process_pay(
|
||||
lamports,
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||
|
||||
Ok(json!({
|
||||
"signature": signature_str,
|
||||
@ -551,7 +558,8 @@ fn process_pay(
|
||||
lamports,
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], ixs, blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||
|
||||
Ok(json!({
|
||||
"signature": signature_str,
|
||||
@ -571,7 +579,8 @@ fn process_cancel(rpc_client: &RpcClient, config: &WalletConfig, pubkey: &Pubkey
|
||||
&config.keypair.pubkey(),
|
||||
);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
|
||||
@ -598,7 +607,8 @@ fn process_time_elapsed(
|
||||
|
||||
let ix = budget_instruction::apply_timestamp(&config.keypair.pubkey(), pubkey, to, dt);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
@ -619,7 +629,8 @@ fn process_witness(
|
||||
let blockhash = rpc_client.get_recent_blockhash()?;
|
||||
let ix = budget_instruction::apply_signature(&config.keypair.pubkey(), pubkey, to);
|
||||
let mut tx = Transaction::new_signed_instructions(&[&config.keypair], vec![ix], blockhash);
|
||||
let signature_str = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &config.keypair);
|
||||
let signature_str = log_instruction_custom_error::<BudgetError>(result)?;
|
||||
|
||||
Ok(signature_str.to_string())
|
||||
}
|
||||
@ -766,10 +777,39 @@ pub fn request_and_confirm_airdrop(
|
||||
let blockhash = rpc_client.get_recent_blockhash()?;
|
||||
let keypair = DroneKeypair::new_keypair(drone_addr, to_pubkey, lamports, blockhash)?;
|
||||
let mut tx = keypair.airdrop_transaction();
|
||||
rpc_client.send_and_confirm_transaction(&mut tx, &keypair)?;
|
||||
let result = rpc_client.send_and_confirm_transaction(&mut tx, &keypair);
|
||||
log_instruction_custom_error::<SystemError>(result)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_instruction_custom_error<E>(result: Result<String, ClientError>) -> ProcessResult
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||
{
|
||||
if result.is_err() {
|
||||
let err = result.unwrap_err();
|
||||
if let ClientError::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::CustomError(code),
|
||||
)) = err
|
||||
{
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(code) {
|
||||
error!(
|
||||
"{:?}: {}::{:?}",
|
||||
err,
|
||||
specific_error.type_of(),
|
||||
specific_error
|
||||
);
|
||||
Err(specific_error)?
|
||||
}
|
||||
}
|
||||
error!("{:?}", err);
|
||||
Err(err)?
|
||||
} else {
|
||||
Ok(result.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
Reference in New Issue
Block a user