diff --git a/Cargo.lock b/Cargo.lock index 97f3184b877d9c..6f73a4d84ee56d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4467,6 +4467,7 @@ name = "solana-transaction-status" version = "1.4.0" dependencies = [ "Inflector", + "base64 0.12.3", "bincode", "bs58", "lazy_static", diff --git a/account-decoder/src/lib.rs b/account-decoder/src/lib.rs index a4d32e5e01ac85..8c1f11caf7009c 100644 --- a/account-decoder/src/lib.rs +++ b/account-decoder/src/lib.rs @@ -32,17 +32,18 @@ pub struct UiAccount { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", untagged)] pub enum UiAccountData { - Binary(String), + LegacyBinary(String), // Legacy. 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, // Legacy. Retained for RPC backwards compatibility + Base58, + Base64, JsonParsed, - Binary64, } impl UiAccount { @@ -54,20 +55,24 @@ 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::Base58 => UiAccountData::Binary( + bs58::encode(slice_data(&account.data, data_slice_config)).into_string(), + encoding, + ), + UiAccountEncoding::Base64 => 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::Base64) } } }; @@ -83,8 +88,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::Base58 => bs58::decode(blob).into_vec().ok(), + UiAccountEncoding::Base64 => base64::decode(blob).ok(), + UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None, + }, }?; Some(Account { lamports: self.lamports, diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 8fd4f6373eb267..38608f626fe66d 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}; +use clap::{value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand}; use log::*; use num_traits::FromPrimitive; use serde_json::{self, json, Value}; @@ -821,9 +821,14 @@ pub fn parse_command( _ => Err(CliError::BadParameter("Invalid signature".to_string())), }, ("decode-transaction", Some(matches)) => { - let encoded_transaction = EncodedTransaction::Binary( - matches.value_of("base58_transaction").unwrap().to_string(), - ); + let blob = value_t_or_exit!(matches, "transaction", String); + let encoding = match matches.value_of("encoding").unwrap() { + "base58" => UiTransactionEncoding::Binary, + "base64" => UiTransactionEncoding::Base64, + _ => unreachable!(), + }; + + let encoded_transaction = EncodedTransaction::Binary(blob, encoding); if let Some(transaction) = encoded_transaction.decode() { Ok(CliCommandInfo { command: CliCommand::DecodeTransaction(transaction), @@ -1068,7 +1073,7 @@ fn process_confirm( if let Some(transaction_status) = status { if config.verbose { match rpc_client - .get_confirmed_transaction(signature, UiTransactionEncoding::Binary) + .get_confirmed_transaction(signature, UiTransactionEncoding::Base64) { Ok(confirmed_transaction) => { println!( @@ -1124,7 +1129,7 @@ fn process_show_account( account: UiAccount::encode( account_pubkey, account, - UiAccountEncoding::Binary64, + UiAccountEncoding::Base64, None, None, ), @@ -2155,12 +2160,22 @@ pub fn app<'ab, 'v>(name: &str, about: &'ab str, version: &'v str) -> App<'ab, ' SubCommand::with_name("decode-transaction") .about("Decode a base-58 binary transaction") .arg( - Arg::with_name("base58_transaction") + Arg::with_name("transaction") .index(1) - .value_name("BASE58_TRANSACTION") + .value_name("TRANSACTION") + .takes_value(true) + .required(true) + .help("transaction to decode"), + ) + .arg( + Arg::with_name("encoding") + .index(2) + .value_name("ENCODING") + .possible_values(&["base58", "base64"]) // Subset of `UiTransactionEncoding` enum + .default_value("base58") .takes_value(true) .required(true) - .help("The transaction to decode"), + .help("transaction encoding"), ), ) .subcommand( diff --git a/cli/src/offline/blockhash_query.rs b/cli/src/offline/blockhash_query.rs index 049c833e88767c..486a0817e56955 100644 --- a/cli/src/offline/blockhash_query.rs +++ b/cli/src/offline/blockhash_query.rs @@ -353,7 +353,7 @@ mod tests { let rpc_nonce_account = UiAccount::encode( &nonce_pubkey, nonce_account, - UiAccountEncoding::Binary64, + UiAccountEncoding::Base64, None, None, ); diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index 0c4f059984b825..72757d12c77c06 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::{ @@ -469,7 +464,7 @@ impl RpcClient { commitment_config: CommitmentConfig, ) -> RpcResult> { let config = RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Binary64), + encoding: Some(UiAccountEncoding::Base64), commitment: Some(commitment_config), data_slice: None, }; @@ -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..513de834143113 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -244,8 +244,11 @@ impl JsonRpcRequestProcessor { if let Some(account) = bank.get_account(pubkey) { if account.owner == spl_token_id_v1_0() && encoding == UiAccountEncoding::JsonParsed { response = Some(get_parsed_token_account(bank.clone(), pubkey, account)); - } else if encoding == UiAccountEncoding::Binary && account.data.len() > 128 { - let message = "Encoded binary (base 58) data should be less than 128 bytes, please use Binary64 encoding.".to_string(); + } else if (encoding == UiAccountEncoding::Binary + || encoding == UiAccountEncoding::Base58) + && account.data.len() > 128 + { + let message = "Encoded binary (base 58) data should be less than 128 bytes, please use Base64 encoding.".to_string(); return Err(error::Error { code: error::ErrorCode::InvalidRequest, message, @@ -1266,7 +1269,7 @@ fn check_slice_and_encoding(encoding: &UiAccountEncoding, data_slice_is_some: bo UiAccountEncoding::JsonParsed => { if data_slice_is_some { let message = - "Sliced account data can only be encoded using binary (base 58) or binary64 encoding." + "Sliced account data can only be encoded using binary (base 58) or base64 encoding." .to_string(); Err(error::Error { code: error::ErrorCode::InvalidRequest, @@ -1277,7 +1280,7 @@ fn check_slice_and_encoding(encoding: &UiAccountEncoding, data_slice_is_some: bo Ok(()) } } - UiAccountEncoding::Binary | UiAccountEncoding::Binary64 => Ok(()), + UiAccountEncoding::Binary | UiAccountEncoding::Base58 | UiAccountEncoding::Base64 => Ok(()), } } @@ -3097,13 +3100,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 = @@ -3119,16 +3122,19 @@ pub mod tests { bank.store_account(&address, &account); let req = format!( - r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary64"}}]}}"#, + r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"base64"}}]}}"#, address ); 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), "base64"]), + ); 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":"base64", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"#, address ); let res = io.handle_request_sync(&req, meta.clone()); @@ -3136,7 +3142,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]), "base64"]), ); let req = format!( @@ -4315,7 +4321,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/core/tests/rpc.rs b/core/tests/rpc.rs index d60a7cad073ef2..9bd5d44d210641 100644 --- a/core/tests/rpc.rs +++ b/core/tests/rpc.rs @@ -103,7 +103,7 @@ fn test_rpc_send_tx() { use solana_account_decoder::UiAccountEncoding; use solana_client::rpc_config::RpcAccountInfoConfig; let config = RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Binary64), + encoding: Some(UiAccountEncoding::Base64), commitment: None, data_slice: None, }; diff --git a/docs/src/apps/jsonrpc-api.md b/docs/src/apps/jsonrpc-api.md index 781f1291fc936d..307ff2aabea342 100644 --- a/docs/src/apps/jsonrpc-api.md +++ b/docs/src/apps/jsonrpc-api.md @@ -157,9 +157,9 @@ Returns all information associated with the account of provided Pubkey - `` - Pubkey of account to query, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary", "binary64", or jsonParsed". If parameter not provided, the default encoding is "binary". "binary" is base-58 encoded and limited to Account data of less than 128 bytes. "binary64" will return base64 encoded data for Account data of any size. - Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** - - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "binary" or "binary64" encoding. + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64", or jsonParsed". "base58" is limited to Account data of less than 128 bytes. "base64" will return base64 encoded data for Account data of any size. + Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** + - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "base58" or "base64" encoding. #### Results: @@ -169,7 +169,7 @@ The result will be an RpcResponse JSON object with `value` equal to: - `` - otherwise, a JSON object containing: - `lamports: `, number of lamports assigned to this account, as a u64 - `owner: `, base-58 encoded Pubkey of the program this account has been assigned to - - `data: `, data associated with the account, either as base-58 encoded binary data or JSON format `{: }`, depending on encoding parameter + - `data: <[string, encoding]|object>`, data associated with the account, either as encoded binary data or JSON format `{: }`, depending on encoding parameter - `executable: `, boolean indicating if the account contains a program \(and is strictly read-only\) - `rentEpoch: `, the epoch at which this account will next owe rent, as u64 @@ -177,10 +177,10 @@ The result will be an RpcResponse JSON object with `value` equal to: ```bash // Request -curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA"]}' http://localhost:8899 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",{"encoding": "base58"}]}' http://localhost:8899 // Result -{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"data":"11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf","executable":false,"lamports":1000000000,"owner":"11111111111111111111111111111111","rentEpoch":2}},"id":1} +{"jsonrpc":"2.0","result":{"context":{"slot":1},"value":{"data":["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHRTPuR3oZ1EioKtYGiYxpxMG5vpbZLsbcBYBEmZZcMKaSoGx9JZeAuWf","base58"],"executable":false,"lamports":1000000000,"owner":"11111111111111111111111111111111","rentEpoch":2}},"id":1} // Request curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getAccountInfo", "params":["4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",{"encoding":"json"}]}' http://localhost:8899 @@ -307,7 +307,7 @@ Returns identity and transaction information about a confirmed block in the ledg #### Parameters: - `` - slot, as u64 integer -- `` - (optional) encoding for each returned Transaction, either "json", "jsonParsed", or "binary". If parameter not provided, the default encoding is JSON. **jsonParsed encoding is UNSTABLE** +- `` - encoding for each returned Transaction, either "json", "jsonParsed", "base58" (*slow*), or "base64". If parameter not provided, the default encoding is JSON. **jsonParsed encoding is UNSTABLE** Parsed-JSON encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields). #### Results: @@ -320,7 +320,7 @@ The result field will be an object with the following fields: - `previousBlockhash: ` - the blockhash of this block's parent, as base-58 encoded string; if the parent block is not available due to ledger cleanup, this field will return "11111111111111111111111111111111" - `parentSlot: ` - the slot index of this block's parent - `transactions: ` - an array of JSON objects containing: - - `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter + - `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or encoded binary data, depending on encoding parameter - `meta: ` - transaction status metadata object, containing `null` or: - `err: ` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14) - `fee: ` - fee this transaction was charged, as u64 integer @@ -341,13 +341,13 @@ The result field will be an object with the following fields: curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "json"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"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":{"message":{"accountKeys":["3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe","AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1","programIdIndex":4}],"recentBlockhash":"mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"},"signatures":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"]}}]},"id":1} // Request -curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "binary"]}' localhost:8899 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[430, "base64"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"blockhash":"Gp3t5bfDsJv1ovP8cB1SuRhXVuoTqDv7p3tymyubYg5","parentSlot":429,"previousBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA","transactions":[{"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}}]},"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==","base64"]}]},"id":1} ``` #### Transaction Structure @@ -465,14 +465,14 @@ Returns transaction details for a confirmed transaction - `` - transaction signature as base-58 encoded string N encoding attempts to use program-specific instruction parsers to return more human-readable and explicit data in the `transaction.message.instructions` list. If parsed-JSON is requested but a parser cannot be found, the instruction falls back to regular JSON encoding (`accounts`, `data`, and `programIdIndex` fields). -- `` - (optional) encoding for the returned Transaction, either "json", "jsonParsed", or "binary". **jsonParsed encoding is UNSTABLE** +- `` - (optional) encoding for the returned Transaction, either "json", "jsonParsed", "base58" (*slow*), or "base64". If parameter not provided, the default encoding is JSON. **jsonParsed encoding is UNSTABLE** #### Results: - `` - if transaction is not found or not confirmed - `` - if transaction is confirmed, an object with the following fields: - `slot: ` - the slot this transaction was processed in - - `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or base-58 encoded binary data, depending on encoding parameter + - `transaction: ` - [Transaction](#transaction-structure) object, either in JSON format or encoded binary data, depending on encoding parameter - `meta: ` - transaction status metadata object: - `err: ` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/master/sdk/src/transaction.rs#L14) - `fee: ` - fee this transaction was charged, as u64 integer @@ -486,16 +486,16 @@ N encoding attempts to use program-specific instruction parsers to return more h ```bash // Request -curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", "json"]}' localhost:8899 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", "json"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"slot":430,"transaction":{"message":{"accountKeys":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC","39UAy8hsoYPywGPGdmun747omSr79zLSjqvPJN3zetoH","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":2},"instructions":[{"accounts":[1,2,3],"data":"29z5mr1JoRmJYQ6ynmk3pf31cGFRziAF1M3mT3L6sFXf5cKLdkEaMXMT8AqLpD4CpcupHmuMEmtZHpomrwfdZetSomNy3d","programIdIndex":4}],"recentBlockhash":"EFejToxii1L5aUF2NrK9dsbAEmZSNyN5nsipmZHQR1eA"},"signatures":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4vANMjSKiwEchGSXwVrQkwHnmsbKQmy9vdrsYxWdCup1bLsFzX8gKrFTSVDCZCae2dbxJB9mPNhqB2sD1vvr4sAD"]},"meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}},"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":{"message":{"accountKeys":["3UVYmECPPMZSCqWKfENfuoTv51fTDTWicX9xmBD2euKe","AjozzgE83A3x1sHNUR64hfH7zaEBWeMaFuAN9kQgujrc","SysvarS1otHashes111111111111111111111111111","SysvarC1ock11111111111111111111111111111111","Vote111111111111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":3,"numRequiredSignatures":1},"instructions":[{"accounts":[1,2,3,0],"data":"37u9WtQpcm6ULa3WRQHmj49EPs4if7o9f1jSRVZpm2dvihR9C8jY4NqEwXUbLwx15HBSNcP1","programIdIndex":4}],"recentBlockhash":"mfcyqEXB3DnHXki6KjjmZck6YjmZLvpAByy2fj4nh6B"},"signatures":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"]}},"id":1} // Request -curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby", "binary"]}' localhost:8899 +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv", "base64"]}' localhost:8899 // Result -{"jsonrpc":"2.0","result":{"slot":430,"transaction":"81UZJt4dh4Do66jDhrgkQudS8J2N6iG3jaVav7gJrqJSFY4Ug53iA9JFJZh2gxKWcaFdLJwhHx9mRdg9JwDAWB4ywiu5154CRwXV4FMdnPLg7bhxRLwhhYaLsVgMF5AyNRcTzjCVoBvqFgDU7P8VEKDEiMvD3qxzm1pLZVxDG1LTQpT3Dz4Uviv4KQbFQNuC22KupBoyHFB7Zh6KFdMqux4M9PvhoqcoJsJKwXjWpKu7xmEKnnrSbfLadkgjBmmjhW3fdTrFvnhQdTkhtdJxUL1xS9GMuJQer8YgSKNtUXB1eXZQwXU8bU2BjYkZE6Q5Xww8hu9Z4E4Mo4QsooVtHoP6BM3NKw8zjVbWfoCQqxTrwuSzrNCWCWt58C24LHecH67CTt2uXbYSviixvrYkK7A3t68BxTJcF1dXJitEPTFe2ceTkauLJqrJgnER4iUrsjr26T8YgWvpY9wkkWFSviQW6wV5RASTCUasVEcrDiaKj8EQMkgyDoe9HyKitSVg67vMWJFpUXpQobseWJUs5FTWWzmfHmFp8FZ","meta":{"err":null,"fee":18000,"postBalances":[499999972500,15298080,1,1,1],"preBalances":[499999990500,15298080,1,1,1],"status":{"Ok":null}}},"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==","base64"]},"id":1} ``` ### getEpochInfo @@ -845,9 +845,9 @@ Returns all accounts owned by the provided program Pubkey - `` - Pubkey of program, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary. - Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** - - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "binary" or "binary64" encoding. + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64" or jsonParsed". + Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** + - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "base58" or "base64" encoding. - (optional) `filters: ` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results ##### Filters: @@ -865,7 +865,7 @@ The result field will be an array of JSON objects, which will contain: - `account: ` - a JSON object, with the following sub fields: - `lamports: `, number of lamports assigned to this account, as a u64 - `owner: `, base-58 encoded Pubkey of the program this account has been assigned to - `data: `, data associated with the account, either as base-58 encoded binary data or JSON format `{: }`, depending on encoding parameter + `data: <[string,encoding]|object>`, data associated with the account, either as encoded binary data or JSON format `{: }`, depending on encoding parameter - `executable: `, boolean indicating if the account contains a program \(and is strictly read-only\) - `rentEpoch: `, the epoch at which this account will next owe rent, as u64 @@ -1100,9 +1100,9 @@ Returns all SPL Token accounts by approved Delegate. **UNSTABLE** * `programId: ` - Pubkey of the Token program ID that owns the accounts, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary. + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64" or jsonParsed". Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** - - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "binary" or "binary64" encoding. + - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "base58" or "base64" encoding. #### Results: @@ -1112,7 +1112,7 @@ The result will be an RpcResponse JSON object with `value` equal to an array of - `account: ` - a JSON object, with the following sub fields: - `lamports: `, number of lamports assigned to this account, as a u64 - `owner: `, base-58 encoded Pubkey of the program this account has been assigned to - - `data: `, Token state data associated with the account, either as base-58 encoded binary data or in JSON format `{: }` + - `data: `, Token state data associated with the account, either as encoded binary data or in JSON format `{: }` - `executable: `, boolean indicating if the account contains a program \(and is strictly read-only\) - `rentEpoch: `, the epoch at which this account will next owe rent, as u64 @@ -1137,9 +1137,9 @@ Returns all SPL Token accounts by token owner. **UNSTABLE** * `programId: ` - Pubkey of the Token program ID that owns the accounts, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary. + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64" or jsonParsed". Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** - - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "binary" or "binary64" encoding. + - (optional) `dataSlice: ` - limit the returned account data using the provided `offset: ` and `length: ` fields; only available for "base58" or "base64" encoding. #### Results: @@ -1149,7 +1149,7 @@ The result will be an RpcResponse JSON object with `value` equal to an array of - `account: ` - a JSON object, with the following sub fields: - `lamports: `, number of lamports assigned to this account, as a u64 - `owner: `, base-58 encoded Pubkey of the program this account has been assigned to - - `data: `, Token state data associated with the account, either as base-58 encoded binary data or in JSON format `{: }` + - `data: `, Token state data associated with the account, either as encoded binary data or in JSON format `{: }` - `executable: `, boolean indicating if the account contains a program \(and is strictly read-only\) - `rentEpoch: `, the epoch at which this account will next owe rent, as u64 @@ -1457,7 +1457,7 @@ Subscribe to an account to receive notifications when the lamports or data for a - `` - account Pubkey, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - `` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary. + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64" or jsonParsed". Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** #### Results: @@ -1468,9 +1468,9 @@ Subscribe to an account to receive notifications when the lamports or data for a ```bash // Request -{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12"]} +{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", {"encoding":"base58"}]} -{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", {"commitment": "single"}]} +{"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", {"encoding":"base64", "commitment": "single"}]} {"jsonrpc":"2.0", "id":1, "method":"accountSubscribe", "params":["CM78CPUeXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNH12", {"encoding":"jsonParsed"}]} @@ -1481,7 +1481,7 @@ Subscribe to an account to receive notifications when the lamports or data for a #### Notification Format: ```bash -// Binary encoding +// Base58 encoding { "jsonrpc": "2.0", "method": "accountNotification", @@ -1491,7 +1491,7 @@ Subscribe to an account to receive notifications when the lamports or data for a "slot": 5199307 }, "value": { - "data": "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], "executable": false, "lamports": 33594, "owner": "11111111111111111111111111111111", @@ -1567,8 +1567,8 @@ Subscribe to a program to receive notifications when the lamports or data for a - `` - program_id Pubkey, as base-58 encoded string - `` - (optional) Configuration object containing the following optional fields: - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment) - - (optional) `encoding: ` - encoding for Account data, either "binary" or jsonParsed". If parameter not provided, the default encoding is binary. - Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to binary encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** + - `encoding: ` - encoding for Account data, either "base58" (*slow*), "base64" or jsonParsed". + Parsed-JSON encoding attempts to use program-specific state parsers to return more human-readable and explicit account state data. If parsed-JSON is requested but a parser cannot be found, the field falls back to base64 encoding, detectable when the `data` field is type ``. **jsonParsed encoding is UNSTABLE** - (optional) `filters: ` - filter results using various [filter objects](jsonrpc-api.md#filters); account must meet all filter criteria to be included in results #### Results: @@ -1579,13 +1579,11 @@ Subscribe to a program to receive notifications when the lamports or data for a ```bash // Request -{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111"]} - -{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111", {"commitment": "single"}]} +{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111", {"encoding":"base64", "commitment": "single"}]} {"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111", {"encoding":"jsonParsed"}]} -{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111", {"filters":[{"dataSize":80}]}]} +{"jsonrpc":"2.0", "id":1, "method":"programSubscribe", "params":["11111111111111111111111111111111", {"encoding":"base64", "filters":[{"dataSize":80}]}]} // Result {"jsonrpc": "2.0","result": 24040,"id": 1} @@ -1594,7 +1592,7 @@ Subscribe to a program to receive notifications when the lamports or data for a #### Notification Format: ```bash -// Binary encoding +// Base58 encoding { "jsonrpc": "2.0", "method": "programNotification", @@ -1606,7 +1604,7 @@ Subscribe to a program to receive notifications when the lamports or data for a "value": { "pubkey": "H4vnBqifaSACnKa7acsxstsY1iV1bvJNxsCY7enrd1hq" "account": { - "data": "11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", + "data": ["11116bv5nS2h3y12kD1yUKeMZvGcKLSjQgX6BeV7u1FrjeJcKfsHPXHRDEHrBesJhZyqnnq9qJeUuF7WHxiuLuL5twc38w2TXNLxnDbjmuR", "base58"], "executable": false, "lamports": 33594, "owner": "11111111111111111111111111111111", diff --git a/ledger-tool/src/bigtable.rs b/ledger-tool/src/bigtable.rs index db70f7283fd614..3f137f1d3e19d2 100644 --- a/ledger-tool/src/bigtable.rs +++ b/ledger-tool/src/bigtable.rs @@ -134,7 +134,7 @@ async fn upload( for (i, slot) in blocks_to_upload.iter().enumerate() { let _ = match blockstore.get_confirmed_block( *slot, - Some(solana_transaction_status::UiTransactionEncoding::Binary), + Some(solana_transaction_status::UiTransactionEncoding::Base64), ) { Ok(confirmed_block) => sender.send((*slot, Some(confirmed_block))), Err(err) => { @@ -231,7 +231,7 @@ async fn block(slot: Slot) -> Result<(), Box> { .map_err(|err| format!("Failed to connect to storage: {:?}", err))?; let block = bigtable - .get_confirmed_block(slot, UiTransactionEncoding::Binary) + .get_confirmed_block(slot, UiTransactionEncoding::Base64) .await?; println!("Slot: {}", slot); @@ -276,7 +276,7 @@ async fn confirm(signature: &Signature, verbose: bool) -> Result<(), Box { diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 82cd9a551e037a..abfab778cb3f09 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -1959,7 +1959,7 @@ impl Blockstore { None => return Ok(vec![]), Some((slot, _)) => { let confirmed_block = self - .get_confirmed_block(slot, Some(UiTransactionEncoding::Binary)) + .get_confirmed_block(slot, Some(UiTransactionEncoding::Base64)) .map_err(|err| { BlockstoreError::IO(IOError::new( ErrorKind::Other, @@ -2013,7 +2013,7 @@ impl Blockstore { None => (0, HashSet::new()), Some((slot, _)) => { let confirmed_block = self - .get_confirmed_block(slot, Some(UiTransactionEncoding::Binary)) + .get_confirmed_block(slot, Some(UiTransactionEncoding::Base64)) .map_err(|err| { BlockstoreError::IO(IOError::new( ErrorKind::Other, diff --git a/stake-monitor/src/lib.rs b/stake-monitor/src/lib.rs index 09eebfdff46b8b..d4ee6a6fb239f6 100644 --- a/stake-monitor/src/lib.rs +++ b/stake-monitor/src/lib.rs @@ -267,6 +267,8 @@ fn process_confirmed_block( ("err", "Transaction signature verification failed", String) ); } + } else { + error!("Transaction decode failed"); } } } @@ -289,7 +291,7 @@ fn load_blocks( let mut blocks = vec![]; for slot in slots.into_iter() { let block = - rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Binary)?; + rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?; blocks.push((slot, block)); } Ok(blocks) diff --git a/transaction-status/Cargo.toml b/transaction-status/Cargo.toml index 83de415c85f326..3399b7553de29e 100644 --- a/transaction-status/Cargo.toml +++ b/transaction-status/Cargo.toml @@ -9,6 +9,7 @@ license = "Apache-2.0" edition = "2018" [dependencies] +base64 = "0.12.3" bincode = "1.3.1" bs58 = "0.3.1" Inflector = "0.11.4" diff --git a/transaction-status/src/lib.rs b/transaction-status/src/lib.rs index 6044ee1193237b..063ef61203e048 100644 --- a/transaction-status/src/lib.rs +++ b/transaction-status/src/lib.rs @@ -217,7 +217,9 @@ pub struct TransactionWithStatusMeta { #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub enum UiTransactionEncoding { - Binary, + Binary, // Legacy. Retained for RPC backwards compatibility + Base64, + Base58, Json, JsonParsed, } @@ -225,17 +227,26 @@ pub enum UiTransactionEncoding { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase", untagged)] pub enum EncodedTransaction { - Binary(String), + LegacyBinary(String), // Old way of expressing base-58, retained for RPC backwards compatibility + Binary(String, UiTransactionEncoding), Json(UiTransaction), } impl EncodedTransaction { pub fn encode(transaction: Transaction, encoding: UiTransactionEncoding) -> Self { match encoding { - UiTransactionEncoding::Binary => EncodedTransaction::Binary( + UiTransactionEncoding::Binary => EncodedTransaction::LegacyBinary( bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(), ), - _ => { + UiTransactionEncoding::Base58 => EncodedTransaction::Binary( + bs58::encode(bincode::serialize(&transaction).unwrap()).into_string(), + encoding, + ), + UiTransactionEncoding::Base64 => EncodedTransaction::Binary( + base64::encode(bincode::serialize(&transaction).unwrap()), + encoding, + ), + UiTransactionEncoding::Json | UiTransactionEncoding::JsonParsed => { let message = if encoding == UiTransactionEncoding::Json { UiMessage::Raw(UiRawMessage { header: transaction.message.header, @@ -298,10 +309,22 @@ impl EncodedTransaction { pub fn decode(&self) -> Option { match self { EncodedTransaction::Json(_) => None, - EncodedTransaction::Binary(blob) => bs58::decode(blob) + EncodedTransaction::LegacyBinary(blob) => bs58::decode(blob) .into_vec() .ok() .and_then(|bytes| bincode::deserialize(&bytes).ok()), + EncodedTransaction::Binary(blob, encoding) => match *encoding { + UiTransactionEncoding::Base58 => bs58::decode(blob) + .into_vec() + .ok() + .and_then(|bytes| bincode::deserialize(&bytes).ok()), + UiTransactionEncoding::Base64 => base64::decode(blob) + .ok() + .and_then(|bytes| bincode::deserialize(&bytes).ok()), + UiTransactionEncoding::Binary + | UiTransactionEncoding::Json + | UiTransactionEncoding::JsonParsed => None, + }, } } } diff --git a/watchtower/src/main.rs b/watchtower/src/main.rs index 874aaa7d612769..67e22b00c54dc4 100644 --- a/watchtower/src/main.rs +++ b/watchtower/src/main.rs @@ -226,7 +226,7 @@ fn load_blocks( let mut blocks = vec![]; for slot in slots.into_iter() { let block = - rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Binary)?; + rpc_client.get_confirmed_block_with_encoding(slot, UiTransactionEncoding::Base64)?; blocks.push((slot, block)); } Ok(blocks)