Rework UiAccountData encode/decode such that it works from Rust
This commit is contained in:
parent
2ebc68a9e2
commit
757e147b3b
|
@ -32,17 +32,17 @@ pub struct UiAccount {
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase", untagged)]
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
pub enum UiAccountData {
|
pub enum UiAccountData {
|
||||||
Binary(String),
|
LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility
|
||||||
Json(ParsedAccount),
|
Json(ParsedAccount),
|
||||||
Binary64(String),
|
Binary(String, UiAccountEncoding),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum UiAccountEncoding {
|
pub enum UiAccountEncoding {
|
||||||
Binary, // SLOW! Avoid this encoding
|
Binary, // base-58 encoded string. SLOW! Avoid this encoding
|
||||||
JsonParsed,
|
JsonParsed,
|
||||||
Binary64,
|
Binary64, // base-64 encoded string.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiAccount {
|
impl UiAccount {
|
||||||
|
@ -54,20 +54,23 @@ impl UiAccount {
|
||||||
data_slice_config: Option<UiDataSliceConfig>,
|
data_slice_config: Option<UiDataSliceConfig>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let data = match encoding {
|
let data = match encoding {
|
||||||
UiAccountEncoding::Binary => UiAccountData::Binary(
|
UiAccountEncoding::Binary => UiAccountData::LegacyBinary(
|
||||||
bs58::encode(slice_data(&account.data, data_slice_config)).into_string(),
|
bs58::encode(slice_data(&account.data, data_slice_config)).into_string(),
|
||||||
),
|
),
|
||||||
UiAccountEncoding::Binary64 => UiAccountData::Binary64(base64::encode(slice_data(
|
UiAccountEncoding::Binary64 => UiAccountData::Binary(
|
||||||
&account.data,
|
base64::encode(slice_data(&account.data, data_slice_config)),
|
||||||
data_slice_config,
|
encoding,
|
||||||
))),
|
),
|
||||||
UiAccountEncoding::JsonParsed => {
|
UiAccountEncoding::JsonParsed => {
|
||||||
if let Ok(parsed_data) =
|
if let Ok(parsed_data) =
|
||||||
parse_account_data(pubkey, &account.owner, &account.data, additional_data)
|
parse_account_data(pubkey, &account.owner, &account.data, additional_data)
|
||||||
{
|
{
|
||||||
UiAccountData::Json(parsed_data)
|
UiAccountData::Json(parsed_data)
|
||||||
} else {
|
} 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<Account> {
|
pub fn decode(&self) -> Option<Account> {
|
||||||
let data = match &self.data {
|
let data = match &self.data {
|
||||||
UiAccountData::Json(_) => None,
|
UiAccountData::Json(_) => None,
|
||||||
UiAccountData::Binary(blob) => bs58::decode(blob).into_vec().ok(),
|
UiAccountData::LegacyBinary(blob) => bs58::decode(blob).into_vec().ok(),
|
||||||
UiAccountData::Binary64(blob) => base64::decode(blob).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 {
|
Some(Account {
|
||||||
lamports: self.lamports,
|
lamports: self.lamports,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
validator_info::*,
|
validator_info::*,
|
||||||
vote::*,
|
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 log::*;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use serde_json::{self, json, Value};
|
use serde_json::{self, json, Value};
|
||||||
|
@ -825,13 +825,10 @@ pub fn parse_command(
|
||||||
let encoding = match matches.value_of("encoding").unwrap() {
|
let encoding = match matches.value_of("encoding").unwrap() {
|
||||||
"binary" => UiTransactionEncoding::Binary,
|
"binary" => UiTransactionEncoding::Binary,
|
||||||
"binary64" => UiTransactionEncoding::Binary64,
|
"binary64" => UiTransactionEncoding::Binary64,
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let encoded_transaction = EncodedTransaction::Binary(
|
let encoded_transaction = EncodedTransaction::Binary(blob, encoding);
|
||||||
blob,
|
|
||||||
encoding,
|
|
||||||
);
|
|
||||||
if let Some(transaction) = encoded_transaction.decode() {
|
if let Some(transaction) = encoded_transaction.decode() {
|
||||||
Ok(CliCommandInfo {
|
Ok(CliCommandInfo {
|
||||||
command: CliCommand::DecodeTransaction(transaction),
|
command: CliCommand::DecodeTransaction(transaction),
|
||||||
|
|
|
@ -15,12 +15,7 @@ use bincode::serialize;
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
use log::*;
|
use log::*;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use solana_account_decoder::{
|
use solana_account_decoder::{parse_token::UiTokenAmount, UiAccount, UiAccountEncoding};
|
||||||
parse_token::UiTokenAmount,
|
|
||||||
UiAccount,
|
|
||||||
UiAccountData::{Binary, Binary64},
|
|
||||||
UiAccountEncoding,
|
|
||||||
};
|
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
clock::{
|
clock::{
|
||||||
|
@ -487,17 +482,8 @@ impl RpcClient {
|
||||||
}
|
}
|
||||||
let Response {
|
let Response {
|
||||||
context,
|
context,
|
||||||
value: mut rpc_account,
|
value: rpc_account,
|
||||||
} = serde_json::from_value::<Response<Option<UiAccount>>>(result_json)?;
|
} = serde_json::from_value::<Response<Option<UiAccount>>>(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);
|
trace!("Response account {:?} {:?}", pubkey, rpc_account);
|
||||||
let account = rpc_account.and_then(|rpc_account| rpc_account.decode());
|
let account = rpc_account.and_then(|rpc_account| rpc_account.decode());
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
|
|
|
@ -3097,13 +3097,13 @@ pub mod tests {
|
||||||
"result": {
|
"result": {
|
||||||
"context":{"slot":0},
|
"context":{"slot":0},
|
||||||
"value":{
|
"value":{
|
||||||
"owner": "11111111111111111111111111111111",
|
"owner": "11111111111111111111111111111111",
|
||||||
"lamports": 20,
|
"lamports": 20,
|
||||||
"data": "",
|
"data": "",
|
||||||
"executable": false,
|
"executable": false,
|
||||||
"rentEpoch": 0
|
"rentEpoch": 0
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
"id": 1,
|
"id": 1,
|
||||||
});
|
});
|
||||||
let expected: Response =
|
let expected: Response =
|
||||||
|
@ -3125,7 +3125,10 @@ pub mod tests {
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.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!(
|
let req = format!(
|
||||||
r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary64", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#,
|
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");
|
.expect("actual response deserialization");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result["result"]["value"]["data"],
|
result["result"]["value"]["data"],
|
||||||
base64::encode(&data[1..3]),
|
json!([base64::encode(&data[1..3]), "binary64"]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let req = format!(
|
let req = format!(
|
||||||
|
@ -4315,7 +4318,7 @@ pub mod tests {
|
||||||
for TransactionWithStatusMeta { transaction, meta } in
|
for TransactionWithStatusMeta { transaction, meta } in
|
||||||
confirmed_block.transactions.into_iter()
|
confirmed_block.transactions.into_iter()
|
||||||
{
|
{
|
||||||
if let EncodedTransaction::Binary(transaction) = transaction {
|
if let EncodedTransaction::LegacyBinary(transaction) = transaction {
|
||||||
let decoded_transaction: Transaction =
|
let decoded_transaction: Transaction =
|
||||||
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
|
||||||
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
|
||||||
|
|
|
@ -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
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary64"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// 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
|
#### 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
|
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", "binary64"]}' localhost:8899
|
||||||
|
|
||||||
// Result
|
// 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
|
### getEpochInfo
|
||||||
|
|
|
@ -226,7 +226,7 @@ pub enum UiTransactionEncoding {
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase", untagged)]
|
#[serde(rename_all = "camelCase", untagged)]
|
||||||
pub enum EncodedTransaction {
|
pub enum EncodedTransaction {
|
||||||
LegacyBinary(String),
|
LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility
|
||||||
Binary(String, UiTransactionEncoding),
|
Binary(String, UiTransactionEncoding),
|
||||||
Json(UiTransaction),
|
Json(UiTransaction),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue