Forráskód Böngészése

Add `slot` to the error context of `EpochRewardsPeriodActiveErrorData` and `SlotNotEpochBoundaryErrorData` (#6962)

* Add `slot` to the error context of `EpochRewardsPeriodActiveErrorData` and `SlotNotEpochBoundaryErrorData`

* Add CHANGELOG entries

* Directly serialize the JSON-RPC error data, rather than bouncing it through a struct

* Make `EpochRewardsPeriodActiveErrorData` from the perspective of deserializing _old_ data by making `slot` an Option
Steven Luscher 4 hónapja
szülő
commit
75458d78cd
4 módosított fájl, 53 hozzáadás és 1 törlés
  1. 4 0
      CHANGELOG.md
  2. 1 0
      Cargo.lock
  3. 3 0
      rpc-client-api/Cargo.toml
  4. 45 1
      rpc-client-api/src/custom_error.rs

+ 4 - 0
CHANGELOG.md

@@ -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.
 

+ 1 - 0
Cargo.lock

@@ -10056,6 +10056,7 @@ dependencies = [
  "solana-signer",
  "solana-transaction-error",
  "solana-transaction-status-client-types",
+ "test-case",
  "thiserror 2.0.12",
 ]
 

+ 3 - 0
rpc-client-api/Cargo.toml

@@ -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 }

+ 45 - 1
rpc-client-api/src/custom_error.rs

@@ -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 {
@@ -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 {
@@ -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),
@@ -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,
+            }
+        );
+    }
+}