From 4130cd8a61e4071d2e63d8c35aff2e5558f40589 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Sat, 15 Aug 2020 17:56:09 -0700 Subject: [PATCH] Rework UiAccountData encode/decode such that it works from Rust --- account-decoder/src/lib.rs | 31 +++++++++++++++++++------------ cli/src/cli.rs | 9 +++------ client/src/rpc_client.rs | 18 ++---------------- core/src/rpc.rs | 21 ++++++++++++--------- docs/src/apps/jsonrpc-api.md | 4 ++-- transaction-status/src/lib.rs | 2 +- 6 files changed, 39 insertions(+), 46 deletions(-) diff --git a/account-decoder/src/lib.rs b/account-decoder/src/lib.rs index a4d32e5e01ac85..cfbd3fa145c773 100644 --- a/account-decoder/src/lib.rs +++ b/account-decoder/src/lib.rs @@ -32,17 +32,17 @@ pub struct UiAccount { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", untagged)] pub enum UiAccountData { - Binary(String), + LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility Json(ParsedAccount), - Binary64(String), + Binary(String, UiAccountEncoding), } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub enum UiAccountEncoding { - Binary, // SLOW! Avoid this encoding + Binary, // base-58 encoded string. SLOW! Avoid this encoding JsonParsed, - Binary64, + Binary64, // base-64 encoded string. } impl UiAccount { @@ -54,20 +54,23 @@ impl UiAccount { data_slice_config: Option, ) -> Self { let data = match encoding { - UiAccountEncoding::Binary => UiAccountData::Binary( + UiAccountEncoding::Binary => UiAccountData::LegacyBinary( bs58::encode(slice_data(&account.data, data_slice_config)).into_string(), ), - UiAccountEncoding::Binary64 => UiAccountData::Binary64(base64::encode(slice_data( - &account.data, - data_slice_config, - ))), + UiAccountEncoding::Binary64 => UiAccountData::Binary( + base64::encode(slice_data(&account.data, data_slice_config)), + encoding, + ), UiAccountEncoding::JsonParsed => { if let Ok(parsed_data) = parse_account_data(pubkey, &account.owner, &account.data, additional_data) { UiAccountData::Json(parsed_data) } else { - UiAccountData::Binary64(base64::encode(&account.data)) + UiAccountData::Binary( + base64::encode(&account.data), + UiAccountEncoding::Binary64, + ) } } }; @@ -83,8 +86,12 @@ impl UiAccount { pub fn decode(&self) -> Option { let data = match &self.data { UiAccountData::Json(_) => None, - UiAccountData::Binary(blob) => bs58::decode(blob).into_vec().ok(), - UiAccountData::Binary64(blob) => base64::decode(blob).ok(), + UiAccountData::LegacyBinary(blob) => bs58::decode(blob).into_vec().ok(), + UiAccountData::Binary(blob, encoding) => match encoding { + UiAccountEncoding::Binary => bs58::decode(blob).into_vec().ok(), + UiAccountEncoding::Binary64 => base64::decode(blob).ok(), + UiAccountEncoding::JsonParsed => None, + }, }?; Some(Account { lamports: self.lamports, diff --git a/cli/src/cli.rs b/cli/src/cli.rs index f572eb0eaf1a14..d26e216b0f6828 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -10,7 +10,7 @@ use crate::{ validator_info::*, vote::*, }; -use clap::{App, AppSettings, Arg, ArgMatches, SubCommand, value_t_or_exit}; +use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand}; use log::*; use num_traits::FromPrimitive; use serde_json::{self, json, Value}; @@ -825,13 +825,10 @@ pub fn parse_command( let encoding = match matches.value_of("encoding").unwrap() { "binary" => UiTransactionEncoding::Binary, "binary64" => UiTransactionEncoding::Binary64, - _ => unreachable!() + _ => unreachable!(), }; - let encoded_transaction = EncodedTransaction::Binary( - blob, - encoding, - ); + let encoded_transaction = EncodedTransaction::Binary(blob, encoding); if let Some(transaction) = encoded_transaction.decode() { Ok(CliCommandInfo { command: CliCommand::DecodeTransaction(transaction), diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 0c4f059984b825..59e8c640081191 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -15,12 +15,7 @@ use bincode::serialize; use indicatif::{ProgressBar, ProgressStyle}; use log::*; use serde_json::{json, Value}; -use solana_account_decoder::{ - parse_token::UiTokenAmount, - UiAccount, - UiAccountData::{Binary, Binary64}, - UiAccountEncoding, -}; +use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount, UiAccountEncoding}; use solana_sdk::{ account::Account, clock::{ @@ -487,17 +482,8 @@ impl RpcClient { } let Response { context, - value: mut rpc_account, + value: rpc_account, } = serde_json::from_value::>>(result_json)?; - if let Some(ref mut account) = rpc_account { - if let Binary(_) = &account.data { - let tmp = Binary64(String::new()); - match std::mem::replace(&mut account.data, tmp) { - Binary(new_data) => account.data = Binary64(new_data), - _ => panic!("should have gotten binary here."), - } - } - } trace!("Response account {:?} {:?}", pubkey, rpc_account); let account = rpc_account.and_then(|rpc_account| rpc_account.decode()); Ok(Response { diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 438676669a7e16..af48e4b3d195fd 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -3097,13 +3097,13 @@ pub mod tests { "result": { "context":{"slot":0}, "value":{ - "owner": "11111111111111111111111111111111", - "lamports": 20, - "data": "", - "executable": false, - "rentEpoch": 0 - }, + "owner": "11111111111111111111111111111111", + "lamports": 20, + "data": "", + "executable": false, + "rentEpoch": 0 }, + }, "id": 1, }); let expected: Response = @@ -3125,7 +3125,10 @@ pub mod tests { let res = io.handle_request_sync(&req, meta.clone()); let result: Value = serde_json::from_str(&res.expect("actual response")) .expect("actual response deserialization"); - assert_eq!(result["result"]["value"]["data"], base64::encode(&data)); + assert_eq!( + result["result"]["value"]["data"], + json!([base64::encode(&data), "binary64"]), + ); let req = format!( r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary64", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#, @@ -3136,7 +3139,7 @@ pub mod tests { .expect("actual response deserialization"); assert_eq!( result["result"]["value"]["data"], - base64::encode(&data[1..3]), + json!([base64::encode(&data[1..3]), "binary64"]), ); let req = format!( @@ -4315,7 +4318,7 @@ pub mod tests { for TransactionWithStatusMeta { transaction, meta } in confirmed_block.transactions.into_iter() { - if let EncodedTransaction::Binary(transaction) = transaction { + if let EncodedTransaction::LegacyBinary(transaction) = transaction { let decoded_transaction: Transaction = deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap(); if decoded_transaction.signatures[0] == confirmed_block_signatures[0] { diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index 6cc512197a94b9..422cf006ef356e 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -347,7 +347,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary64"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"blockTime":null,"blockhash":"3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA","parentSlot":429,"previousBlockhash":"mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B","rewards":[],"transactions":[{"meta":{"err":null,"fee":5000,"postBalances":[499998932500,26858640,1,1,1],"preBalances":[499998937500,26858640,1,1,1],"status":{"Ok":null}},"transaction":"AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA=="}]},"id":1} +{"jsonrpc":"2.0","result":{"blockTime":null,"blockhash":"3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA","parentSlot":429,"previousBlockhash":"mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B","rewards":[],"transactions":[{"meta":{"err":null,"fee":5000,"postBalances":[499998932500,26858640,1,1,1],"preBalances":[499998937500,26858640,1,1,1],"status":{"Ok":null}},"transaction":["AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==","binary64"]}]},"id":1} ``` #### Transaction Structure @@ -495,7 +495,7 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", "binary64"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"meta":{"err":null,"fee":5000,"postBalances":[499998932500,26858640,1,1,1],"preBalances":[499998937500,26858640,1,1,1],"status":{"Ok":null}},"slot":430,"transaction":"AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA=="},"id":1} +{"jsonrpc":"2.0","result":{"meta":{"err":null,"fee":5000,"postBalances":[499998932500,26858640,1,1,1],"preBalances":[499998937500,26858640,1,1,1],"status":{"Ok":null}},"slot":430,"transaction":["AVj7dxHlQ9IrvdYVIjuiRFs1jLaDMHixgrv+qtHBwz51L4/ImLZhszwiyEJDIp7xeBSpm/TX5B7mYzxa+fPOMw0BAAMFJMJVqLw+hJYheizSoYlLm53KzgT82cDVmazarqQKG2GQsLgiqktA+a+FDR4/7xnDX7rsusMwryYVUdixfz1B1Qan1RcZLwqvxvJl4/t3zHragsUp0L47E24tAFUgAAAABqfVFxjHdMkoVmOYaR1etoteuKObS21cc1VbIQAAAAAHYUgdNXR0u3xNdiTr072z2DVec9EQQ/wNo1OAAAAAAAtxOUhPBp2WSjUNJEgfvy70BbxI00fZyEPvFHNfxrtEAQQEAQIDADUCAAAAAQAAAAAAAACtAQAAAAAAAAdUE18R96XTJCe+YfRfUp6WP+YKCy/72ucOL8AoBFSpAA==","binary64"]},"id":1} ``` ### getEpochInfo diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index d2d6a084c31be2..78b2322a8e5560 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -226,7 +226,7 @@ pub enum UiTransactionEncoding { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", untagged)] pub enum EncodedTransaction { - LegacyBinary(String), + LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility Binary(String, UiTransactionEncoding), Json(UiTransaction), }