Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Release channels have their own copy of this changelog:

### RPC

#### Breaking
* Added a `slot` property to `EpochRewardsPeriodActiveErrorData`
* Added error data containing a `slot` property to `RpcCustomError::SlotNotEpochBoundary`

#### Changes
* The subscription server now prioritizes processing received messages before sending out responses. This ensures that new subscription requests and time-sensitive messages like `PING` opcodes take priority over notifications.

Expand Down
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.

3 changes: 3 additions & 0 deletions rpc-client-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ solana-signer = { workspace = true }
solana-transaction-error = { workspace = true }
solana-transaction-status-client-types = { workspace = true }
thiserror = { workspace = true }

[dev-dependencies]
test-case = { workspace = true }
46 changes: 45 additions & 1 deletion rpc-client-api/src/custom_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,13 @@ pub struct MinContextSlotNotReachedErrorData {
pub context_slot: Slot,
}

#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EpochRewardsPeriodActiveErrorData {
pub current_block_height: u64,
pub rewards_complete_block_height: u64,
pub slot: Option<u64>,
}

impl From<EncodeError> for RpcCustomError {
Expand Down Expand Up @@ -237,6 +239,7 @@ impl From<RpcCustomError> for Error {
data: Some(serde_json::json!(EpochRewardsPeriodActiveErrorData {
current_block_height,
rewards_complete_block_height,
slot: Some(slot),
})),
},
RpcCustomError::SlotNotEpochBoundary { slot } => Self {
Expand All @@ -245,7 +248,9 @@ impl From<RpcCustomError> for Error {
"Rewards cannot be found because slot {slot} is not the epoch boundary. This \
may be due to gap in the queried node's local ledger or long-term storage"
),
data: None,
data: Some(serde_json::json!({
"slot": slot,
})),
},
RpcCustomError::LongTermStorageUnreachable => Self {
code: ErrorCode::ServerError(JSON_RPC_SERVER_ERROR_LONG_TERM_STORAGE_UNREACHABLE),
Expand All @@ -255,3 +260,42 @@ impl From<RpcCustomError> for Error {
}
}
}

#[cfg(test)]
mod tests {
use {
crate::custom_error::EpochRewardsPeriodActiveErrorData, serde_json::Value,
test_case::test_case,
};

#[test_case(serde_json::json!({
"currentBlockHeight": 123,
"rewardsCompleteBlockHeight": 456
}); "Pre-3.0 schema")]
#[test_case(serde_json::json!({
"currentBlockHeight": 123,
"rewardsCompleteBlockHeight": 456,
"slot": 789
}); "3.0+ schema")]
fn test_deseriailze_epoch_rewards_period_active_error_data(serialized_data: Value) {
let expected_current_block_height = serialized_data
.get("currentBlockHeight")
.map(|v| v.as_u64().unwrap())
.unwrap();
let expected_rewards_complete_block_height = serialized_data
.get("rewardsCompleteBlockHeight")
.map(|v| v.as_u64().unwrap())
.unwrap();
let expected_slot: Option<u64> = serialized_data.get("slot").map(|v| v.as_u64().unwrap());
let actual: EpochRewardsPeriodActiveErrorData =
serde_json::from_value(serialized_data).expect("Failed to deserialize test fixture");
assert_eq!(
actual,
EpochRewardsPeriodActiveErrorData {
current_block_height: expected_current_block_height,
rewards_complete_block_height: expected_rewards_complete_block_height,
slot: expected_slot,
}
);
}
}
Loading