Add block_time to getConfirmedSignaturesForAddress2 and getConfirmedTransaction (#14572)
* add block_time to get_confirmed_signatures_for_address2 and protobuf implementation for tx_by_addr * add tests for convert * update cargo lock * run cargo format after rebase * introduce legacy TransactionByAddrInfo * move LegacyTransactionByAddrInfo back to storage-bigtable
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5017,6 +5017,7 @@ name = "solana-storage-proto"
|
||||
version = "1.6.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bs58",
|
||||
"prost",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::client_error;
|
||||
use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount};
|
||||
use solana_sdk::{
|
||||
clock::{Epoch, Slot},
|
||||
clock::{Epoch, Slot, UnixTimestamp},
|
||||
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
||||
inflation::Inflation,
|
||||
transaction::{Result, TransactionError},
|
||||
@ -286,6 +286,7 @@ pub struct RpcConfirmedTransactionStatusWithSignature {
|
||||
pub slot: Slot,
|
||||
pub err: Option<TransactionError>,
|
||||
pub memo: Option<String>,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -304,12 +305,14 @@ impl From<ConfirmedTransactionStatusWithSignature> for RpcConfirmedTransactionSt
|
||||
slot,
|
||||
err,
|
||||
memo,
|
||||
block_time,
|
||||
} = value;
|
||||
Self {
|
||||
signature: signature.to_string(),
|
||||
slot,
|
||||
err,
|
||||
memo,
|
||||
block_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2023,12 +2023,14 @@ impl Blockstore {
|
||||
let transaction = self
|
||||
.find_transaction_in_slot(slot, signature)?
|
||||
.ok_or(BlockstoreError::TransactionStatusSlotMismatch)?; // Should not happen
|
||||
let block_time = self.get_block_time(slot)?;
|
||||
Ok(Some(ConfirmedTransaction {
|
||||
slot,
|
||||
transaction: TransactionWithStatusMeta {
|
||||
transaction,
|
||||
meta: Some(status),
|
||||
},
|
||||
block_time,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
@ -2323,11 +2325,13 @@ impl Blockstore {
|
||||
None => None,
|
||||
Some((_slot, status)) => status.status.err(),
|
||||
};
|
||||
let block_time = self.get_block_time(slot)?;
|
||||
infos.push(ConfirmedTransactionStatusWithSignature {
|
||||
signature,
|
||||
slot,
|
||||
err,
|
||||
memo: None,
|
||||
block_time,
|
||||
});
|
||||
}
|
||||
get_status_info_timer.stop();
|
||||
@ -6590,7 +6594,11 @@ pub mod tests {
|
||||
let signature = transaction.transaction.signatures[0];
|
||||
assert_eq!(
|
||||
blockstore.get_confirmed_transaction(signature).unwrap(),
|
||||
Some(ConfirmedTransaction { slot, transaction })
|
||||
Some(ConfirmedTransaction {
|
||||
slot,
|
||||
transaction,
|
||||
block_time: None
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,10 @@ use solana_sdk::{
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use solana_storage_proto::convert::generated;
|
||||
use solana_storage_proto::convert::tx_by_addr;
|
||||
use solana_transaction_status::{
|
||||
ConfirmedBlock, ConfirmedTransaction, ConfirmedTransactionStatusWithSignature, Reward,
|
||||
TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta,
|
||||
TransactionByAddrInfo, TransactionConfirmationStatus, TransactionStatus, TransactionStatusMeta,
|
||||
TransactionWithStatusMeta,
|
||||
};
|
||||
use std::{collections::HashMap, convert::TryInto};
|
||||
@ -263,14 +264,31 @@ impl From<TransactionInfo> for TransactionStatus {
|
||||
}
|
||||
}
|
||||
|
||||
// A serialized `Vec<TransactionByAddrInfo>` is stored in the `tx-by-addr` table. The row keys are
|
||||
// the one's compliment of the slot so that rows may be listed in reverse order
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TransactionByAddrInfo {
|
||||
signature: Signature, // The transaction signature
|
||||
err: Option<TransactionError>, // None if the transaction executed successfully
|
||||
index: u32, // Where the transaction is located in the block
|
||||
memo: Option<String>, // Transaction memo
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
struct LegacyTransactionByAddrInfo {
|
||||
pub signature: Signature, // The transaction signature
|
||||
pub err: Option<TransactionError>, // None if the transaction executed successfully
|
||||
pub index: u32, // Where the transaction is located in the block
|
||||
pub memo: Option<String>, // Transaction memo
|
||||
}
|
||||
|
||||
impl From<LegacyTransactionByAddrInfo> for TransactionByAddrInfo {
|
||||
fn from(legacy: LegacyTransactionByAddrInfo) -> Self {
|
||||
let LegacyTransactionByAddrInfo {
|
||||
signature,
|
||||
err,
|
||||
index,
|
||||
memo,
|
||||
} = legacy;
|
||||
|
||||
Self {
|
||||
signature,
|
||||
err,
|
||||
index,
|
||||
memo,
|
||||
block_time: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -363,6 +381,7 @@ impl LedgerStorage {
|
||||
Ok(Some(ConfirmedTransaction {
|
||||
slot,
|
||||
transaction: bucket_block_transaction,
|
||||
block_time: block.block_time,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@ -417,12 +436,17 @@ impl LedgerStorage {
|
||||
let mut infos = vec![];
|
||||
|
||||
let starting_slot_tx_len = bigtable
|
||||
.get_bincode_cell::<Vec<TransactionByAddrInfo>>(
|
||||
.get_protobuf_or_bincode_cell::<Vec<LegacyTransactionByAddrInfo>, tx_by_addr::TransactionByAddr>(
|
||||
"tx-by-addr",
|
||||
format!("{}{}", address_prefix, slot_to_key(!first_slot)),
|
||||
)
|
||||
.await
|
||||
.map(|txs| txs.len())
|
||||
.map(|cell_data| {
|
||||
match cell_data {
|
||||
bigtable::CellData::Bincode(tx_by_addr) => tx_by_addr.len(),
|
||||
bigtable::CellData::Protobuf(tx_by_addr) => tx_by_addr.tx_by_addrs.len(),
|
||||
}
|
||||
})
|
||||
.unwrap_or(0);
|
||||
|
||||
// Return the next tx-by-addr data of amount `limit` plus extra to account for the largest
|
||||
@ -443,8 +467,27 @@ impl LedgerStorage {
|
||||
row_key
|
||||
))
|
||||
})?;
|
||||
let mut cell_data: Vec<TransactionByAddrInfo> =
|
||||
bigtable::deserialize_bincode_cell_data(&data, "tx-by-addr", row_key)?;
|
||||
|
||||
let deserialized_cell_data = bigtable::deserialize_protobuf_or_bincode_cell_data::<
|
||||
Vec<LegacyTransactionByAddrInfo>,
|
||||
tx_by_addr::TransactionByAddr,
|
||||
>(&data, "tx-by-addr", row_key.clone())?;
|
||||
|
||||
let mut cell_data: Vec<TransactionByAddrInfo> = match deserialized_cell_data {
|
||||
bigtable::CellData::Bincode(tx_by_addr) => {
|
||||
tx_by_addr.into_iter().map(|legacy| legacy.into()).collect()
|
||||
}
|
||||
bigtable::CellData::Protobuf(tx_by_addr) => {
|
||||
tx_by_addr.try_into().map_err(|error| {
|
||||
bigtable::Error::ObjectCorrupt(format!(
|
||||
"Failed to deserialize: {}: tx-by-addr/{}",
|
||||
error,
|
||||
row_key.clone()
|
||||
))
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
cell_data.reverse();
|
||||
for tx_by_addr_info in cell_data.into_iter() {
|
||||
// Filter out records before `before_transaction_index`
|
||||
@ -461,6 +504,7 @@ impl LedgerStorage {
|
||||
slot,
|
||||
err: tx_by_addr_info.err,
|
||||
memo: tx_by_addr_info.memo,
|
||||
block_time: tx_by_addr_info.block_time,
|
||||
},
|
||||
tx_by_addr_info.index,
|
||||
));
|
||||
@ -500,6 +544,7 @@ impl LedgerStorage {
|
||||
err: err.clone(),
|
||||
index,
|
||||
memo: None, // TODO
|
||||
block_time: confirmed_block.block_time,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -520,7 +565,12 @@ impl LedgerStorage {
|
||||
.map(|(address, transaction_info_by_addr)| {
|
||||
(
|
||||
format!("{}/{}", address, slot_to_key(!slot)),
|
||||
transaction_info_by_addr,
|
||||
tx_by_addr::TransactionByAddr {
|
||||
tx_by_addrs: transaction_info_by_addr
|
||||
.into_iter()
|
||||
.map(|by_addr| by_addr.into())
|
||||
.collect(),
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
@ -535,7 +585,7 @@ impl LedgerStorage {
|
||||
if !tx_by_addr_cells.is_empty() {
|
||||
bytes_written += self
|
||||
.connection
|
||||
.put_bincode_cells_with_retry::<Vec<TransactionByAddrInfo>>(
|
||||
.put_protobuf_cells_with_retry::<tx_by_addr::TransactionByAddr>(
|
||||
"tx-by-addr",
|
||||
&tx_by_addr_cells,
|
||||
)
|
||||
|
@ -10,6 +10,7 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.2.1"
|
||||
bs58 = "0.3.1"
|
||||
prost = "0.6.1"
|
||||
serde = "1.0.112"
|
||||
serde_derive = "1.0.103"
|
||||
|
@ -12,5 +12,11 @@ fn main() -> Result<(), std::io::Error> {
|
||||
.build_server(false)
|
||||
.format(true)
|
||||
.out_dir(&out_dir)
|
||||
.compile(&[proto_files.join("confirmed_block.proto")], &[proto_files])
|
||||
.compile(
|
||||
&[
|
||||
proto_files.join("confirmed_block.proto"),
|
||||
proto_files.join("transaction_by_addr.proto"),
|
||||
],
|
||||
&[proto_files],
|
||||
)
|
||||
}
|
||||
|
117
storage-proto/proto/solana.storage.transaction_by_addr.rs
Normal file
117
storage-proto/proto/solana.storage.transaction_by_addr.rs
Normal file
@ -0,0 +1,117 @@
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionByAddr {
|
||||
#[prost(message, repeated, tag = "1")]
|
||||
pub tx_by_addrs: ::std::vec::Vec<TransactionByAddrInfo>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionByAddrInfo {
|
||||
#[prost(bytes, tag = "1")]
|
||||
pub signature: std::vec::Vec<u8>,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub err: ::std::option::Option<TransactionError>,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub index: u32,
|
||||
#[prost(message, optional, tag = "4")]
|
||||
pub memo: ::std::option::Option<Memo>,
|
||||
#[prost(message, optional, tag = "5")]
|
||||
pub block_time: ::std::option::Option<UnixTimestamp>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Memo {
|
||||
#[prost(string, tag = "1")]
|
||||
pub memo: std::string::String,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionError {
|
||||
#[prost(enumeration = "TransactionErrorType", tag = "1")]
|
||||
pub transaction_error: i32,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub instruction_error: ::std::option::Option<InstructionError>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct InstructionError {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub index: u32,
|
||||
#[prost(enumeration = "InstructionErrorType", tag = "2")]
|
||||
pub error: i32,
|
||||
#[prost(message, optional, tag = "3")]
|
||||
pub custom: ::std::option::Option<CustomError>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UnixTimestamp {
|
||||
#[prost(int64, tag = "1")]
|
||||
pub timestamp: i64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CustomError {
|
||||
#[prost(uint32, tag = "1")]
|
||||
pub custom: u32,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum TransactionErrorType {
|
||||
AccountInUse = 0,
|
||||
AccountLoadedTwice = 1,
|
||||
AccountNotFound = 2,
|
||||
ProgramAccountNotFound = 3,
|
||||
InsufficientFundsForFee = 4,
|
||||
InvalidAccountForFee = 5,
|
||||
DuplicateSignature = 6,
|
||||
BlockhashNotFound = 7,
|
||||
InstructionError = 8,
|
||||
CallChainTooDeep = 9,
|
||||
MissingSignatureForFee = 10,
|
||||
InvalidAccountIndex = 11,
|
||||
SignatureFailure = 12,
|
||||
InvalidProgramForExecution = 13,
|
||||
SanitizeFailure = 14,
|
||||
ClusterMaintenance = 15,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum InstructionErrorType {
|
||||
GenericError = 0,
|
||||
InvalidArgument = 1,
|
||||
InvalidInstructionData = 2,
|
||||
InvalidAccountData = 3,
|
||||
AccountDataTooSmall = 4,
|
||||
InsufficientFunds = 5,
|
||||
IncorrectProgramId = 6,
|
||||
MissingRequiredSignature = 7,
|
||||
AccountAlreadyInitialized = 8,
|
||||
UninitializedAccount = 9,
|
||||
UnbalancedInstruction = 10,
|
||||
ModifiedProgramId = 11,
|
||||
ExternalAccountLamportSpend = 12,
|
||||
ExternalAccountDataModified = 13,
|
||||
ReadonlyLamportChange = 14,
|
||||
ReadonlyDataModified = 15,
|
||||
DuplicateAccountIndex = 16,
|
||||
ExecutableModified = 17,
|
||||
RentEpochModified = 18,
|
||||
NotEnoughAccountKeys = 19,
|
||||
AccountDataSizeChanged = 20,
|
||||
AccountNotExecutable = 21,
|
||||
AccountBorrowFailed = 22,
|
||||
AccountBorrowOutstanding = 23,
|
||||
DuplicateAccountOutOfSync = 24,
|
||||
Custom = 25,
|
||||
InvalidError = 26,
|
||||
ExecutableDataModified = 27,
|
||||
ExecutableLamportChange = 28,
|
||||
ExecutableAccountNotRentExempt = 29,
|
||||
UnsupportedProgramId = 30,
|
||||
CallDepth = 31,
|
||||
MissingAccount = 32,
|
||||
ReentrancyNotAllowed = 33,
|
||||
MaxSeedLengthExceeded = 34,
|
||||
InvalidSeeds = 35,
|
||||
InvalidRealloc = 36,
|
||||
ComputationalBudgetExceeded = 37,
|
||||
PrivilegeEscalation = 38,
|
||||
ProgramEnvironmentSetupFailure = 39,
|
||||
ProgramFailedToComplete = 40,
|
||||
ProgramFailedToCompile = 41,
|
||||
Immutable = 42,
|
||||
IncorrectAuthority = 43,
|
||||
}
|
@ -3,14 +3,16 @@ use solana_account_decoder::parse_token::UiTokenAmount;
|
||||
use solana_sdk::{
|
||||
hash::Hash,
|
||||
instruction::CompiledInstruction,
|
||||
instruction::InstructionError,
|
||||
message::{Message, MessageHeader},
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
transaction::Transaction,
|
||||
transaction::TransactionError,
|
||||
};
|
||||
use solana_transaction_status::{
|
||||
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionStatusMeta,
|
||||
TransactionTokenBalance, TransactionWithStatusMeta,
|
||||
ConfirmedBlock, InnerInstructions, Reward, RewardType, TransactionByAddrInfo,
|
||||
TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta,
|
||||
};
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
@ -21,6 +23,13 @@ pub mod generated {
|
||||
));
|
||||
}
|
||||
|
||||
pub mod tx_by_addr {
|
||||
include!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
concat!("/proto/solana.storage.transaction_by_addr.rs")
|
||||
));
|
||||
}
|
||||
|
||||
impl From<Vec<Reward>> for generated::Rewards {
|
||||
fn from(rewards: Vec<Reward>) -> Self {
|
||||
Self {
|
||||
@ -417,6 +426,356 @@ impl From<generated::CompiledInstruction> for CompiledInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<tx_by_addr::TransactionError> for TransactionError {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(transaction_error: tx_by_addr::TransactionError) -> Result<Self, Self::Error> {
|
||||
if transaction_error.transaction_error == 8 {
|
||||
if let Some(instruction_error) = transaction_error.instruction_error {
|
||||
if let Some(custom) = instruction_error.custom {
|
||||
return Ok(TransactionError::InstructionError(
|
||||
instruction_error.index as u8,
|
||||
InstructionError::Custom(custom.custom),
|
||||
));
|
||||
}
|
||||
|
||||
let ie = match instruction_error.error {
|
||||
0 => InstructionError::GenericError,
|
||||
1 => InstructionError::InvalidArgument,
|
||||
2 => InstructionError::InvalidInstructionData,
|
||||
3 => InstructionError::InvalidAccountData,
|
||||
4 => InstructionError::AccountDataTooSmall,
|
||||
5 => InstructionError::InsufficientFunds,
|
||||
6 => InstructionError::IncorrectProgramId,
|
||||
7 => InstructionError::MissingRequiredSignature,
|
||||
8 => InstructionError::AccountAlreadyInitialized,
|
||||
9 => InstructionError::UninitializedAccount,
|
||||
10 => InstructionError::UnbalancedInstruction,
|
||||
11 => InstructionError::ModifiedProgramId,
|
||||
12 => InstructionError::ExternalAccountLamportSpend,
|
||||
13 => InstructionError::ExternalAccountDataModified,
|
||||
14 => InstructionError::ReadonlyLamportChange,
|
||||
15 => InstructionError::ReadonlyDataModified,
|
||||
16 => InstructionError::DuplicateAccountIndex,
|
||||
17 => InstructionError::ExecutableModified,
|
||||
18 => InstructionError::RentEpochModified,
|
||||
19 => InstructionError::NotEnoughAccountKeys,
|
||||
20 => InstructionError::AccountDataSizeChanged,
|
||||
21 => InstructionError::AccountNotExecutable,
|
||||
22 => InstructionError::AccountBorrowFailed,
|
||||
23 => InstructionError::AccountBorrowOutstanding,
|
||||
24 => InstructionError::DuplicateAccountOutOfSync,
|
||||
26 => InstructionError::InvalidError,
|
||||
27 => InstructionError::ExecutableDataModified,
|
||||
28 => InstructionError::ExecutableLamportChange,
|
||||
29 => InstructionError::ExecutableAccountNotRentExempt,
|
||||
30 => InstructionError::UnsupportedProgramId,
|
||||
31 => InstructionError::CallDepth,
|
||||
32 => InstructionError::MissingAccount,
|
||||
33 => InstructionError::ReentrancyNotAllowed,
|
||||
34 => InstructionError::MaxSeedLengthExceeded,
|
||||
35 => InstructionError::InvalidSeeds,
|
||||
36 => InstructionError::InvalidRealloc,
|
||||
37 => InstructionError::ComputationalBudgetExceeded,
|
||||
38 => InstructionError::PrivilegeEscalation,
|
||||
39 => InstructionError::ProgramEnvironmentSetupFailure,
|
||||
40 => InstructionError::ProgramFailedToComplete,
|
||||
41 => InstructionError::ProgramFailedToCompile,
|
||||
42 => InstructionError::Immutable,
|
||||
43 => InstructionError::IncorrectAuthority,
|
||||
_ => return Err("Invalid InstructionError"),
|
||||
};
|
||||
|
||||
return Ok(TransactionError::InstructionError(
|
||||
instruction_error.index as u8,
|
||||
ie,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(match transaction_error.transaction_error {
|
||||
0 => TransactionError::AccountInUse,
|
||||
1 => TransactionError::AccountLoadedTwice,
|
||||
2 => TransactionError::AccountNotFound,
|
||||
3 => TransactionError::ProgramAccountNotFound,
|
||||
4 => TransactionError::InsufficientFundsForFee,
|
||||
5 => TransactionError::InvalidAccountForFee,
|
||||
6 => TransactionError::DuplicateSignature,
|
||||
7 => TransactionError::BlockhashNotFound,
|
||||
9 => TransactionError::CallChainTooDeep,
|
||||
10 => TransactionError::MissingSignatureForFee,
|
||||
11 => TransactionError::InvalidAccountIndex,
|
||||
12 => TransactionError::SignatureFailure,
|
||||
13 => TransactionError::InvalidProgramForExecution,
|
||||
14 => TransactionError::SanitizeFailure,
|
||||
15 => TransactionError::ClusterMaintenance,
|
||||
_ => return Err("Invalid TransactionError"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for tx_by_addr::TransactionError {
|
||||
fn from(transaction_error: TransactionError) -> Self {
|
||||
Self {
|
||||
transaction_error: match transaction_error {
|
||||
TransactionError::AccountInUse => tx_by_addr::TransactionErrorType::AccountInUse,
|
||||
TransactionError::AccountLoadedTwice => {
|
||||
tx_by_addr::TransactionErrorType::AccountLoadedTwice
|
||||
}
|
||||
TransactionError::AccountNotFound => {
|
||||
tx_by_addr::TransactionErrorType::AccountNotFound
|
||||
}
|
||||
TransactionError::ProgramAccountNotFound => {
|
||||
tx_by_addr::TransactionErrorType::ProgramAccountNotFound
|
||||
}
|
||||
TransactionError::InsufficientFundsForFee => {
|
||||
tx_by_addr::TransactionErrorType::InsufficientFundsForFee
|
||||
}
|
||||
TransactionError::InvalidAccountForFee => {
|
||||
tx_by_addr::TransactionErrorType::InvalidAccountForFee
|
||||
}
|
||||
TransactionError::DuplicateSignature => {
|
||||
tx_by_addr::TransactionErrorType::DuplicateSignature
|
||||
}
|
||||
TransactionError::BlockhashNotFound => {
|
||||
tx_by_addr::TransactionErrorType::BlockhashNotFound
|
||||
}
|
||||
TransactionError::CallChainTooDeep => {
|
||||
tx_by_addr::TransactionErrorType::CallChainTooDeep
|
||||
}
|
||||
TransactionError::MissingSignatureForFee => {
|
||||
tx_by_addr::TransactionErrorType::MissingSignatureForFee
|
||||
}
|
||||
TransactionError::InvalidAccountIndex => {
|
||||
tx_by_addr::TransactionErrorType::InvalidAccountIndex
|
||||
}
|
||||
TransactionError::SignatureFailure => {
|
||||
tx_by_addr::TransactionErrorType::SignatureFailure
|
||||
}
|
||||
TransactionError::InvalidProgramForExecution => {
|
||||
tx_by_addr::TransactionErrorType::InvalidProgramForExecution
|
||||
}
|
||||
TransactionError::SanitizeFailure => {
|
||||
tx_by_addr::TransactionErrorType::SanitizeFailure
|
||||
}
|
||||
TransactionError::ClusterMaintenance => {
|
||||
tx_by_addr::TransactionErrorType::ClusterMaintenance
|
||||
}
|
||||
TransactionError::InstructionError(_, _) => {
|
||||
tx_by_addr::TransactionErrorType::InstructionError
|
||||
}
|
||||
} as i32,
|
||||
instruction_error: match transaction_error {
|
||||
TransactionError::InstructionError(index, ref instruction_error) => {
|
||||
Some(tx_by_addr::InstructionError {
|
||||
index: index as u32,
|
||||
error: match instruction_error {
|
||||
InstructionError::GenericError => {
|
||||
tx_by_addr::InstructionErrorType::GenericError
|
||||
}
|
||||
InstructionError::InvalidArgument => {
|
||||
tx_by_addr::InstructionErrorType::InvalidArgument
|
||||
}
|
||||
InstructionError::InvalidInstructionData => {
|
||||
tx_by_addr::InstructionErrorType::InvalidInstructionData
|
||||
}
|
||||
InstructionError::InvalidAccountData => {
|
||||
tx_by_addr::InstructionErrorType::InvalidAccountData
|
||||
}
|
||||
InstructionError::AccountDataTooSmall => {
|
||||
tx_by_addr::InstructionErrorType::AccountDataTooSmall
|
||||
}
|
||||
InstructionError::InsufficientFunds => {
|
||||
tx_by_addr::InstructionErrorType::InsufficientFunds
|
||||
}
|
||||
InstructionError::IncorrectProgramId => {
|
||||
tx_by_addr::InstructionErrorType::IncorrectProgramId
|
||||
}
|
||||
InstructionError::MissingRequiredSignature => {
|
||||
tx_by_addr::InstructionErrorType::MissingRequiredSignature
|
||||
}
|
||||
InstructionError::AccountAlreadyInitialized => {
|
||||
tx_by_addr::InstructionErrorType::AccountAlreadyInitialized
|
||||
}
|
||||
InstructionError::UninitializedAccount => {
|
||||
tx_by_addr::InstructionErrorType::UninitializedAccount
|
||||
}
|
||||
InstructionError::UnbalancedInstruction => {
|
||||
tx_by_addr::InstructionErrorType::UnbalancedInstruction
|
||||
}
|
||||
InstructionError::ModifiedProgramId => {
|
||||
tx_by_addr::InstructionErrorType::ModifiedProgramId
|
||||
}
|
||||
InstructionError::ExternalAccountLamportSpend => {
|
||||
tx_by_addr::InstructionErrorType::ExternalAccountLamportSpend
|
||||
}
|
||||
InstructionError::ExternalAccountDataModified => {
|
||||
tx_by_addr::InstructionErrorType::ExternalAccountDataModified
|
||||
}
|
||||
InstructionError::ReadonlyLamportChange => {
|
||||
tx_by_addr::InstructionErrorType::ReadonlyLamportChange
|
||||
}
|
||||
InstructionError::ReadonlyDataModified => {
|
||||
tx_by_addr::InstructionErrorType::ReadonlyDataModified
|
||||
}
|
||||
InstructionError::DuplicateAccountIndex => {
|
||||
tx_by_addr::InstructionErrorType::DuplicateAccountIndex
|
||||
}
|
||||
InstructionError::ExecutableModified => {
|
||||
tx_by_addr::InstructionErrorType::ExecutableModified
|
||||
}
|
||||
InstructionError::RentEpochModified => {
|
||||
tx_by_addr::InstructionErrorType::RentEpochModified
|
||||
}
|
||||
InstructionError::NotEnoughAccountKeys => {
|
||||
tx_by_addr::InstructionErrorType::NotEnoughAccountKeys
|
||||
}
|
||||
InstructionError::AccountDataSizeChanged => {
|
||||
tx_by_addr::InstructionErrorType::AccountDataSizeChanged
|
||||
}
|
||||
InstructionError::AccountNotExecutable => {
|
||||
tx_by_addr::InstructionErrorType::AccountNotExecutable
|
||||
}
|
||||
InstructionError::AccountBorrowFailed => {
|
||||
tx_by_addr::InstructionErrorType::AccountBorrowFailed
|
||||
}
|
||||
InstructionError::AccountBorrowOutstanding => {
|
||||
tx_by_addr::InstructionErrorType::AccountBorrowOutstanding
|
||||
}
|
||||
InstructionError::DuplicateAccountOutOfSync => {
|
||||
tx_by_addr::InstructionErrorType::DuplicateAccountOutOfSync
|
||||
}
|
||||
InstructionError::Custom(_) => tx_by_addr::InstructionErrorType::Custom,
|
||||
InstructionError::InvalidError => {
|
||||
tx_by_addr::InstructionErrorType::InvalidError
|
||||
}
|
||||
InstructionError::ExecutableDataModified => {
|
||||
tx_by_addr::InstructionErrorType::ExecutableDataModified
|
||||
}
|
||||
InstructionError::ExecutableLamportChange => {
|
||||
tx_by_addr::InstructionErrorType::ExecutableLamportChange
|
||||
}
|
||||
InstructionError::ExecutableAccountNotRentExempt => {
|
||||
tx_by_addr::InstructionErrorType::ExecutableAccountNotRentExempt
|
||||
}
|
||||
InstructionError::UnsupportedProgramId => {
|
||||
tx_by_addr::InstructionErrorType::UnsupportedProgramId
|
||||
}
|
||||
InstructionError::CallDepth => {
|
||||
tx_by_addr::InstructionErrorType::CallDepth
|
||||
}
|
||||
InstructionError::MissingAccount => {
|
||||
tx_by_addr::InstructionErrorType::MissingAccount
|
||||
}
|
||||
InstructionError::ReentrancyNotAllowed => {
|
||||
tx_by_addr::InstructionErrorType::ReentrancyNotAllowed
|
||||
}
|
||||
InstructionError::MaxSeedLengthExceeded => {
|
||||
tx_by_addr::InstructionErrorType::MaxSeedLengthExceeded
|
||||
}
|
||||
InstructionError::InvalidSeeds => {
|
||||
tx_by_addr::InstructionErrorType::InvalidSeeds
|
||||
}
|
||||
InstructionError::InvalidRealloc => {
|
||||
tx_by_addr::InstructionErrorType::InvalidRealloc
|
||||
}
|
||||
InstructionError::ComputationalBudgetExceeded => {
|
||||
tx_by_addr::InstructionErrorType::ComputationalBudgetExceeded
|
||||
}
|
||||
InstructionError::PrivilegeEscalation => {
|
||||
tx_by_addr::InstructionErrorType::PrivilegeEscalation
|
||||
}
|
||||
InstructionError::ProgramEnvironmentSetupFailure => {
|
||||
tx_by_addr::InstructionErrorType::ProgramEnvironmentSetupFailure
|
||||
}
|
||||
InstructionError::ProgramFailedToComplete => {
|
||||
tx_by_addr::InstructionErrorType::ProgramFailedToComplete
|
||||
}
|
||||
InstructionError::ProgramFailedToCompile => {
|
||||
tx_by_addr::InstructionErrorType::ProgramFailedToCompile
|
||||
}
|
||||
InstructionError::Immutable => {
|
||||
tx_by_addr::InstructionErrorType::Immutable
|
||||
}
|
||||
InstructionError::IncorrectAuthority => {
|
||||
tx_by_addr::InstructionErrorType::IncorrectAuthority
|
||||
}
|
||||
} as i32,
|
||||
custom: match instruction_error {
|
||||
InstructionError::Custom(custom) => {
|
||||
Some(tx_by_addr::CustomError { custom: *custom })
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionByAddrInfo> for tx_by_addr::TransactionByAddrInfo {
|
||||
fn from(by_addr: TransactionByAddrInfo) -> Self {
|
||||
let TransactionByAddrInfo {
|
||||
signature,
|
||||
err,
|
||||
index,
|
||||
memo,
|
||||
block_time,
|
||||
} = by_addr;
|
||||
|
||||
Self {
|
||||
signature: <Signature as AsRef<[u8]>>::as_ref(&signature).into(),
|
||||
err: match err {
|
||||
None => None,
|
||||
Some(e) => Some(e.into()),
|
||||
},
|
||||
index,
|
||||
memo: memo.map(|memo| tx_by_addr::Memo { memo }),
|
||||
block_time: block_time.map(|timestamp| tx_by_addr::UnixTimestamp { timestamp }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<tx_by_addr::TransactionByAddrInfo> for TransactionByAddrInfo {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(
|
||||
transaction_by_addr: tx_by_addr::TransactionByAddrInfo,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let err = if let Some(err) = transaction_by_addr.err {
|
||||
Some(err.try_into()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
signature: Signature::new(&transaction_by_addr.signature),
|
||||
err,
|
||||
index: transaction_by_addr.index,
|
||||
memo: transaction_by_addr
|
||||
.memo
|
||||
.map(|tx_by_addr::Memo { memo }| memo),
|
||||
block_time: transaction_by_addr
|
||||
.block_time
|
||||
.map(|tx_by_addr::UnixTimestamp { timestamp }| timestamp),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<tx_by_addr::TransactionByAddr> for Vec<TransactionByAddrInfo> {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(collection: tx_by_addr::TransactionByAddr) -> Result<Self, Self::Error> {
|
||||
Ok(collection
|
||||
.tx_by_addrs
|
||||
.into_iter()
|
||||
.map(|tx_by_addr| tx_by_addr.try_into())
|
||||
.collect::<Result<Vec<TransactionByAddrInfo>, Self::Error>>()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
@ -448,4 +807,539 @@ mod test {
|
||||
let gen_reward: generated::Reward = reward.clone().into();
|
||||
assert_eq!(reward, gen_reward.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_by_addr_encode() {
|
||||
let info = TransactionByAddrInfo {
|
||||
signature: Signature::new(&bs58::decode("Nfo6rgemG1KLbk1xuNwfrQTsdxaGfLuWURHNRy9LYnDrubG7LFQZaA5obPNas9LQ6DdorJqxh2LxA3PsnWdkSrL").into_vec().unwrap()),
|
||||
err: None,
|
||||
index: 5,
|
||||
memo: Some("string".to_string()),
|
||||
block_time: Some(1610674861)
|
||||
};
|
||||
|
||||
let tx_by_addr_transaction_info: tx_by_addr::TransactionByAddrInfo = info.clone().into();
|
||||
assert_eq!(info, tx_by_addr_transaction_info.try_into().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transaction_error_encode() {
|
||||
let transaction_error = TransactionError::AccountInUse;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::AccountLoadedTwice;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::AccountNotFound;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::BlockhashNotFound;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::CallChainTooDeep;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::ClusterMaintenance;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::DuplicateSignature;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InsufficientFundsForFee;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InvalidAccountForFee;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InvalidAccountIndex;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InvalidProgramForExecution;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::MissingSignatureForFee;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::ProgramAccountNotFound;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::SanitizeFailure;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::SignatureFailure;
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountAlreadyInitialized);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountBorrowFailed);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountBorrowOutstanding);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountDataSizeChanged);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountDataTooSmall);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::AccountNotExecutable);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InstructionError(10, InstructionError::CallDepth);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ComputationalBudgetExceeded);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::DuplicateAccountIndex);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::DuplicateAccountOutOfSync);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InstructionError(
|
||||
10,
|
||||
InstructionError::ExecutableAccountNotRentExempt,
|
||||
);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ExecutableDataModified);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ExecutableLamportChange);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ExecutableModified);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ExternalAccountDataModified);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ExternalAccountLamportSpend);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::GenericError);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InstructionError(10, InstructionError::Immutable);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::IncorrectAuthority);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::IncorrectProgramId);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InsufficientFunds);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidAccountData);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidArgument);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidError);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidInstructionData);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidRealloc);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::InvalidSeeds);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::MaxSeedLengthExceeded);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::MissingAccount);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::MissingRequiredSignature);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ModifiedProgramId);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::NotEnoughAccountKeys);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::PrivilegeEscalation);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error = TransactionError::InstructionError(
|
||||
10,
|
||||
InstructionError::ProgramEnvironmentSetupFailure,
|
||||
);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ProgramFailedToCompile);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ProgramFailedToComplete);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ReadonlyDataModified);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ReadonlyLamportChange);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::ReentrancyNotAllowed);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::RentEpochModified);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::UnbalancedInstruction);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::UninitializedAccount);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::UnsupportedProgramId);
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
|
||||
let transaction_error =
|
||||
TransactionError::InstructionError(10, InstructionError::Custom(10));
|
||||
let tx_by_addr_transaction_error: tx_by_addr::TransactionError =
|
||||
transaction_error.clone().into();
|
||||
assert_eq!(
|
||||
transaction_error,
|
||||
tx_by_addr_transaction_error.try_into().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
104
storage-proto/src/transaction_by_addr.proto
Normal file
104
storage-proto/src/transaction_by_addr.proto
Normal file
@ -0,0 +1,104 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package solana.storage.TransactionByAddr;
|
||||
|
||||
message TransactionByAddr {
|
||||
repeated TransactionByAddrInfo tx_by_addrs = 1;
|
||||
}
|
||||
|
||||
message TransactionByAddrInfo {
|
||||
bytes signature = 1;
|
||||
TransactionError err = 2;
|
||||
uint32 index = 3;
|
||||
Memo memo = 4;
|
||||
UnixTimestamp block_time = 5;
|
||||
}
|
||||
|
||||
message Memo {
|
||||
string memo = 1;
|
||||
}
|
||||
|
||||
message TransactionError {
|
||||
TransactionErrorType transaction_error = 1;
|
||||
InstructionError instruction_error = 2;
|
||||
}
|
||||
|
||||
enum TransactionErrorType {
|
||||
ACCOUNT_IN_USE = 0;
|
||||
ACCOUNT_LOADED_TWICE = 1;
|
||||
ACCOUNT_NOT_FOUND = 2;
|
||||
PROGRAM_ACCOUNT_NOT_FOUND = 3;
|
||||
INSUFFICIENT_FUNDS_FOR_FEE = 4;
|
||||
INVALID_ACCOUNT_FOR_FEE = 5;
|
||||
DUPLICATE_SIGNATURE = 6;
|
||||
BLOCKHASH_NOT_FOUND = 7;
|
||||
INSTRUCTION_ERROR = 8;
|
||||
CALL_CHAIN_TOO_DEEP = 9;
|
||||
MISSING_SIGNATURE_FOR_FEE = 10;
|
||||
INVALID_ACCOUNT_INDEX = 11;
|
||||
SIGNATURE_FAILURE = 12;
|
||||
INVALID_PROGRAM_FOR_EXECUTION = 13;
|
||||
SANITIZE_FAILURE = 14;
|
||||
CLUSTER_MAINTENANCE = 15;
|
||||
}
|
||||
|
||||
message InstructionError {
|
||||
uint32 index = 1;
|
||||
InstructionErrorType error = 2;
|
||||
CustomError custom = 3;
|
||||
}
|
||||
|
||||
enum InstructionErrorType {
|
||||
GENERIC_ERROR = 0;
|
||||
INVALID_ARGUMENT = 1;
|
||||
INVALID_INSTRUCTION_DATA = 2;
|
||||
INVALID_ACCOUNT_DATA = 3;
|
||||
ACCOUNT_DATA_TOO_SMALL = 4;
|
||||
INSUFFICIENT_FUNDS = 5;
|
||||
INCORRECT_PROGRAM_ID = 6;
|
||||
MISSING_REQUIRED_SIGNATURE = 7;
|
||||
ACCOUNT_ALREADY_INITIALIZED = 8;
|
||||
UNINITIALIZED_ACCOUNT = 9;
|
||||
UNBALANCED_INSTRUCTION = 10;
|
||||
MODIFIED_PROGRAM_ID = 11;
|
||||
EXTERNAL_ACCOUNT_LAMPORT_SPEND = 12;
|
||||
EXTERNAL_ACCOUNT_DATA_MODIFIED = 13;
|
||||
READONLY_LAMPORT_CHANGE = 14;
|
||||
READONLY_DATA_MODIFIED = 15;
|
||||
DUPLICATE_ACCOUNT_INDEX = 16;
|
||||
EXECUTABLE_MODIFIED = 17;
|
||||
RENT_EPOCH_MODIFIED = 18;
|
||||
NOT_ENOUGH_ACCOUNT_KEYS = 19;
|
||||
ACCOUNT_DATA_SIZE_CHANGED = 20;
|
||||
ACCOUNT_NOT_EXECUTABLE = 21;
|
||||
ACCOUNT_BORROW_FAILED = 22;
|
||||
ACCOUNT_BORROW_OUTSTANDING = 23;
|
||||
DUPLICATE_ACCOUNT_OUT_OF_SYNC = 24;
|
||||
CUSTOM = 25;
|
||||
INVALID_ERROR = 26;
|
||||
EXECUTABLE_DATA_MODIFIED = 27;
|
||||
EXECUTABLE_LAMPORT_CHANGE = 28;
|
||||
EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT = 29;
|
||||
UNSUPPORTED_PROGRAM_ID = 30;
|
||||
CALL_DEPTH = 31;
|
||||
MISSING_ACCOUNT = 32;
|
||||
REENTRANCY_NOT_ALLOWED = 33;
|
||||
MAX_SEED_LENGTH_EXCEEDED = 34;
|
||||
INVALID_SEEDS = 35;
|
||||
INVALID_REALLOC = 36;
|
||||
COMPUTATIONAL_BUDGET_EXCEEDED = 37;
|
||||
PRIVILEGE_ESCALATION = 38;
|
||||
PROGRAM_ENVIRONMENT_SETUP_FAILURE = 39;
|
||||
PROGRAM_FAILED_TO_COMPLETE = 40;
|
||||
PROGRAM_FAILED_TO_COMPILE = 41;
|
||||
IMMUTABLE = 42;
|
||||
INCORRECT_AUTHORITY = 43;
|
||||
}
|
||||
|
||||
message UnixTimestamp {
|
||||
int64 timestamp = 1;
|
||||
}
|
||||
|
||||
message CustomError {
|
||||
uint32 custom = 1;
|
||||
}
|
@ -324,6 +324,7 @@ pub struct ConfirmedTransactionStatusWithSignature {
|
||||
pub slot: Slot,
|
||||
pub err: Option<TransactionError>,
|
||||
pub memo: Option<String>,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@ -382,6 +383,7 @@ pub struct ConfirmedTransaction {
|
||||
pub slot: Slot,
|
||||
#[serde(flatten)]
|
||||
pub transaction: TransactionWithStatusMeta,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
impl ConfirmedTransaction {
|
||||
@ -389,6 +391,7 @@ impl ConfirmedTransaction {
|
||||
EncodedConfirmedTransaction {
|
||||
slot: self.slot,
|
||||
transaction: self.transaction.encode(encoding),
|
||||
block_time: self.block_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -399,6 +402,7 @@ pub struct EncodedConfirmedTransaction {
|
||||
pub slot: Slot,
|
||||
#[serde(flatten)]
|
||||
pub transaction: EncodedTransactionWithStatusMeta,
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
/// A duplicate representation of a Transaction for pretty JSON serialization
|
||||
@ -575,6 +579,17 @@ impl EncodedTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
// A serialized `Vec<TransactionByAddrInfo>` is stored in the `tx-by-addr` table. The row keys are
|
||||
// the one's compliment of the slot so that rows may be listed in reverse order
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TransactionByAddrInfo {
|
||||
pub signature: Signature, // The transaction signature
|
||||
pub err: Option<TransactionError>, // None if the transaction executed successfully
|
||||
pub index: u32, // Where the transaction is located in the block
|
||||
pub memo: Option<String>, // Transaction memo
|
||||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
Reference in New Issue
Block a user