From 0cdaf5f8d9c05e3272822f4d9c56882e72ba28fd Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 29 Jun 2020 22:41:51 -0600 Subject: [PATCH] Add account-decoder crate and use to decode vote and system (nonce) accounts --- Cargo.lock | 22 +++++ Cargo.toml | 1 + account-decoder/Cargo.toml | 25 +++++ account-decoder/src/lib.rs | 80 +++++++++++++++ account-decoder/src/parse_account_data.rs | 51 ++++++++++ account-decoder/src/parse_nonce.rs | 35 +++++++ account-decoder/src/parse_vote.rs | 113 ++++++++++++++++++++++ cli/Cargo.toml | 1 + cli/src/cli.rs | 5 +- cli/src/offline/blockhash_query.rs | 5 +- client/Cargo.toml | 3 +- client/src/rpc_client.rs | 3 +- client/src/rpc_config.rs | 9 ++ client/src/rpc_response.rs | 44 +-------- core/Cargo.toml | 5 +- core/src/rpc.rs | 35 ++++--- core/src/rpc_pubsub.rs | 5 +- core/src/rpc_subscriptions.rs | 13 ++- core/tests/rpc.rs | 3 +- 19 files changed, 389 insertions(+), 69 deletions(-) create mode 100644 account-decoder/Cargo.toml create mode 100644 account-decoder/src/lib.rs create mode 100644 account-decoder/src/parse_account_data.rs create mode 100644 account-decoder/src/parse_nonce.rs create mode 100644 account-decoder/src/parse_vote.rs diff --git a/Cargo.lock b/Cargo.lock index 4834e8e04d..21b3f10c50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3629,6 +3629,23 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "solana-account-decoder" +version = "1.3.0" +dependencies = [ + "Inflector", + "bincode", + "bs58 0.3.1", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-sdk 1.3.0", + "solana-vote-program", + "spl-memo", + "thiserror", +] + [[package]] name = "solana-accounts-bench" version = "1.3.0" @@ -3816,6 +3833,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "solana-account-decoder", "solana-budget-program", "solana-clap-utils", "solana-cli-config", @@ -3866,6 +3884,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "solana-account-decoder", "solana-logger", "solana-net-utils", "solana-sdk 1.3.0", @@ -3925,6 +3944,7 @@ dependencies = [ "serde_json", "serial_test", "serial_test_derive", + "solana-account-decoder", "solana-bpf-loader-program", "solana-budget-program", "solana-clap-utils", @@ -4792,6 +4812,8 @@ dependencies = [ "serde_derive", "serde_json", "solana-sdk 1.3.0", + "solana-stake-program", + "solana-vote-program", "spl-memo", ] diff --git a/Cargo.toml b/Cargo.toml index 7879451cd6..b103370cee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ members = [ "sys-tuner", "tokens", "transaction-status", + "account-decoder", "upload-perf", "net-utils", "version", diff --git a/account-decoder/Cargo.toml b/account-decoder/Cargo.toml new file mode 100644 index 0000000000..909a8ced11 --- /dev/null +++ b/account-decoder/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "solana-account-decoder" +version = "1.3.0" +description = "Solana account decoder" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +homepage = "https://solana.com/" +license = "Apache-2.0" +edition = "2018" + +[dependencies] +bincode = "1.2.1" +bs58 = "0.3.1" +Inflector = "0.11.4" +lazy_static = "1.4.0" +solana-sdk = { path = "../sdk", version = "1.3.0" } +solana-vote-program = { path = "../programs/vote", version = "1.3.0" } +spl-memo = "1.0.0" +serde = "1.0.112" +serde_derive = "1.0.103" +serde_json = "1.0.54" +thiserror = "1.0" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/account-decoder/src/lib.rs b/account-decoder/src/lib.rs new file mode 100644 index 0000000000..8f247979d3 --- /dev/null +++ b/account-decoder/src/lib.rs @@ -0,0 +1,80 @@ +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate serde_derive; + +pub mod parse_account_data; +pub mod parse_nonce; +pub mod parse_vote; + +use crate::parse_account_data::parse_account_data; +use serde_json::Value; +use solana_sdk::{account::Account, clock::Epoch, pubkey::Pubkey}; +use std::str::FromStr; + +/// A duplicate representation of a Message for pretty JSON serialization +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RpcAccount { + pub lamports: u64, + pub data: EncodedAccount, + pub owner: String, + pub executable: bool, + pub rent_epoch: Epoch, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase", untagged)] +pub enum EncodedAccount { + Binary(String), + Json(Value), +} + +impl From> for EncodedAccount { + fn from(data: Vec) -> Self { + Self::Binary(bs58::encode(data).into_string()) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[serde(rename_all = "camelCase")] +pub enum AccountEncoding { + Binary, + Json, +} + +impl RpcAccount { + pub fn encode(account: Account, encoding: AccountEncoding) -> Self { + let data = match encoding { + AccountEncoding::Binary => account.data.into(), + AccountEncoding::Json => { + if let Ok(parsed_data) = parse_account_data(&account.owner, &account.data) { + EncodedAccount::Json(parsed_data) + } else { + account.data.into() + } + } + }; + RpcAccount { + lamports: account.lamports, + data, + owner: account.owner.to_string(), + executable: account.executable, + rent_epoch: account.rent_epoch, + } + } + + pub fn decode(&self) -> Option { + let data = match &self.data { + EncodedAccount::Json(_) => None, + EncodedAccount::Binary(blob) => bs58::decode(blob).into_vec().ok(), + }?; + Some(Account { + lamports: self.lamports, + data, + owner: Pubkey::from_str(&self.owner).ok()?, + executable: self.executable, + rent_epoch: self.rent_epoch, + }) + } +} diff --git a/account-decoder/src/parse_account_data.rs b/account-decoder/src/parse_account_data.rs new file mode 100644 index 0000000000..901a20a0cd --- /dev/null +++ b/account-decoder/src/parse_account_data.rs @@ -0,0 +1,51 @@ +use crate::{parse_nonce::parse_nonce, parse_vote::parse_vote}; +use inflector::Inflector; +use serde_json::{json, Value}; +use solana_sdk::{instruction::InstructionError, pubkey::Pubkey, system_program}; +use std::{collections::HashMap, str::FromStr}; +use thiserror::Error; + +lazy_static! { + static ref SYSTEM_PROGRAM_ID: Pubkey = + Pubkey::from_str(&system_program::id().to_string()).unwrap(); + static ref VOTE_PROGRAM_ID: Pubkey = + Pubkey::from_str(&solana_vote_program::id().to_string()).unwrap(); + pub static ref PARSABLE_PROGRAM_IDS: HashMap = { + let mut m = HashMap::new(); + m.insert(*SYSTEM_PROGRAM_ID, ParsableAccount::Nonce); + m.insert(*VOTE_PROGRAM_ID, ParsableAccount::Vote); + m + }; +} + +#[derive(Error, Debug)] +pub enum ParseAccountError { + #[error("Program not parsable")] + ProgramNotParsable, + + #[error("Instruction error")] + InstructionError(#[from] InstructionError), + + #[error("Serde json error")] + SerdeJsonError(#[from] serde_json::error::Error), +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ParsableAccount { + Nonce, + Vote, +} + +pub fn parse_account_data(program_id: &Pubkey, data: &[u8]) -> Result { + let program_name = PARSABLE_PROGRAM_IDS + .get(program_id) + .ok_or_else(|| ParseAccountError::ProgramNotParsable)?; + let parsed_json = match program_name { + ParsableAccount::Nonce => serde_json::to_value(parse_nonce(data)?)?, + ParsableAccount::Vote => serde_json::to_value(parse_vote(data)?)?, + }; + Ok(json!({ + format!("{:?}", program_name).to_kebab_case(): parsed_json + })) +} diff --git a/account-decoder/src/parse_nonce.rs b/account-decoder/src/parse_nonce.rs new file mode 100644 index 0000000000..4726e2b16b --- /dev/null +++ b/account-decoder/src/parse_nonce.rs @@ -0,0 +1,35 @@ +use crate::parse_account_data::ParseAccountError; +use solana_sdk::{ + fee_calculator::FeeCalculator, + instruction::InstructionError, + nonce::{state::Versions, State}, +}; + +pub fn parse_nonce(data: &[u8]) -> Result { + let nonce_state: Versions = bincode::deserialize(data) + .map_err(|_| ParseAccountError::from(InstructionError::InvalidAccountData))?; + let nonce_state = nonce_state.convert_to_current(); + match nonce_state { + State::Uninitialized => Ok(RpcNonceState::Uninitialized), + State::Initialized(data) => Ok(RpcNonceState::Initialized(RpcNonceData { + authority: data.authority.to_string(), + blockhash: data.blockhash.to_string(), + fee_calculator: data.fee_calculator, + })), + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum RpcNonceState { + Uninitialized, + Initialized(RpcNonceData), +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RpcNonceData { + pub authority: String, + pub blockhash: String, + pub fee_calculator: FeeCalculator, +} diff --git a/account-decoder/src/parse_vote.rs b/account-decoder/src/parse_vote.rs new file mode 100644 index 0000000000..fd91c3a592 --- /dev/null +++ b/account-decoder/src/parse_vote.rs @@ -0,0 +1,113 @@ +use crate::parse_account_data::ParseAccountError; +use solana_sdk::{ + clock::{Epoch, Slot}, + pubkey::Pubkey, +}; +use solana_vote_program::vote_state::{BlockTimestamp, Lockout, VoteState}; + +pub fn parse_vote(data: &[u8]) -> Result { + let mut vote_state = VoteState::deserialize(data).map_err(ParseAccountError::from)?; + let epoch_credits = vote_state + .epoch_credits() + .iter() + .map(|(epoch, credits, previous_credits)| RpcEpochCredits { + epoch: *epoch, + credits: *credits, + previous_credits: *previous_credits, + }) + .collect(); + let votes = vote_state + .votes + .iter() + .map(|lockout| RpcLockout { + slot: lockout.slot, + confirmation_count: lockout.confirmation_count, + }) + .collect(); + let authorized_voters = vote_state + .authorized_voters() + .iter() + .map(|(epoch, authorized_voter)| RpcAuthorizedVoters { + epoch: *epoch, + authorized_voter: authorized_voter.to_string(), + }) + .collect(); + let prior_voters = vote_state + .prior_voters() + .buf() + .iter() + .filter(|(pubkey, _, _)| pubkey != &Pubkey::default()) + .map( + |(authorized_pubkey, epoch_of_last_authorized_switch, target_epoch)| RpcPriorVoters { + authorized_pubkey: authorized_pubkey.to_string(), + epoch_of_last_authorized_switch: *epoch_of_last_authorized_switch, + target_epoch: *target_epoch, + }, + ) + .collect(); + Ok(RpcVoteState { + node_pubkey: vote_state.node_pubkey.to_string(), + authorized_withdrawer: vote_state.authorized_withdrawer.to_string(), + commission: vote_state.commission, + votes, + root_slot: vote_state.root_slot, + authorized_voters, + prior_voters, + epoch_credits, + last_timestamp: vote_state.last_timestamp, + }) +} + +/// A duplicate representation of VoteState for pretty JSON serialization +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RpcVoteState { + node_pubkey: String, + authorized_withdrawer: String, + commission: u8, + votes: Vec, + root_slot: Option, + authorized_voters: Vec, + prior_voters: Vec, + epoch_credits: Vec, + last_timestamp: BlockTimestamp, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RpcLockout { + slot: Slot, + confirmation_count: u32, +} + +impl From<&Lockout> for RpcLockout { + fn from(lockout: &Lockout) -> Self { + Self { + slot: lockout.slot, + confirmation_count: lockout.confirmation_count, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RpcAuthorizedVoters { + epoch: Epoch, + authorized_voter: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RpcPriorVoters { + authorized_pubkey: String, + epoch_of_last_authorized_switch: Epoch, + target_epoch: Epoch, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RpcEpochCredits { + epoch: Epoch, + credits: u64, + previous_credits: u64, +} diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 62ae1eefb0..2746280f60 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -27,6 +27,7 @@ reqwest = { version = "0.10.6", default-features = false, features = ["blocking" serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.54" +solana-account-decoder = { path = "../account-decoder", version = "1.3.0" } solana-budget-program = { path = "../programs/budget", version = "1.3.0" } solana-clap-utils = { path = "../clap-utils", version = "1.3.0" } solana-cli-config = { path = "../cli-config", version = "1.3.0" } diff --git a/cli/src/cli.rs b/cli/src/cli.rs index d30bc94e59..8bc8f64bcf 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -15,6 +15,7 @@ use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; use log::*; use num_traits::FromPrimitive; use serde_json::{self, json, Value}; +use solana_account_decoder::{AccountEncoding, RpcAccount}; use solana_budget_program::budget_instruction::{self, BudgetError}; use solana_clap_utils::{ commitment::commitment_arg_with_default, input_parsers::*, input_validators::*, @@ -24,7 +25,7 @@ use solana_client::{ client_error::{ClientError, ClientErrorKind, Result as ClientResult}, rpc_client::RpcClient, rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig}, - rpc_response::{RpcAccount, RpcKeyedAccount}, + rpc_response::RpcKeyedAccount, }; #[cfg(not(test))] use solana_faucet::faucet::request_airdrop_transaction; @@ -1225,7 +1226,7 @@ fn process_show_account( let cli_account = CliAccount { keyed_account: RpcKeyedAccount { pubkey: account_pubkey.to_string(), - account: RpcAccount::encode(account), + account: RpcAccount::encode(account, AccountEncoding::Binary), }, use_lamports_unit, }; diff --git a/cli/src/offline/blockhash_query.rs b/cli/src/offline/blockhash_query.rs index 5765a13c4c..ab40a5266f 100644 --- a/cli/src/offline/blockhash_query.rs +++ b/cli/src/offline/blockhash_query.rs @@ -111,9 +111,10 @@ mod tests { use crate::{nonce::nonce_arg, offline::blockhash_query::BlockhashQuery}; use clap::App; use serde_json::{self, json, Value}; + use solana_account_decoder::{AccountEncoding, RpcAccount}; use solana_client::{ rpc_request::RpcRequest, - rpc_response::{Response, RpcAccount, RpcFeeCalculator, RpcResponseContext}, + rpc_response::{Response, RpcFeeCalculator, RpcResponseContext}, }; use solana_sdk::{ account::Account, fee_calculator::FeeCalculator, hash::hash, nonce, system_program, @@ -349,7 +350,7 @@ mod tests { ) .unwrap(); let nonce_pubkey = Pubkey::new(&[4u8; 32]); - let rpc_nonce_account = RpcAccount::encode(nonce_account); + let rpc_nonce_account = RpcAccount::encode(nonce_account, AccountEncoding::Binary); let get_account_response = json!(Response { context: RpcResponseContext { slot: 1 }, value: json!(Some(rpc_nonce_account)), diff --git a/client/Cargo.toml b/client/Cargo.toml index 827cd048c9..95e3bd2ea6 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -19,9 +19,10 @@ reqwest = { version = "0.10.6", default-features = false, features = ["blocking" serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.54" -solana-transaction-status = { path = "../transaction-status", version = "1.3.0" } +solana-account-decoder = { path = "../account-decoder", version = "1.3.0" } solana-net-utils = { path = "../net-utils", version = "1.3.0" } solana-sdk = { path = "../sdk", version = "1.3.0" } +solana-transaction-status = { path = "../transaction-status", version = "1.3.0" } solana-vote-program = { path = "../programs/vote", version = "1.3.0" } thiserror = "1.0" tungstenite = "0.10.1" diff --git a/client/src/rpc_client.rs b/client/src/rpc_client.rs index de0c2c5967..3117573ce0 100644 --- a/client/src/rpc_client.rs +++ b/client/src/rpc_client.rs @@ -11,6 +11,7 @@ use bincode::serialize; use indicatif::{ProgressBar, ProgressStyle}; use log::*; use serde_json::{json, Value}; +use solana_account_decoder::RpcAccount; use solana_sdk::{ account::Account, clock::{ @@ -442,7 +443,7 @@ impl RpcClient { value: rpc_account, } = serde_json::from_value::>>(result_json)?; trace!("Response account {:?} {:?}", pubkey, rpc_account); - let account = rpc_account.and_then(|rpc_account| rpc_account.decode().ok()); + let account = rpc_account.and_then(|rpc_account| rpc_account.decode()); Ok(Response { context, value: account, diff --git a/client/src/rpc_config.rs b/client/src/rpc_config.rs index d48ecddd16..8cfcee1f8f 100644 --- a/client/src/rpc_config.rs +++ b/client/src/rpc_config.rs @@ -1,3 +1,4 @@ +use solana_account_decoder::AccountEncoding; use solana_sdk::{clock::Epoch, commitment_config::CommitmentConfig}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -40,3 +41,11 @@ pub struct RpcInflationConfig { #[serde(flatten)] pub commitment: Option, } + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct RpcAccountInfoConfig { + pub encoding: Option, + #[serde(flatten)] + pub commitment: Option, +} diff --git a/client/src/rpc_response.rs b/client/src/rpc_response.rs index b78f42fe4a..b93fe357a9 100644 --- a/client/src/rpc_response.rs +++ b/client/src/rpc_response.rs @@ -1,13 +1,12 @@ -use crate::{client_error, rpc_request::RpcError}; +use crate::client_error; +use solana_account_decoder::RpcAccount; use solana_sdk::{ - account::Account, clock::{Epoch, Slot}, fee_calculator::{FeeCalculator, FeeRateGovernor}, inflation::Inflation, - pubkey::Pubkey, transaction::{Result, TransactionError}, }; -use std::{collections::HashMap, net::SocketAddr, str::FromStr}; +use std::{collections::HashMap, net::SocketAddr}; pub type RpcResult = client_error::Result>; @@ -100,43 +99,6 @@ pub struct RpcSignatureResult { pub err: Option, } -/// A duplicate representation of a Message for pretty JSON serialization -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(rename_all = "camelCase")] -pub struct RpcAccount { - pub lamports: u64, - pub data: String, - pub owner: String, - pub executable: bool, - pub rent_epoch: Epoch, -} - -impl RpcAccount { - pub fn encode(account: Account) -> Self { - RpcAccount { - lamports: account.lamports, - data: bs58::encode(account.data.clone()).into_string(), - owner: account.owner.to_string(), - executable: account.executable, - rent_epoch: account.rent_epoch, - } - } - - pub fn decode(&self) -> std::result::Result { - Ok(Account { - lamports: self.lamports, - data: bs58::decode(self.data.clone()).into_vec().map_err(|_| { - RpcError::RpcRequestError("Could not parse encoded account data".to_string()) - })?, - owner: Pubkey::from_str(&self.owner).map_err(|_| { - RpcError::RpcRequestError("Could not parse encoded account owner".to_string()) - })?, - executable: self.executable, - rent_epoch: self.rent_epoch, - }) - } -} - #[derive(Serialize, Deserialize, Clone, Debug)] pub struct RpcContactInfo { /// Pubkey of the node as a base-58 string diff --git a/core/Cargo.toml b/core/Cargo.toml index 9c6078a375..0f426dd37b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -42,11 +42,11 @@ regex = "1.3.9" serde = "1.0.112" serde_derive = "1.0.103" serde_json = "1.0.54" +solana-account-decoder = { path = "../account-decoder", version = "1.3.0" } solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.3.0" } solana-budget-program = { path = "../programs/budget", version = "1.3.0" } solana-clap-utils = { path = "../clap-utils", version = "1.3.0" } solana-client = { path = "../client", version = "1.3.0" } -solana-transaction-status = { path = "../transaction-status", version = "1.3.0" } solana-faucet = { path = "../faucet", version = "1.3.0" } solana-genesis-programs = { path = "../genesis-programs", version = "1.3.0" } solana-ledger = { path = "../ledger", version = "1.3.0" } @@ -60,10 +60,11 @@ solana-runtime = { path = "../runtime", version = "1.3.0" } solana-sdk = { path = "../sdk", version = "1.3.0" } solana-stake-program = { path = "../programs/stake", version = "1.3.0" } solana-streamer = { path = "../streamer", version = "1.3.0" } +solana-sys-tuner = { path = "../sys-tuner", version = "1.3.0" } +solana-transaction-status = { path = "../transaction-status", version = "1.3.0" } solana-version = { path = "../version", version = "1.3.0" } solana-vote-program = { path = "../programs/vote", version = "1.3.0" } solana-vote-signer = { path = "../vote-signer", version = "1.3.0" } -solana-sys-tuner = { path = "../sys-tuner", version = "1.3.0" } tempfile = "3.1.0" thiserror = "1.0" tokio = "0.1" diff --git a/core/src/rpc.rs b/core/src/rpc.rs index a52e284590..e42f822834 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -8,6 +8,7 @@ use crate::{ use bincode::serialize; use jsonrpc_core::{Error, Metadata, Result}; use jsonrpc_derive::rpc; +use solana_account_decoder::{AccountEncoding, RpcAccount}; use solana_client::{ rpc_config::*, rpc_request::{ @@ -205,10 +206,16 @@ impl JsonRpcRequestProcessor { pub fn get_account_info( &self, pubkey: &Pubkey, - commitment: Option, + config: Option, ) -> Result>> { - let bank = self.bank(commitment)?; - new_response(&bank, bank.get_account(pubkey).map(RpcAccount::encode)) + let config = config.unwrap_or_default(); + let bank = self.bank(config.commitment)?; + let encoding = config.encoding.unwrap_or(AccountEncoding::Binary); + new_response( + &bank, + bank.get_account(pubkey) + .map(|account| RpcAccount::encode(account, encoding)), + ) } pub fn get_minimum_balance_for_rent_exemption( @@ -224,15 +231,17 @@ impl JsonRpcRequestProcessor { pub fn get_program_accounts( &self, program_id: &Pubkey, - commitment: Option, + config: Option, ) -> Result> { - Ok(self - .bank(commitment)? + let config = config.unwrap_or_default(); + let bank = self.bank(config.commitment)?; + let encoding = config.encoding.unwrap_or(AccountEncoding::Binary); + Ok(bank .get_program_accounts(Some(&program_id)) .into_iter() .map(|(pubkey, account)| RpcKeyedAccount { pubkey: pubkey.to_string(), - account: RpcAccount::encode(account), + account: RpcAccount::encode(account, encoding.clone()), }) .collect()) } @@ -823,7 +832,7 @@ pub trait RpcSol { &self, meta: Self::Metadata, pubkey_str: String, - commitment: Option, + config: Option, ) -> Result>>; #[rpc(meta, name = "getProgramAccounts")] @@ -831,7 +840,7 @@ pub trait RpcSol { &self, meta: Self::Metadata, program_id_str: String, - commitment: Option, + config: Option, ) -> Result>; #[rpc(meta, name = "getMinimumBalanceForRentExemption")] @@ -1076,11 +1085,11 @@ impl RpcSol for RpcSolImpl { &self, meta: Self::Metadata, pubkey_str: String, - commitment: Option, + config: Option, ) -> Result>> { debug!("get_account_info rpc request received: {:?}", pubkey_str); let pubkey = verify_pubkey(pubkey_str)?; - meta.get_account_info(&pubkey, commitment) + meta.get_account_info(&pubkey, config) } fn get_minimum_balance_for_rent_exemption( @@ -1100,14 +1109,14 @@ impl RpcSol for RpcSolImpl { &self, meta: Self::Metadata, program_id_str: String, - commitment: Option, + config: Option, ) -> Result> { debug!( "get_program_accounts rpc request received: {:?}", program_id_str ); let program_id = verify_pubkey(program_id_str)?; - meta.get_program_accounts(&program_id, commitment) + meta.get_program_accounts(&program_id, config) } fn get_inflation_governor( diff --git a/core/src/rpc_pubsub.rs b/core/src/rpc_pubsub.rs index 50db2d318d..08be0a08f0 100644 --- a/core/src/rpc_pubsub.rs +++ b/core/src/rpc_pubsub.rs @@ -4,9 +4,8 @@ use crate::rpc_subscriptions::{RpcSubscriptions, RpcVote, SlotInfo}; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId}; -use solana_client::rpc_response::{ - Response as RpcResponse, RpcAccount, RpcKeyedAccount, RpcSignatureResult, -}; +use solana_account_decoder::RpcAccount; +use solana_client::rpc_response::{Response as RpcResponse, RpcKeyedAccount, RpcSignatureResult}; #[cfg(test)] use solana_runtime::bank_forks::BankForks; use solana_sdk::{ diff --git a/core/src/rpc_subscriptions.rs b/core/src/rpc_subscriptions.rs index 852f93d511..a160436492 100644 --- a/core/src/rpc_subscriptions.rs +++ b/core/src/rpc_subscriptions.rs @@ -7,8 +7,9 @@ use jsonrpc_pubsub::{ SubscriptionId, }; use serde::Serialize; +use solana_account_decoder::{AccountEncoding, RpcAccount}; use solana_client::rpc_response::{ - Response, RpcAccount, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult, + Response, RpcKeyedAccount, RpcResponseContext, RpcSignatureResult, }; use solana_runtime::{bank::Bank, bank_forks::BankForks, commitment::BlockCommitmentCache}; use solana_sdk::{ @@ -230,7 +231,13 @@ fn filter_account_result( // If fork < last_notified_slot this means that we last notified for a fork // and should notify that the account state has been reverted. if fork != last_notified_slot { - return (Box::new(iter::once(RpcAccount::encode(account))), fork); + return ( + Box::new(iter::once(RpcAccount::encode( + account, + AccountEncoding::Binary, + ))), + fork, + ); } } (Box::new(iter::empty()), last_notified_slot) @@ -260,7 +267,7 @@ fn filter_program_results( .into_iter() .map(|(pubkey, account)| RpcKeyedAccount { pubkey: pubkey.to_string(), - account: RpcAccount::encode(account), + account: RpcAccount::encode(account, AccountEncoding::Binary), }), ), last_notified_slot, diff --git a/core/tests/rpc.rs b/core/tests/rpc.rs index 3ffa0e6077..adae7e7143 100644 --- a/core/tests/rpc.rs +++ b/core/tests/rpc.rs @@ -7,9 +7,10 @@ use jsonrpc_core_client::transports::ws; use log::*; use reqwest::{self, header::CONTENT_TYPE}; use serde_json::{json, Value}; +use solana_account_decoder::RpcAccount; use solana_client::{ rpc_client::{get_rpc_request_str, RpcClient}, - rpc_response::{Response, RpcAccount, RpcSignatureResult}, + rpc_response::{Response, RpcSignatureResult}, }; use solana_core::contact_info::ContactInfo; use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};