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

Commit

Permalink
Add serialization-control enum for RPC Options (backport #27676) (#27792
Browse files Browse the repository at this point in the history
)

* Add serialization-control enum for RPC Options (#27676)

* Add test to verify output when deserializing/reserializing empty fields

* Add test to verify serialization from UiTransactionStatusMeta constructors

* Add OptionSerializer

* Use OptionSerializer for inner_instructions

* Use OptionSerializer for loaded_addresses

* Remove Default variant, use into instead

* Add as_ref implementation

* Use OptionSerializer for log_messages and rewards

* Use OptionSerializer for token_balances

* Use OptionSerializer for return_data

* Use OptionSerializer for compute_units_consumed

(cherry picked from commit 360ca07)

# Conflicts:
#	cli-output/src/display.rs
#	client/src/mock_sender.rs
#	transaction-status/src/lib.rs

* Fix conflicts
  • Loading branch information
Tyera Eulberg authored Sep 15, 2022
1 parent 5a23027 commit 0fafcce
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 42 deletions.
4 changes: 2 additions & 2 deletions cli-output/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ fn write_transaction<W: io::Write>(
write_status(w, &transaction_status.status, prefix)?;
write_fees(w, transaction_status.fee, prefix)?;
write_balances(w, transaction_status, prefix)?;
write_log_messages(w, transaction_status.log_messages.as_ref(), prefix)?;
write_rewards(w, transaction_status.rewards.as_ref(), prefix)?;
write_log_messages(w, transaction_status.log_messages.as_ref().into(), prefix)?;
write_rewards(w, transaction_status.rewards.as_ref().into(), prefix)?;
} else {
writeln!(w, "{}Status: Unavailable", prefix)?;
}
Expand Down
15 changes: 8 additions & 7 deletions client/src/mock_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use {
transaction::{self, Transaction, TransactionError, TransactionVersion},
},
solana_transaction_status::{
EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction,
option_serializer::OptionSerializer, EncodedConfirmedBlock,
EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction,
EncodedTransactionWithStatusMeta, Rewards, TransactionBinaryEncoding,
TransactionConfirmationStatus, TransactionStatus, UiCompiledInstruction, UiMessage,
UiRawMessage, UiTransaction, UiTransactionStatusMeta,
Expand Down Expand Up @@ -223,12 +224,12 @@ impl RpcSender for MockSender {
fee: 0,
pre_balances: vec![499999999999999950, 50, 1],
post_balances: vec![499999999999999950, 50, 1],
inner_instructions: None,
log_messages: None,
pre_token_balances: None,
post_token_balances: None,
rewards: None,
loaded_addresses: None,
inner_instructions: OptionSerializer::None,
log_messages: OptionSerializer::None,
pre_token_balances: OptionSerializer::None,
post_token_balances: OptionSerializer::None,
rewards: OptionSerializer::None,
loaded_addresses: OptionSerializer::Skip,
}),
},
block_time: Some(1628633791),
Expand Down
233 changes: 200 additions & 33 deletions transaction-status/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub use {crate::extract_memos::extract_and_fmt_memos, solana_sdk::reward_type::RewardType};
use {
crate::{
option_serializer::OptionSerializer,
parse_accounts::{parse_legacy_message_accounts, parse_v0_message_accounts, ParsedAccount},
parse_instruction::{parse, ParsedInstruction},
},
Expand Down Expand Up @@ -32,6 +33,7 @@ extern crate lazy_static;
extern crate serde_derive;

pub mod extract_memos;
pub mod option_serializer;
pub mod parse_accounts;
pub mod parse_associated_token;
pub mod parse_bpf_loader;
Expand Down Expand Up @@ -248,10 +250,16 @@ pub struct UiTransactionTokenBalance {
pub account_index: u8,
pub mint: String,
pub ui_token_amount: UiTokenAmount,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub owner: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub program_id: Option<String>,
#[serde(
default = "OptionSerializer::skip",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub owner: OptionSerializer<String>,
#[serde(
default = "OptionSerializer::skip",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub program_id: OptionSerializer<String>,
}

impl From<TransactionTokenBalance> for UiTransactionTokenBalance {
Expand All @@ -261,14 +269,14 @@ impl From<TransactionTokenBalance> for UiTransactionTokenBalance {
mint: token_balance.mint,
ui_token_amount: token_balance.ui_token_amount,
owner: if !token_balance.owner.is_empty() {
Some(token_balance.owner)
OptionSerializer::Some(token_balance.owner)
} else {
None
OptionSerializer::Skip
},
program_id: if !token_balance.program_id.is_empty() {
Some(token_balance.program_id)
OptionSerializer::Some(token_balance.program_id)
} else {
None
OptionSerializer::Skip
},
}
}
Expand Down Expand Up @@ -314,13 +322,36 @@ pub struct UiTransactionStatusMeta {
pub fee: u64,
pub pre_balances: Vec<u64>,
pub post_balances: Vec<u64>,
pub inner_instructions: Option<Vec<UiInnerInstructions>>,
pub log_messages: Option<Vec<String>>,
pub pre_token_balances: Option<Vec<UiTransactionTokenBalance>>,
pub post_token_balances: Option<Vec<UiTransactionTokenBalance>>,
pub rewards: Option<Rewards>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub loaded_addresses: Option<UiLoadedAddresses>,
#[serde(
default = "OptionSerializer::none",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub inner_instructions: OptionSerializer<Vec<UiInnerInstructions>>,
#[serde(
default = "OptionSerializer::none",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub log_messages: OptionSerializer<Vec<String>>,
#[serde(
default = "OptionSerializer::none",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub pre_token_balances: OptionSerializer<Vec<UiTransactionTokenBalance>>,
#[serde(
default = "OptionSerializer::none",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub post_token_balances: OptionSerializer<Vec<UiTransactionTokenBalance>>,
#[serde(
default = "OptionSerializer::none",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub rewards: OptionSerializer<Rewards>,
#[serde(
default = "OptionSerializer::skip",
skip_serializing_if = "OptionSerializer::should_skip"
)]
pub loaded_addresses: OptionSerializer<UiLoadedAddresses>,
}

/// A duplicate representation of LoadedAddresses
Expand Down Expand Up @@ -357,20 +388,25 @@ impl UiTransactionStatusMeta {
fee: meta.fee,
pre_balances: meta.pre_balances,
post_balances: meta.post_balances,
inner_instructions: meta.inner_instructions.map(|ixs| {
ixs.into_iter()
.map(|ix| UiInnerInstructions::parse(ix, &account_keys))
.collect()
}),
log_messages: meta.log_messages,
inner_instructions: meta
.inner_instructions
.map(|ixs| {
ixs.into_iter()
.map(|ix| UiInnerInstructions::parse(ix, &account_keys))
.collect()
})
.into(),
log_messages: meta.log_messages.into(),
pre_token_balances: meta
.pre_token_balances
.map(|balance| balance.into_iter().map(Into::into).collect()),
.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()),
rewards: if show_rewards { meta.rewards } else { None },
loaded_addresses: None,
.map(|balance| balance.into_iter().map(Into::into).collect())
.into(),
rewards: if show_rewards { meta.rewards } else { None }.into(),
loaded_addresses: OptionSerializer::Skip,
}
}
}
Expand All @@ -385,16 +421,19 @@ impl From<TransactionStatusMeta> for UiTransactionStatusMeta {
post_balances: meta.post_balances,
inner_instructions: meta
.inner_instructions
.map(|ixs| ixs.into_iter().map(Into::into).collect()),
log_messages: meta.log_messages,
.map(|ixs| ixs.into_iter().map(Into::into).collect())
.into(),
log_messages: meta.log_messages.into(),
pre_token_balances: meta
.pre_token_balances
.map(|balance| balance.into_iter().map(Into::into).collect()),
.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()),
rewards: meta.rewards,
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)),
.map(|balance| balance.into_iter().map(Into::into).collect())
.into(),
rewards: meta.rewards.into(),
loaded_addresses: Some(UiLoadedAddresses::from(&meta.loaded_addresses)).into(),
}
}
}
Expand Down Expand Up @@ -709,7 +748,7 @@ impl VersionedTransactionWithStatusMeta {
_ => {
let mut meta = UiTransactionStatusMeta::from(self.meta);
if !show_rewards {
meta.rewards = None;
meta.rewards = OptionSerializer::None;
}
meta
}
Expand Down Expand Up @@ -1020,7 +1059,7 @@ pub struct TransactionByAddrInfo {

#[cfg(test)]
mod test {
use super::*;
use {super::*, serde_json::json};

#[test]
fn test_decode_invalid_transaction() {
Expand Down Expand Up @@ -1114,4 +1153,132 @@ mod test {
};
assert!(status.satisfies_commitment(CommitmentConfig::confirmed()));
}

#[test]
fn test_serde_empty_fields() {
fn test_serde<'de, T: serde::Serialize + serde::Deserialize<'de>>(
json_input: &'de str,
expected_json_output: &str,
) {
let typed_meta: T = serde_json::from_str(json_input).unwrap();
let reserialized_value = json!(typed_meta);

let expected_json_output_value: serde_json::Value =
serde_json::from_str(expected_json_output).unwrap();
assert_eq!(reserialized_value, expected_json_output_value);
}

let json_input = "{\
\"err\":null,\
\"status\":{\"Ok\":null},\
\"fee\":1234,\
\"preBalances\":[1,2,3],\
\"postBalances\":[4,5,6]\
}";
let expected_json_output = "{\
\"err\":null,\
\"status\":{\"Ok\":null},\
\"fee\":1234,\
\"preBalances\":[1,2,3],\
\"postBalances\":[4,5,6],\
\"innerInstructions\":null,\
\"logMessages\":null,\
\"preTokenBalances\":null,\
\"postTokenBalances\":null,\
\"rewards\":null\
}";
test_serde::<UiTransactionStatusMeta>(json_input, expected_json_output);

let json_input = "{\
\"accountIndex\":5,\
\"mint\":\"DXM2yVSouSg1twmQgHLKoSReqXhtUroehWxrTgPmmfWi\",\
\"uiTokenAmount\": {
\"amount\": \"1\",\
\"decimals\": 0,\
\"uiAmount\": 1.0,\
\"uiAmountString\": \"1\"\
}\
}";
let expected_json_output = "{\
\"accountIndex\":5,\
\"mint\":\"DXM2yVSouSg1twmQgHLKoSReqXhtUroehWxrTgPmmfWi\",\
\"uiTokenAmount\": {
\"amount\": \"1\",\
\"decimals\": 0,\
\"uiAmount\": 1.0,\
\"uiAmountString\": \"1\"\
}\
}";
test_serde::<UiTransactionTokenBalance>(json_input, expected_json_output);
}

#[test]
fn test_ui_transaction_status_meta_ctors_serialization() {
let meta = TransactionStatusMeta {
status: Ok(()),
fee: 1234,
pre_balances: vec![1, 2, 3],
post_balances: vec![4, 5, 6],
inner_instructions: None,
log_messages: None,
pre_token_balances: None,
post_token_balances: None,
rewards: None,
loaded_addresses: LoadedAddresses {
writable: vec![],
readonly: vec![],
},
};
let expected_json_output_value: serde_json::Value = serde_json::from_str(
"{\
\"err\":null,\
\"status\":{\"Ok\":null},\
\"fee\":1234,\
\"preBalances\":[1,2,3],\
\"postBalances\":[4,5,6],\
\"innerInstructions\":null,\
\"logMessages\":null,\
\"preTokenBalances\":null,\
\"postTokenBalances\":null,\
\"rewards\":null,\
\"loadedAddresses\":{\
\"readonly\": [],\
\"writable\": []\
}\
}",
)
.unwrap();
let ui_meta_from: UiTransactionStatusMeta = meta.clone().into();
assert_eq!(
serde_json::to_value(&ui_meta_from).unwrap(),
expected_json_output_value
);

let expected_json_output_value: serde_json::Value = serde_json::from_str(
"{\
\"err\":null,\
\"status\":{\"Ok\":null},\
\"fee\":1234,\
\"preBalances\":[1,2,3],\
\"postBalances\":[4,5,6],\
\"innerInstructions\":null,\
\"logMessages\":null,\
\"preTokenBalances\":null,\
\"postTokenBalances\":null,\
\"rewards\":null\
}",
)
.unwrap();
let ui_meta_parse_with_rewards = UiTransactionStatusMeta::parse(meta.clone(), &[], true);
assert_eq!(
serde_json::to_value(&ui_meta_parse_with_rewards).unwrap(),
expected_json_output_value
);

let ui_meta_parse_no_rewards = UiTransactionStatusMeta::parse(meta, &[], false);
assert_eq!(
serde_json::to_value(&ui_meta_parse_no_rewards).unwrap(),
expected_json_output_value
);
}
}
Loading

0 comments on commit 0fafcce

Please sign in to comment.