Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Add new TransactionDetails level #27601

Merged
merged 4 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/developing/clients/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ Returns identity and transaction information about a confirmed block in the ledg
- (optional) `<object>` - Configuration object containing the following optional fields:
- (optional) `encoding: <string>` - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (_slow_), "base64". If parameter not provided, the default encoding is "json".
["jsonParsed" encoding](jsonrpc-api.md#parsed-responses) attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If "jsonParsed" is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields).
- (optional) `transactionDetails: <string>` - level of transaction detail to return, either "full", "signatures", or "none". If parameter not provided, the default detail level is "full".
- (optional) `transactionDetails: <string>` - level of transaction detail to return, either "full", "accounts", "signatures", or "none". If parameter not provided, the default detail level is "full". If "accounts" are requested, transaction details only include signatures and an annotated list of accounts in each transaction. Transaction metadata is limited to only: fee, err, pre_balances, post_balances, pre_token_balances, and post_token_balances.
- (optional) `rewards: bool` - whether to populate the `rewards` array. If parameter not provided, the default includes rewards.
- (optional) `commitment: <string>` - [Commitment](jsonrpc-api.md#configuring-state-commitment); "processed" is not supported. If parameter not provided, the default is "finalized".
- (optional) `maxSupportedTransactionVersion: <number>` - set the max transaction version to return in responses. If the requested block contains a transaction with a higher version, an error will be returned. If this parameter is omitted, only legacy transactions will be returned, and a block containing any versioned transaction will prompt the error.
Expand Down
138 changes: 131 additions & 7 deletions transaction-status/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ pub trait EncodableWithMeta {
fn json_encode(&self) -> Self::Encoded;
}

trait JsonAccounts {
type Encoded;
fn build_json_accounts(&self) -> Self::Encoded;
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[serde(rename_all = "camelCase")]
pub enum TransactionBinaryEncoding {
Expand Down Expand Up @@ -116,6 +121,7 @@ pub enum TransactionDetails {
Full,
Signatures,
None,
Accounts,
}

impl Default for TransactionDetails {
Expand Down Expand Up @@ -429,6 +435,34 @@ impl UiTransactionStatusMeta {
compute_units_consumed: OptionSerializer::or_skip(meta.compute_units_consumed),
}
}

fn build_simple(meta: TransactionStatusMeta, show_rewards: bool) -> Self {
Self {
err: meta.status.clone().err(),
status: meta.status,
fee: meta.fee,
pre_balances: meta.pre_balances,
post_balances: meta.post_balances,
inner_instructions: OptionSerializer::Skip,
log_messages: OptionSerializer::Skip,
pre_token_balances: meta
.pre_token_balances
.map(|balance| balance.into_iter().map(Into::into).collect())
.into(),
post_token_balances: meta
.post_token_balances
.map(|balance| balance.into_iter().map(Into::into).collect())
.into(),
rewards: if show_rewards {
meta.rewards.into()
} else {
OptionSerializer::Skip
},
loaded_addresses: OptionSerializer::Skip,
return_data: OptionSerializer::Skip,
compute_units_consumed: OptionSerializer::Skip,
}
}
}

impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
Expand Down Expand Up @@ -610,6 +644,20 @@ impl ConfirmedBlock {
),
),
TransactionDetails::None => (None, None),
TransactionDetails::Accounts => (
Some(
self.transactions
.into_iter()
.map(|tx_with_meta| {
tx_with_meta.build_json_accounts(
options.max_supported_transaction_version,
options.show_rewards,
jstarry marked this conversation as resolved.
Show resolved Hide resolved
)
})
.collect::<Result<Vec<_>, _>>()?,
),
None,
),
};
Ok(UiConfirmedBlock {
previous_blockhash: self.previous_blockhash,
Expand Down Expand Up @@ -733,16 +781,31 @@ impl TransactionWithStatusMeta {
Self::Complete(tx_with_meta) => tx_with_meta.account_keys(),
}
}
}

impl VersionedTransactionWithStatusMeta {
pub fn encode(
fn build_json_accounts(
self,
encoding: UiTransactionEncoding,
max_supported_transaction_version: Option<u8>,
show_rewards: bool,
) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
let version = match (
match self {
Self::MissingMetadata(ref transaction) => Ok(EncodedTransactionWithStatusMeta {
version: None,
transaction: transaction.build_json_accounts(),
meta: None,
}),
Self::Complete(tx_with_meta) => {
tx_with_meta.build_json_accounts(max_supported_transaction_version, show_rewards)
}
}
}
}

impl VersionedTransactionWithStatusMeta {
fn validate_version(
&self,
max_supported_transaction_version: Option<u8>,
) -> Result<Option<TransactionVersion>, EncodeError> {
match (
max_supported_transaction_version,
self.transaction.version(),
) {
Expand All @@ -759,7 +822,16 @@ impl VersionedTransactionWithStatusMeta {
Err(EncodeError::UnsupportedTransactionVersion(version))
}
}
}?;
}
}

pub fn encode(
self,
encoding: UiTransactionEncoding,
max_supported_transaction_version: Option<u8>,
show_rewards: bool,
) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
let version = self.validate_version(max_supported_transaction_version)?;

Ok(EncodedTransactionWithStatusMeta {
transaction: self.transaction.encode_with_meta(encoding, &self.meta),
Expand Down Expand Up @@ -787,6 +859,40 @@ impl VersionedTransactionWithStatusMeta {
Some(&self.meta.loaded_addresses),
)
}

fn build_json_accounts(
self,
max_supported_transaction_version: Option<u8>,
show_rewards: bool,
) -> Result<EncodedTransactionWithStatusMeta, EncodeError> {
let version = self.validate_version(max_supported_transaction_version)?;

let account_keys = match &self.transaction.message {
VersionedMessage::Legacy(message) => parse_legacy_message_accounts(message),
VersionedMessage::V0(message) => {
let loaded_message =
LoadedMessage::new_borrowed(message, &self.meta.loaded_addresses);
parse_v0_message_accounts(&loaded_message)
}
};

Ok(EncodedTransactionWithStatusMeta {
transaction: EncodedTransaction::Accounts(UiAccountsList {
signatures: self
.transaction
.signatures
.iter()
.map(ToString::to_string)
.collect(),
account_keys,
}),
meta: Some(UiTransactionStatusMeta::build_simple(
self.meta,
show_rewards,
)),
version,
})
}
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -849,6 +955,7 @@ pub enum EncodedTransaction {
LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility
Binary(String, TransactionBinaryEncoding),
Json(UiTransaction),
Accounts(UiAccountsList),
}

impl EncodableWithMeta for VersionedTransaction {
Expand Down Expand Up @@ -920,10 +1027,20 @@ impl Encodable for Transaction {
}
}

impl JsonAccounts for Transaction {
type Encoded = EncodedTransaction;
fn build_json_accounts(&self) -> Self::Encoded {
EncodedTransaction::Accounts(UiAccountsList {
signatures: self.signatures.iter().map(ToString::to_string).collect(),
account_keys: parse_legacy_message_accounts(&self.message),
})
}
}

impl EncodedTransaction {
pub fn decode(&self) -> Option<VersionedTransaction> {
let (blob, encoding) = match self {
Self::Json(_) => return None,
Self::Json(_) | Self::Accounts(_) => return None,
Self::LegacyBinary(blob) => (blob, TransactionBinaryEncoding::Base58),
Self::Binary(blob, encoding) => (blob, *encoding),
};
Expand Down Expand Up @@ -1041,6 +1158,13 @@ pub struct UiRawMessage {
pub address_table_lookups: Option<Vec<UiAddressTableLookup>>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiAccountsList {
pub signatures: Vec<String>,
pub account_keys: Vec<ParsedAccount>,
CriesofCarrots marked this conversation as resolved.
Show resolved Hide resolved
}

/// A duplicate representation of a MessageAddressTableLookup, in raw format, for pretty JSON serialization
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
Expand Down