Skip to content

Commit

Permalink
RPC: Add API version to context response (solana-labs#25134)
Browse files Browse the repository at this point in the history
* RPC: Add API version to context response

* restore backwards compatibility
  • Loading branch information
jstarry authored May 12, 2022
1 parent 9d18fe0 commit a118af0
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 78 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 32 additions & 8 deletions cli/src/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,10 @@ mod tests {
fn test_check_account_for_fees() {
let account_balance = 1;
let account_balance_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(account_balance),
});
let pubkey = solana_sdk::pubkey::new_rand();
Expand All @@ -183,7 +186,10 @@ mod tests {
check_account_for_fee(&rpc_client, &pubkey, &message0).expect("unexpected result");

let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(2),
});
let mut mocks = HashMap::new();
Expand All @@ -193,7 +199,10 @@ mod tests {
assert!(check_account_for_fee(&rpc_client, &pubkey, &message1).is_err());

let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(2),
});
let mut mocks = HashMap::new();
Expand All @@ -206,11 +215,17 @@ mod tests {

let account_balance = 2;
let account_balance_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(account_balance),
});
let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(1),
});

Expand All @@ -227,7 +242,10 @@ mod tests {
fn test_check_account_for_balance() {
let account_balance = 50;
let account_balance_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(account_balance),
});
let pubkey = solana_sdk::pubkey::new_rand();
Expand All @@ -244,7 +262,10 @@ mod tests {
#[test]
fn test_get_fee_for_messages() {
let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(1),
});
let mut mocks = HashMap::new();
Expand All @@ -263,7 +284,10 @@ mod tests {

// No signatures, no fee.
let check_fee_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(0),
});
let mut mocks = HashMap::new();
Expand Down
10 changes: 8 additions & 2 deletions cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,7 +1986,10 @@ mod tests {
assert!(result.is_ok());

let vote_account_info_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!({
"data": ["KLUv/QBYNQIAtAIBAAAAbnoc3Smwt4/ROvTFWY/v9O8qlxZuPKby5Pv8zYBQW/EFAAEAAB8ACQD6gx92zAiAAecDP4B2XeEBSIx7MQeung==", "base64+zstd"],
"lamports": 42,
Expand Down Expand Up @@ -2272,7 +2275,10 @@ mod tests {
// Success case
let mut config = CliConfig::default();
let account_info_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: Value::Null,
});
let mut mocks = HashMap::new();
Expand Down
15 changes: 12 additions & 3 deletions client/src/blockhash_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ mod tests {
let rpc_blockhash = hash(&[1u8]);
let rpc_fee_calc = FeeCalculator::new(42);
let get_recent_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(RpcFees {
blockhash: rpc_blockhash.to_string(),
fee_calculator: rpc_fee_calc.clone(),
Expand All @@ -364,7 +367,10 @@ mod tests {
}),
});
let get_fee_calculator_for_blockhash_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(RpcFeeCalculator {
fee_calculator: rpc_fee_calc.clone()
}),
Expand Down Expand Up @@ -428,7 +434,10 @@ mod tests {
None,
);
let get_account_response = json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None
},
value: json!(Some(rpc_nonce_account)),
});

Expand Down
30 changes: 15 additions & 15 deletions client/src/mock_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,15 @@ impl RpcSender for MockSender {

let val = match method.as_str().unwrap() {
"getAccountInfo" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: Value::Null,
})?,
"getBalance" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: Value::Number(Number::from(50)),
})?,
"getRecentBlockhash" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: (
Value::String(PUBKEY.to_string()),
serde_json::to_value(FeeCalculator::default()).unwrap(),
Expand All @@ -137,16 +137,16 @@ impl RpcSender for MockSender {
serde_json::to_value(Some(FeeCalculator::default())).unwrap()
};
serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value,
})?
}
"getFeeRateGovernor" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: serde_json::to_value(FeeRateGovernor::default()).unwrap(),
})?,
"getFees" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: serde_json::to_value(RpcFees {
blockhash: PUBKEY.to_string(),
fee_calculator: FeeCalculator::default(),
Expand Down Expand Up @@ -185,7 +185,7 @@ impl RpcSender for MockSender {
.map(|_| status.clone())
.collect();
serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: statuses,
})?
}
Expand Down Expand Up @@ -248,7 +248,7 @@ impl RpcSender for MockSender {
"getBlockProduction" => {
if params.is_null() {
json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: RpcBlockProduction {
by_identity: HashMap::new(),
range: RpcBlockProductionRange {
Expand All @@ -266,7 +266,7 @@ impl RpcSender for MockSender {
let config_range = config.range.unwrap_or_default();

json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: RpcBlockProduction {
by_identity,
range: RpcBlockProductionRange {
Expand All @@ -289,7 +289,7 @@ impl RpcSender for MockSender {
inactive: 12,
}),
"getSupply" => json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: RpcSupply {
total: 100000000,
circulating: 50000,
Expand All @@ -304,7 +304,7 @@ impl RpcSender for MockSender {
};

json!(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: vec![rpc_account_balance],
})
}
Expand Down Expand Up @@ -335,7 +335,7 @@ impl RpcSender for MockSender {
Value::String(signature)
}
"simulateTransaction" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: RpcSimulateTransactionResult {
err: None,
logs: None,
Expand All @@ -353,14 +353,14 @@ impl RpcSender for MockSender {
})
}
"getLatestBlockhash" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: RpcBlockhash {
blockhash: PUBKEY.to_string(),
last_valid_block_height: 1234,
},
})?,
"getFeeForMessage" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: json!(Some(0)),
})?,
"getClusterNodes" => serde_json::to_value(vec![RpcContactInfo {
Expand Down Expand Up @@ -441,7 +441,7 @@ impl RpcSender for MockSender {
"minimumLedgerSlot" => json![123],
"getMaxRetransmitSlot" => json![123],
"getMultipleAccounts" => serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext { slot: 1, api_version: None },
value: vec![Value::Null, Value::Null]
})?,
"getProgramAccounts" => {
Expand Down
7 changes: 5 additions & 2 deletions client/src/nonblocking/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl RpcClient {
/// // Create a mock with a custom repsonse to the `GetBalance` request
/// let account_balance = 50;
/// let account_balance_response = json!(Response {
/// context: RpcResponseContext { slot: 1 },
/// context: RpcResponseContext { slot: 1, api_version: None },
/// value: json!(account_balance),
/// });
///
Expand Down Expand Up @@ -5394,7 +5394,10 @@ pub fn create_rpc_client_mocks() -> crate::mock_sender::Mocks {

let get_account_request = RpcRequest::GetAccountInfo;
let get_account_response = serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None,
},
value: {
let pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
let account = Account {
Expand Down
7 changes: 5 additions & 2 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ impl RpcClient {
/// // Create a mock with a custom repsonse to the `GetBalance` request
/// let account_balance = 50;
/// let account_balance_response = json!(Response {
/// context: RpcResponseContext { slot: 1 },
/// context: RpcResponseContext { slot: 1, api_version: None },
/// value: json!(account_balance),
/// });
///
Expand Down Expand Up @@ -4061,7 +4061,10 @@ pub fn create_rpc_client_mocks() -> crate::mock_sender::Mocks {

let get_account_request = RpcRequest::GetAccountInfo;
let get_account_response = serde_json::to_value(Response {
context: RpcResponseContext { slot: 1 },
context: RpcResponseContext {
slot: 1,
api_version: None,
},
value: {
let pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
let account = Account {
Expand Down
54 changes: 52 additions & 2 deletions client/src/rpc_response.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use {
crate::client_error,
serde::{Deserialize, Deserializer, Serialize, Serializer},
solana_account_decoder::{parse_token::UiTokenAmount, UiAccount},
solana_sdk::{
clock::{Epoch, Slot, UnixTimestamp},
Expand All @@ -12,15 +13,64 @@ use {
solana_transaction_status::{
ConfirmedTransactionStatusWithSignature, TransactionConfirmationStatus, UiConfirmedBlock,
},
std::{collections::HashMap, fmt, net::SocketAddr},
std::{collections::HashMap, fmt, net::SocketAddr, str::FromStr},
thiserror::Error,
};

pub type RpcResult<T> = client_error::Result<Response<T>>;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RpcResponseContext {
pub slot: u64,
pub slot: Slot,
#[serde(skip_serializing_if = "Option::is_none")]
pub api_version: Option<RpcApiVersion>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct RpcApiVersion(semver::Version);

impl std::ops::Deref for RpcApiVersion {
type Target = semver::Version;
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl Default for RpcApiVersion {
fn default() -> Self {
Self(solana_version::Version::default().as_semver_version())
}
}

impl Serialize for RpcApiVersion {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de> Deserialize<'de> for RpcApiVersion {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
Ok(RpcApiVersion(
semver::Version::from_str(&s).map_err(serde::de::Error::custom)?,
))
}
}

impl RpcResponseContext {
pub fn new(slot: Slot) -> Self {
Self {
slot,
api_version: Some(RpcApiVersion::default()),
}
}
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
Expand Down
Loading

0 comments on commit a118af0

Please sign in to comment.