|
|
@@ -7,7 +7,7 @@ use {
|
|
|
solana_message::v0::LoadedAddresses,
|
|
|
solana_serde::default_on_eof,
|
|
|
solana_transaction_context::TransactionReturnData,
|
|
|
- solana_transaction_error::TransactionResult as Result,
|
|
|
+ solana_transaction_error::{TransactionError, TransactionResult as Result},
|
|
|
solana_transaction_status::{
|
|
|
InnerInstructions, Reward, RewardType, TransactionStatusMeta, TransactionTokenBalance,
|
|
|
},
|
|
|
@@ -109,6 +109,22 @@ impl From<UiTokenAmount> for StoredTokenAmount {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+struct StoredTransactionError(Vec<u8>);
|
|
|
+
|
|
|
+impl From<StoredTransactionError> for TransactionError {
|
|
|
+ fn from(value: StoredTransactionError) -> Self {
|
|
|
+ let bytes = value.0;
|
|
|
+ bincode::deserialize(&bytes).expect("transaction error to deserialize from bytes")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl From<TransactionError> for StoredTransactionError {
|
|
|
+ fn from(value: TransactionError) -> Self {
|
|
|
+ let bytes = bincode::serialize(&value).expect("transaction error to serialize to bytes");
|
|
|
+ StoredTransactionError(bytes)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
pub struct StoredTransactionTokenBalance {
|
|
|
pub account_index: u8,
|
|
|
@@ -265,3 +281,104 @@ impl TryFrom<TransactionStatusMeta> for StoredTransactionStatusMeta {
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+#[cfg(test)]
|
|
|
+mod tests {
|
|
|
+ use {
|
|
|
+ crate::StoredTransactionError, solana_instruction::error::InstructionError,
|
|
|
+ solana_transaction_error::TransactionError, test_case::test_case,
|
|
|
+ };
|
|
|
+
|
|
|
+ #[test_case(TransactionError::InsufficientFundsForFee; "Named variant error")]
|
|
|
+ #[test_case(TransactionError::InsufficientFundsForRent { account_index: 42 }; "Struct variant error")]
|
|
|
+ #[test_case(TransactionError::DuplicateInstruction(42); "Single-value tuple variant error")]
|
|
|
+ #[test_case(TransactionError::InstructionError(42, InstructionError::Custom(0xdeadbeef)); "`InstructionError`")]
|
|
|
+ fn test_serialize_transaction_error_to_stored_transaction_error_round_trip(
|
|
|
+ err: TransactionError,
|
|
|
+ ) {
|
|
|
+ let serialized: StoredTransactionError = err.clone().into();
|
|
|
+ let deserialized: TransactionError = serialized.into();
|
|
|
+ assert_eq!(deserialized, err);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test_case(
|
|
|
+ vec![4, 0, 0, 0, /* Fourth enum variant - `InsufficientFundsForFee` */],
|
|
|
+ TransactionError::InsufficientFundsForFee;
|
|
|
+ "Named variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 31, 0, 0, 0, /* Thirty-first enum variant - `InsufficientFundsForRent` */
|
|
|
+ 42, /* Account index */
|
|
|
+ ],
|
|
|
+ TransactionError::InsufficientFundsForRent { account_index: 42 };
|
|
|
+ "Struct variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 30, 0, 0, 0, /* Thirtieth enum variant - `DuplicateInstruction` */
|
|
|
+ 42, /* Instruction index */
|
|
|
+ ],
|
|
|
+ TransactionError::DuplicateInstruction(42);
|
|
|
+ "Single-value tuple variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 8, 0, 0, 0, /* Eighth enum variant - `InstructionError` */
|
|
|
+ 42, /* Outer instruction index */
|
|
|
+ 25, 0, 0, 0, /* InstructionError::Custom */
|
|
|
+ /* 0xdeadbeef */
|
|
|
+ 239, 190, 173, 222,
|
|
|
+ ],
|
|
|
+ TransactionError::InstructionError(42, InstructionError::Custom(0xdeadbeef));
|
|
|
+ "`InstructionError`"
|
|
|
+ )]
|
|
|
+ fn test_deserialize_stored_transaction_error(
|
|
|
+ stored_bytes: Vec<u8>,
|
|
|
+ expected_transaction_error: TransactionError,
|
|
|
+ ) {
|
|
|
+ let stored_transaction = StoredTransactionError(stored_bytes);
|
|
|
+ let deserialized: TransactionError = stored_transaction.into();
|
|
|
+ assert_eq!(deserialized, expected_transaction_error);
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test_case(
|
|
|
+ vec![4, 0, 0, 0, /* Fourth enum variant - `InsufficientFundsForFee` */],
|
|
|
+ TransactionError::InsufficientFundsForFee;
|
|
|
+ "Named variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 31, 0, 0, 0, /* Thirty-first enum variant - `InsufficientFundsForRent` */
|
|
|
+ 42, /* Account index */
|
|
|
+ ],
|
|
|
+ TransactionError::InsufficientFundsForRent { account_index: 42 };
|
|
|
+ "Struct variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 30, 0, 0, 0, /* Thirtieth enum variant - `DuplicateInstruction` */
|
|
|
+ 42, /* Instruction index */
|
|
|
+ ],
|
|
|
+ TransactionError::DuplicateInstruction(42);
|
|
|
+ "Single-value tuple variant error"
|
|
|
+ )]
|
|
|
+ #[test_case(
|
|
|
+ vec![
|
|
|
+ 8, 0, 0, 0, /* Eighth enum variant - `InstructionError` */
|
|
|
+ 42, /* Outer instruction index */
|
|
|
+ 25, 0, 0, 0, /* InstructionError::Custom */
|
|
|
+ /* 0xdeadbeef */
|
|
|
+ 239, 190, 173, 222,
|
|
|
+ ],
|
|
|
+ TransactionError::InstructionError(42, InstructionError::Custom(0xdeadbeef));
|
|
|
+ "`InstructionError`"
|
|
|
+ )]
|
|
|
+ fn test_seserialize_stored_transaction_error(
|
|
|
+ expected_serialized_bytes: Vec<u8>,
|
|
|
+ transaction_error: TransactionError,
|
|
|
+ ) {
|
|
|
+ let StoredTransactionError(serialized_bytes) = transaction_error.into();
|
|
|
+ assert_eq!(serialized_bytes, expected_serialized_bytes);
|
|
|
+ }
|
|
|
+}
|