From 0bfc18837583b943780da7a2c3a0fa744ad2be67 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 8 Sep 2022 14:10:57 -0700 Subject: [PATCH] Update getBlock/getTransaction rpc handling of return_data (#27672) * Move return_data type to transaction-status crate * Use UiTransactionReturnData in UiTransactionStatusMeta * Fixup display handling * Update docs --- cli-output/src/display.rs | 21 ++++++++++---- docs/src/developing/clients/jsonrpc-api.md | 6 ++++ rpc-client-api/src/response.rs | 26 ++---------------- transaction-status/src/lib.rs | 32 ++++++++++++++++++++-- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/cli-output/src/display.rs b/cli-output/src/display.rs index 26947a346..c8450dd57 100644 --- a/cli-output/src/display.rs +++ b/cli-output/src/display.rs @@ -15,9 +15,10 @@ use { signature::Signature, stake, transaction::{TransactionError, TransactionVersion, VersionedTransaction}, - transaction_context::TransactionReturnData, }, - solana_transaction_status::{Rewards, UiTransactionStatusMeta}, + solana_transaction_status::{ + Rewards, UiReturnDataEncoding, UiTransactionReturnData, UiTransactionStatusMeta, + }, spl_memo::{id as spl_memo_id, v1::id as spl_memo_v1_id}, std::{collections::HashMap, fmt, io, time::Duration}, }; @@ -597,18 +598,27 @@ fn write_balances( fn write_return_data( w: &mut W, - return_data: Option<&TransactionReturnData>, + return_data: Option<&UiTransactionReturnData>, prefix: &str, ) -> io::Result<()> { if let Some(return_data) = return_data { - if !return_data.data.is_empty() { + let (data, encoding) = &return_data.data; + let raw_return_data = match encoding { + UiReturnDataEncoding::Base64 => base64::decode(data).map_err(|err| { + io::Error::new( + io::ErrorKind::Other, + format!("could not parse data as {:?}: {:?}", encoding, err), + ) + })?, + }; + if !raw_return_data.is_empty() { use pretty_hex::*; writeln!( w, "{}Return Data from Program {}:", prefix, return_data.program_id )?; - writeln!(w, "{} {:?}", prefix, return_data.data.hex_dump())?; + writeln!(w, "{} {:?}", prefix, raw_return_data.hex_dump())?; } } Ok(()) @@ -724,6 +734,7 @@ mod test { pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, + transaction_context::TransactionReturnData, }, solana_transaction_status::{Reward, RewardType, TransactionStatusMeta}, std::io::BufWriter, diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 04a151998..7f30fd1ce 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -449,6 +449,9 @@ The result field will be an object with the following fields: - `loadedAddresses: ` - Transaction addresses loaded from address lookup tables. Undefined if `maxSupportedTransactionVersion` is not set in request params. - `writable: ` - Ordered list of base-58 encoded addresses for writable loaded accounts - `readonly: ` - Ordered list of base-58 encoded addresses for readonly loaded accounts + - `returnData: ` - the most-recent return data generated by an instruction in the transaction, with the following fields: + - `programId: `, the program that generated the return data, as base-58 encoded Pubkey + - `data: <[string, encoding]>`, the return data itself, as base-64 encoded binary data - `version: <"legacy"|number|undefined>` - Transaction version. Undefined if `maxSupportedTransactionVersion` is not set in request params. - `signatures: ` - present if "signatures" are requested for transaction details; an array of signatures strings, corresponding to the transaction order in the block - `rewards: ` - block-level rewards, present if rewards are requested; an array of JSON objects containing: @@ -3053,6 +3056,9 @@ Returns transaction details for a confirmed transaction - `loadedAddresses: ` - Transaction addresses loaded from address lookup tables. Undefined if `maxSupportedTransactionVersion` is not set in request params. - `writable: ` - Ordered list of base-58 encoded addresses for writable loaded accounts - `readonly: ` - Ordered list of base-58 encoded addresses for readonly loaded accounts + - `returnData: ` - the most-recent return data generated by an instruction in the transaction, with the following fields: + - `programId: `, the program that generated the return data, as base-58 encoded Pubkey + - `data: <[string, encoding]>`, the return data itself, as base-64 encoded binary data - `version: <"legacy"|number|undefined>` - Transaction version. Undefined if `maxSupportedTransactionVersion` is not set in request params. #### Example: diff --git a/rpc-client-api/src/response.rs b/rpc-client-api/src/response.rs index 29ce96166..dee39046b 100644 --- a/rpc-client-api/src/response.rs +++ b/rpc-client-api/src/response.rs @@ -8,10 +8,10 @@ use { hash::Hash, inflation::Inflation, transaction::{Result, TransactionError}, - transaction_context::TransactionReturnData, }, solana_transaction_status::{ ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock, + UiTransactionReturnData, }, std::{collections::HashMap, fmt, net::SocketAddr, str::FromStr}, thiserror::Error, @@ -399,29 +399,7 @@ pub struct RpcSimulateTransactionResult { pub logs: Option>, pub accounts: Option>>, pub units_consumed: Option, - pub return_data: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -#[serde(rename_all = "camelCase")] -pub struct RpcTransactionReturnData { - pub program_id: String, - pub data: (String, ReturnDataEncoding), -} - -impl From for RpcTransactionReturnData { - fn from(return_data: TransactionReturnData) -> Self { - Self { - program_id: return_data.program_id.to_string(), - data: (base64::encode(return_data.data), ReturnDataEncoding::Base64), - } - } -} - -#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum ReturnDataEncoding { - Base64, + pub return_data: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 2e17bc541..5704cdf44 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -327,7 +327,8 @@ pub struct UiTransactionStatusMeta { pub rewards: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub loaded_addresses: Option, - pub return_data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub return_data: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub compute_units_consumed: Option, } @@ -380,7 +381,7 @@ impl UiTransactionStatusMeta { .map(|balance| balance.into_iter().map(Into::into).collect()), rewards: if show_rewards { meta.rewards } else { None }, loaded_addresses: None, - return_data: meta.return_data, + return_data: meta.return_data.map(|return_data| return_data.into()), compute_units_consumed: meta.compute_units_consumed, } } @@ -406,7 +407,7 @@ impl From for UiTransactionStatusMeta { .map(|balance| balance.into_iter().map(Into::into).collect()), rewards: meta.rewards, loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)), - return_data: meta.return_data, + return_data: meta.return_data.map(|return_data| return_data.into()), compute_units_consumed: meta.compute_units_consumed, } } @@ -1031,6 +1032,31 @@ pub struct TransactionByAddrInfo { pub block_time: Option, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct UiTransactionReturnData { + pub program_id: String, + pub data: (String, UiReturnDataEncoding), +} + +impl From for UiTransactionReturnData { + fn from(return_data: TransactionReturnData) -> Self { + Self { + program_id: return_data.program_id.to_string(), + data: ( + base64::encode(return_data.data), + UiReturnDataEncoding::Base64, + ), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum UiReturnDataEncoding { + Base64, +} + #[cfg(test)] mod test { use super::*;