Cleanup - merge_nonce_error_into_system_error (#31773)

* merge_nonce_error_into_system_error

* more cleanup

---------

Co-authored-by: Trent Nelson <trent@solana.com>
This commit is contained in:
Alexander Meißner 2023-05-24 18:05:07 +02:00 committed by GitHub
parent 4d19f1d019
commit 691b12c693
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 400 deletions

View File

@ -2,11 +2,10 @@ use {
crate::{
checks::{check_account_for_fee_with_commitment, check_unique_pubkeys},
cli::{
log_instruction_custom_error, log_instruction_custom_error_ex, CliCommand,
CliCommandInfo, CliConfig, CliError, ProcessResult,
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
ProcessResult,
},
compute_unit_price::WithComputeUnitPrice,
feature::get_feature_is_active,
memo::WithMemo,
spend_utils::{resolve_spend_tx_and_check_account_balance, SpendAmount},
},
@ -25,19 +24,17 @@ use {
solana_rpc_client_nonce_utils::*,
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, instruction_to_nonce_error, upgrade_nonce_account,
withdraw_nonce_account, NonceError, SystemError,
create_nonce_account_with_seed, upgrade_nonce_account, withdraw_nonce_account,
SystemError,
},
system_program,
transaction::{Transaction, TransactionError},
transaction::Transaction,
},
std::sync::Arc,
};
@ -427,21 +424,9 @@ 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);
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
}
})
}
log_instruction_custom_error::<SystemError>(result, config)
}
pub fn process_create_nonce_account(
@ -524,40 +509,9 @@ pub fn process_create_nonce_account(
let mut tx = Transaction::new_unsigned(message);
tx.try_sign(&config.signers, latest_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);
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),
}
log_instruction_custom_error::<SystemError>(result, config)
}
pub fn process_get_nonce(
@ -611,21 +565,9 @@ 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);
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
}
})
}
log_instruction_custom_error::<SystemError>(result, config)
}
pub fn process_show_nonce_account(
@ -688,21 +630,9 @@ 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);
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
}
})
}
log_instruction_custom_error::<SystemError>(result, config)
}
pub(crate) fn process_upgrade_nonce_account(
@ -725,20 +655,8 @@ pub(crate) fn process_upgrade_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);
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
}
})
}
log_instruction_custom_error::<SystemError>(result, config)
}
#[cfg(test)]

View File

@ -1,7 +1,6 @@
use {
solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
solana_sdk::{
feature_set,
instruction::{checked_add, InstructionError},
nonce::{
self,
@ -9,7 +8,7 @@ use {
State,
},
pubkey::Pubkey,
system_instruction::{nonce_to_instruction_error, NonceError},
system_instruction::SystemError,
sysvar::rent::Rent,
transaction_context::{
BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
@ -23,10 +22,6 @@ pub fn advance_nonce_account(
signers: &HashSet<Pubkey>,
invoke_context: &InvokeContext,
) -> Result<(), InstructionError> {
let merge_nonce_error_into_system_error = invoke_context
.feature_set
.is_active(&feature_set::merge_nonce_error_into_system_error::id());
if !account.is_writable() {
ic_msg!(
invoke_context,
@ -53,10 +48,7 @@ pub fn advance_nonce_account(
invoke_context,
"Advance nonce account: nonce can only advance once per slot"
);
return Err(nonce_to_instruction_error(
NonceError::NotExpired,
merge_nonce_error_into_system_error,
));
return Err(SystemError::NonceBlockhashNotExpired.into());
}
let new_data = nonce::state::Data::new(
@ -72,10 +64,7 @@ pub fn advance_nonce_account(
"Advance nonce account: Account {} state is invalid",
account.get_key()
);
Err(nonce_to_instruction_error(
NonceError::BadAccountState,
merge_nonce_error_into_system_error,
))
Err(InstructionError::InvalidAccountData)
}
}
}
@ -92,10 +81,6 @@ pub fn withdraw_nonce_account(
) -> Result<(), InstructionError> {
let mut from = instruction_context
.try_borrow_instruction_account(transaction_context, from_account_index)?;
let merge_nonce_error_into_system_error = invoke_context
.feature_set
.is_active(&feature_set::merge_nonce_error_into_system_error::id());
if !from.is_writable() {
ic_msg!(
invoke_context,
@ -127,10 +112,7 @@ pub fn withdraw_nonce_account(
invoke_context,
"Withdraw nonce account: nonce can only advance once per slot"
);
return Err(nonce_to_instruction_error(
NonceError::NotExpired,
merge_nonce_error_into_system_error,
));
return Err(SystemError::NonceBlockhashNotExpired.into());
}
from.set_state(&Versions::new(State::Uninitialized))?;
} else {
@ -174,10 +156,6 @@ pub fn initialize_nonce_account(
rent: &Rent,
invoke_context: &InvokeContext,
) -> Result<(), InstructionError> {
let merge_nonce_error_into_system_error = invoke_context
.feature_set
.is_active(&feature_set::merge_nonce_error_into_system_error::id());
if !account.is_writable() {
ic_msg!(
invoke_context,
@ -214,10 +192,7 @@ pub fn initialize_nonce_account(
"Initialize nonce account: Account {} state is invalid",
account.get_key()
);
Err(nonce_to_instruction_error(
NonceError::BadAccountState,
merge_nonce_error_into_system_error,
))
Err(InstructionError::InvalidAccountData)
}
}
}
@ -228,10 +203,6 @@ pub fn authorize_nonce_account(
signers: &HashSet<Pubkey>,
invoke_context: &InvokeContext,
) -> Result<(), InstructionError> {
let merge_nonce_error_into_system_error = invoke_context
.feature_set
.is_active(&feature_set::merge_nonce_error_into_system_error::id());
if !account.is_writable() {
ic_msg!(
invoke_context,
@ -251,10 +222,7 @@ pub fn authorize_nonce_account(
"Authorize nonce account: Account {} state is invalid",
account.get_key()
);
Err(nonce_to_instruction_error(
NonceError::BadAccountState,
merge_nonce_error_into_system_error,
))
Err(InstructionError::InvalidAccountData)
}
Err(AuthorizeNonceError::MissingRequiredSignature(account_authority)) => {
ic_msg!(
@ -278,7 +246,6 @@ mod test {
hash::hash,
nonce::{self, State},
nonce_account::{create_account, verify_nonce_account},
system_instruction::SystemError,
system_program,
transaction_context::InstructionAccount,
},

View File

@ -14,9 +14,7 @@ use {
nonce,
program_utils::limited_deserialize,
pubkey::Pubkey,
system_instruction::{
NonceError, SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH,
},
system_instruction::{SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH},
system_program,
transaction_context::{
BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
@ -435,7 +433,7 @@ declare_process_instruction!(process_instruction, 150, |invoke_context| {
invoke_context,
"Advance nonce account: recent blockhash list is empty",
);
return Err(NonceError::NoRecentBlockhashes.into());
return Err(SystemError::NonceNoRecentBlockhashes.into());
}
advance_nonce_account(&mut me, &signers, invoke_context)
}
@ -474,7 +472,7 @@ declare_process_instruction!(process_instruction, 150, |invoke_context| {
invoke_context,
"Initialize nonce account: recent blockhash list is empty",
);
return Err(NonceError::NoRecentBlockhashes.into());
return Err(SystemError::NonceNoRecentBlockhashes.into());
}
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
@ -1884,7 +1882,7 @@ mod tests {
is_writable: false,
},
],
Err(NonceError::NoRecentBlockhashes.into()),
Err(SystemError::NonceNoRecentBlockhashes.into()),
);
}
@ -1945,7 +1943,7 @@ mod tests {
is_writable: false,
},
],
Err(NonceError::NoRecentBlockhashes.into()),
Err(SystemError::NonceNoRecentBlockhashes.into()),
super::process_instruction,
|invoke_context: &mut InvokeContext| {
invoke_context.blockhash = hash(&serialize(&0).unwrap());

View File

@ -43,7 +43,7 @@
use {
crate::{
decode_error::DecodeError,
instruction::{AccountMeta, Instruction, InstructionError},
instruction::{AccountMeta, Instruction},
nonce,
pubkey::Pubkey,
system_program,
@ -81,101 +81,6 @@ impl<T> DecodeError<T> for SystemError {
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum NonceError {
#[error("recent blockhash list is empty")]
NoRecentBlockhashes,
#[error("stored nonce is still in recent_blockhashes")]
NotExpired,
#[error("specified nonce does not match stored nonce")]
UnexpectedValue,
#[error("cannot handle request in current account state")]
BadAccountState,
}
impl<E> DecodeError<E> for NonceError {
fn type_of() -> &'static str {
"NonceError"
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
enum NonceErrorAdapter {
#[error("recent blockhash list is empty")]
NoRecentBlockhashes,
#[error("stored nonce is still in recent_blockhashes")]
NotExpired,
#[error("specified nonce does not match stored nonce")]
UnexpectedValue,
#[error("cannot handle request in current account state")]
BadAccountState,
}
impl<E> DecodeError<E> for NonceErrorAdapter {
fn type_of() -> &'static str {
"NonceErrorAdapter"
}
}
impl From<NonceErrorAdapter> for NonceError {
fn from(e: NonceErrorAdapter) -> Self {
match e {
NonceErrorAdapter::NoRecentBlockhashes => NonceError::NoRecentBlockhashes,
NonceErrorAdapter::NotExpired => NonceError::NotExpired,
NonceErrorAdapter::UnexpectedValue => NonceError::UnexpectedValue,
NonceErrorAdapter::BadAccountState => NonceError::BadAccountState,
}
}
}
pub fn nonce_to_instruction_error(error: NonceError, use_system_variant: bool) -> InstructionError {
if use_system_variant {
match error {
NonceError::NoRecentBlockhashes => SystemError::NonceNoRecentBlockhashes.into(),
NonceError::NotExpired => SystemError::NonceBlockhashNotExpired.into(),
NonceError::UnexpectedValue => SystemError::NonceUnexpectedBlockhashValue.into(),
NonceError::BadAccountState => InstructionError::InvalidAccountData,
}
} else {
match error {
NonceError::NoRecentBlockhashes => NonceErrorAdapter::NoRecentBlockhashes.into(),
NonceError::NotExpired => NonceErrorAdapter::NotExpired.into(),
NonceError::UnexpectedValue => NonceErrorAdapter::UnexpectedValue.into(),
NonceError::BadAccountState => NonceErrorAdapter::BadAccountState.into(),
}
}
}
pub fn instruction_to_nonce_error(
error: &InstructionError,
use_system_variant: bool,
) -> Option<NonceError> {
if use_system_variant {
match error {
InstructionError::Custom(discriminant) => {
match SystemError::decode_custom_error_to_enum(*discriminant) {
Some(SystemError::NonceNoRecentBlockhashes) => {
Some(NonceError::NoRecentBlockhashes)
}
Some(SystemError::NonceBlockhashNotExpired) => Some(NonceError::NotExpired),
Some(SystemError::NonceUnexpectedBlockhashValue) => {
Some(NonceError::UnexpectedValue)
}
_ => None,
}
}
InstructionError::InvalidAccountData => Some(NonceError::BadAccountState),
_ => None,
}
} else if let InstructionError::Custom(discriminant) = error {
let maybe: Option<NonceErrorAdapter> =
NonceErrorAdapter::decode_custom_error_to_enum(*discriminant);
maybe.map(NonceError::from)
} else {
None
}
}
/// Maximum permitted size of account data (10 MiB).
pub const MAX_PERMITTED_DATA_LENGTH: u64 = 10 * 1024 * 1024;
@ -1867,11 +1772,7 @@ pub fn upgrade_nonce_account(nonce_pubkey: Pubkey) -> Instruction {
#[cfg(test)]
mod tests {
use {
super::*,
crate::instruction::{Instruction, InstructionError},
num_traits::ToPrimitive,
};
use {super::*, crate::instruction::Instruction};
fn get_keys(instruction: &Instruction) -> Vec<Pubkey> {
instruction.accounts.iter().map(|x| x.pubkey).collect()
@ -1903,165 +1804,4 @@ mod tests {
assert!(pubkeys.contains(&from_pubkey));
assert!(pubkeys.contains(&nonce_pubkey));
}
#[test]
fn test_nonce_error_decode() {
use num_traits::FromPrimitive;
fn pretty_err<T>(err: InstructionError) -> String
where
T: 'static + std::error::Error + DecodeError<T> + FromPrimitive,
{
if let InstructionError::Custom(code) = err {
let specific_error: T = T::decode_custom_error_to_enum(code).unwrap();
format!(
"{:?}: {}::{:?} - {}",
err,
T::type_of(),
specific_error,
specific_error,
)
} else {
"".to_string()
}
}
assert_eq!(
"Custom(0): NonceError::NoRecentBlockhashes - recent blockhash list is empty",
pretty_err::<NonceError>(NonceError::NoRecentBlockhashes.into())
);
assert_eq!(
"Custom(1): NonceError::NotExpired - stored nonce is still in recent_blockhashes",
pretty_err::<NonceError>(NonceError::NotExpired.into())
);
assert_eq!(
"Custom(2): NonceError::UnexpectedValue - specified nonce does not match stored nonce",
pretty_err::<NonceError>(NonceError::UnexpectedValue.into())
);
assert_eq!(
"Custom(3): NonceError::BadAccountState - cannot handle request in current account state",
pretty_err::<NonceError>(NonceError::BadAccountState.into())
);
}
#[test]
fn test_nonce_to_instruction_error() {
assert_eq!(
nonce_to_instruction_error(NonceError::NoRecentBlockhashes, false),
NonceError::NoRecentBlockhashes.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::NotExpired, false),
NonceError::NotExpired.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::UnexpectedValue, false),
NonceError::UnexpectedValue.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::BadAccountState, false),
NonceError::BadAccountState.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::NoRecentBlockhashes, true),
SystemError::NonceNoRecentBlockhashes.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::NotExpired, true),
SystemError::NonceBlockhashNotExpired.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::UnexpectedValue, true),
SystemError::NonceUnexpectedBlockhashValue.into(),
);
assert_eq!(
nonce_to_instruction_error(NonceError::BadAccountState, true),
InstructionError::InvalidAccountData,
);
}
#[test]
fn test_instruction_to_nonce_error() {
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(NonceErrorAdapter::NoRecentBlockhashes.to_u32().unwrap(),),
false,
),
Some(NonceError::NoRecentBlockhashes),
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(NonceErrorAdapter::NotExpired.to_u32().unwrap(),),
false,
),
Some(NonceError::NotExpired),
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(NonceErrorAdapter::UnexpectedValue.to_u32().unwrap(),),
false,
),
Some(NonceError::UnexpectedValue),
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(NonceErrorAdapter::BadAccountState.to_u32().unwrap(),),
false,
),
Some(NonceError::BadAccountState),
);
assert_eq!(
instruction_to_nonce_error(&InstructionError::Custom(u32::MAX), false),
None,
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(SystemError::NonceNoRecentBlockhashes.to_u32().unwrap(),),
true,
),
Some(NonceError::NoRecentBlockhashes),
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(SystemError::NonceBlockhashNotExpired.to_u32().unwrap(),),
true,
),
Some(NonceError::NotExpired),
);
assert_eq!(
instruction_to_nonce_error(
&InstructionError::Custom(
SystemError::NonceUnexpectedBlockhashValue.to_u32().unwrap(),
),
true,
),
Some(NonceError::UnexpectedValue),
);
assert_eq!(
instruction_to_nonce_error(&InstructionError::InvalidAccountData, true),
Some(NonceError::BadAccountState),
);
assert_eq!(
instruction_to_nonce_error(&InstructionError::Custom(u32::MAX), true),
None,
);
}
#[test]
fn test_nonce_error_adapter_compat() {
assert_eq!(
NonceError::NoRecentBlockhashes.to_u32(),
NonceErrorAdapter::NoRecentBlockhashes.to_u32(),
);
assert_eq!(
NonceError::NotExpired.to_u32(),
NonceErrorAdapter::NotExpired.to_u32(),
);
assert_eq!(
NonceError::UnexpectedValue.to_u32(),
NonceErrorAdapter::UnexpectedValue.to_u32(),
);
assert_eq!(
NonceError::BadAccountState.to_u32(),
NonceErrorAdapter::BadAccountState.to_u32(),
);
}
}