nonce: Unify NonceError
with SystemError
This commit is contained in:
@ -12,12 +12,10 @@ use solana_cli_output::{
|
||||
};
|
||||
use solana_client::{
|
||||
blockhash_query::BlockhashQuery,
|
||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||
client_error::{ClientError, Result as ClientResult},
|
||||
nonce_utils,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig, RpcTransactionLogsFilter},
|
||||
rpc_request::{RpcError, RpcResponseErrorData},
|
||||
rpc_response::RpcSimulateTransactionResult,
|
||||
};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
@ -1536,43 +1534,41 @@ pub fn request_and_confirm_airdrop(
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
fn common_error_adapter<E>(ix_error: &InstructionError) -> Option<E>
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||
{
|
||||
if let InstructionError::Custom(code) = ix_error {
|
||||
E::decode_custom_error_to_enum(*code)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log_instruction_custom_error<E>(
|
||||
result: ClientResult<Signature>,
|
||||
config: &CliConfig,
|
||||
) -> ProcessResult
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||
{
|
||||
log_instruction_custom_error_ex::<E, _>(result, config, common_error_adapter)
|
||||
}
|
||||
|
||||
pub fn log_instruction_custom_error_ex<E, F>(
|
||||
result: ClientResult<Signature>,
|
||||
config: &CliConfig,
|
||||
error_adapter: F,
|
||||
) -> ProcessResult
|
||||
where
|
||||
E: 'static + std::error::Error + DecodeError<E> + FromPrimitive,
|
||||
F: Fn(&InstructionError) -> Option<E>,
|
||||
{
|
||||
match result {
|
||||
Err(err) => {
|
||||
// If transaction simulation returns a known Custom InstructionError, decode it
|
||||
if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
|
||||
data:
|
||||
RpcResponseErrorData::SendTransactionPreflightFailure(
|
||||
RpcSimulateTransactionResult {
|
||||
err:
|
||||
Some(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(code),
|
||||
)),
|
||||
..
|
||||
},
|
||||
),
|
||||
..
|
||||
}) = err.kind()
|
||||
{
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(*code) {
|
||||
return Err(specific_error.into());
|
||||
}
|
||||
}
|
||||
// If the transaction was instead submitted and returned a known Custom
|
||||
// InstructionError, decode it
|
||||
if let ClientErrorKind::TransactionError(TransactionError::InstructionError(
|
||||
_,
|
||||
InstructionError::Custom(code),
|
||||
)) = err.kind()
|
||||
{
|
||||
if let Some(specific_error) = E::decode_custom_error_to_enum(*code) {
|
||||
let maybe_tx_err = err.get_transaction_error();
|
||||
if let Some(TransactionError::InstructionError(_, ix_error)) = maybe_tx_err {
|
||||
if let Some(specific_error) = error_adapter(&ix_error) {
|
||||
return Err(specific_error.into());
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use solana_cli_output::{QuietDisplay, VerboseDisplay};
|
||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
clock::Slot,
|
||||
feature::{self, Feature},
|
||||
feature_set::FEATURE_NAMES,
|
||||
@ -312,6 +313,31 @@ fn feature_activation_allowed(rpc_client: &RpcClient, quiet: bool) -> Result<boo
|
||||
Ok(feature_activation_allowed)
|
||||
}
|
||||
|
||||
fn status_from_account(account: Account) -> Option<CliFeatureStatus> {
|
||||
feature::from_account(&account).map(|feature| match feature.activated_at {
|
||||
None => CliFeatureStatus::Pending,
|
||||
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_feature_status(
|
||||
rpc_client: &RpcClient,
|
||||
feature_id: &Pubkey,
|
||||
) -> Result<Option<CliFeatureStatus>, Box<dyn std::error::Error>> {
|
||||
rpc_client
|
||||
.get_account(feature_id)
|
||||
.map(status_from_account)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn get_feature_is_active(
|
||||
rpc_client: &RpcClient,
|
||||
feature_id: &Pubkey,
|
||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
get_feature_status(rpc_client, feature_id)
|
||||
.map(|status| matches!(status, Some(CliFeatureStatus::Active(_))))
|
||||
}
|
||||
|
||||
fn process_status(
|
||||
rpc_client: &RpcClient,
|
||||
config: &CliConfig,
|
||||
@ -327,11 +353,7 @@ fn process_status(
|
||||
let feature_id = &feature_ids[i];
|
||||
let feature_name = FEATURE_NAMES.get(feature_id).unwrap();
|
||||
if let Some(account) = account {
|
||||
if let Some(feature) = feature::from_account(&account) {
|
||||
let feature_status = match feature.activated_at {
|
||||
None => CliFeatureStatus::Pending,
|
||||
Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
|
||||
};
|
||||
if let Some(feature_status) = status_from_account(account) {
|
||||
features.push(CliFeature {
|
||||
id: feature_id.to_string(),
|
||||
description: feature_name.to_string(),
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
|
||||
cli::{
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult,
|
||||
log_instruction_custom_error, log_instruction_custom_error_ex, CliCommand, CliCommandInfo,
|
||||
CliConfig, CliError, ProcessResult,
|
||||
},
|
||||
feature::get_feature_is_active,
|
||||
memo::WithMemo,
|
||||
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
|
||||
};
|
||||
@ -20,16 +21,19 @@ use solana_client::{nonce_utils::*, rpc_client::RpcClient};
|
||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
feature_set::merge_nonce_error_into_system_error,
|
||||
hash::Hash,
|
||||
instruction::InstructionError,
|
||||
message::Message,
|
||||
nonce::{self, State},
|
||||
pubkey::Pubkey,
|
||||
system_instruction::{
|
||||
advance_nonce_account, authorize_nonce_account, create_nonce_account,
|
||||
create_nonce_account_with_seed, withdraw_nonce_account, NonceError, SystemError,
|
||||
create_nonce_account_with_seed, instruction_to_nonce_error, withdraw_nonce_account,
|
||||
NonceError, SystemError,
|
||||
},
|
||||
system_program,
|
||||
transaction::Transaction,
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -367,8 +371,21 @@ pub fn process_authorize_nonce_account(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let merge_errors =
|
||||
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<NonceError>(result, config)
|
||||
|
||||
if merge_errors {
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
} else {
|
||||
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
|
||||
if let InstructionError::Custom(_) = ix_error {
|
||||
instruction_to_nonce_error(ix_error, merge_errors)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_create_nonce_account(
|
||||
@ -452,8 +469,40 @@ pub fn process_create_nonce_account(
|
||||
|
||||
let mut tx = Transaction::new_unsigned(message);
|
||||
tx.try_sign(&config.signers, recent_blockhash)?;
|
||||
let merge_errors =
|
||||
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
|
||||
let err_ix_index = if let Err(err) = &result {
|
||||
err.get_transaction_error().and_then(|tx_err| {
|
||||
if let TransactionError::InstructionError(ix_index, _) = tx_err {
|
||||
Some(ix_index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match err_ix_index {
|
||||
// SystemInstruction::InitializeNonceAccount failed
|
||||
Some(1) => {
|
||||
if merge_errors {
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
} else {
|
||||
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
|
||||
if let InstructionError::Custom(_) = ix_error {
|
||||
instruction_to_nonce_error(ix_error, merge_errors)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// SystemInstruction::CreateAccount{,WithSeed} failed
|
||||
_ => log_instruction_custom_error::<SystemError>(result, config),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_get_nonce(
|
||||
@ -506,8 +555,21 @@ pub fn process_new_nonce(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let merge_errors =
|
||||
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
|
||||
if merge_errors {
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
} else {
|
||||
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
|
||||
if let InstructionError::Custom(_) = ix_error {
|
||||
instruction_to_nonce_error(ix_error, merge_errors)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_show_nonce_account(
|
||||
@ -569,8 +631,21 @@ pub fn process_withdraw_from_nonce_account(
|
||||
&tx.message,
|
||||
config.commitment,
|
||||
)?;
|
||||
let merge_errors =
|
||||
get_feature_is_active(rpc_client, &merge_nonce_error_into_system_error::id())?;
|
||||
let result = rpc_client.send_and_confirm_transaction_with_spinner(&tx);
|
||||
log_instruction_custom_error::<NonceError>(result, config)
|
||||
|
||||
if merge_errors {
|
||||
log_instruction_custom_error::<SystemError>(result, config)
|
||||
} else {
|
||||
log_instruction_custom_error_ex::<NonceError, _>(result, config, |ix_error| {
|
||||
if let InstructionError::Custom(_) = ix_error {
|
||||
instruction_to_nonce_error(ix_error, merge_errors)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Reference in New Issue
Block a user