diff --git a/account-decoder/src/lib.rs b/account-decoder/src/lib.rs index 2f9e00ce5ea625..3c1fdcda8a2ad5 100644 --- a/account-decoder/src/lib.rs +++ b/account-decoder/src/lib.rs @@ -20,6 +20,7 @@ pub mod validator_info; use { crate::parse_account_data::{parse_account_data_v2, AccountAdditionalDataV2, ParsedAccount}, base64::{prelude::BASE64_STANDARD, Engine}, + serde::Deserialize, solana_sdk::{ account::{ReadableAccount, WritableAccount}, clock::Epoch, @@ -44,6 +45,7 @@ pub struct UiAccount { pub data: UiAccountData, pub owner: String, pub executable: bool, + #[serde(deserialize_with = "deser_rent_epoch")] pub rent_epoch: Epoch, pub space: Option, } @@ -218,12 +220,23 @@ fn slice_data(data: &[u8], data_slice_config: Option) -> &[u8 } } +fn deser_rent_epoch<'de, D>(deserializer: D) -> Result +where + D: serde::de::Deserializer<'de>, +{ + let rent_epoch: u128 = Deserialize::deserialize(deserializer)?; + Ok(rent_epoch.min(u64::MAX as u128) as u64) +} + #[cfg(test)] mod test { use { super::*, assert_matches::assert_matches, - solana_sdk::account::{Account, AccountSharedData}, + solana_sdk::{ + account::{Account, AccountSharedData}, + rent_collector::RENT_EXEMPT_RENT_EPOCH, + }, }; #[test] @@ -327,4 +340,36 @@ mod test { let decoded_account = encoded_account.decode::().unwrap(); assert_eq!(decoded_account.data(), &vec![0; 1024]); } + + #[test] + fn deserialize_rent_epoch_issue_2950() { + let response_with_overflow = r#"{ + "data": [ + "KLUv/SAAAQAA", + "base64+zstd" + ], + "executable": false, + "lamports": 2088540689624, + "owner": "11111111111111111111111111111111", + "rentEpoch": 18446744073709552000, + "space": 0 + }"#; + let result: UiAccount = serde_json::from_str(&response_with_overflow).unwrap(); + assert_eq!(result.rent_epoch, RENT_EXEMPT_RENT_EPOCH); + + let response = r#"{ + "data": [ + "KLUv/SAAAQAA", + "base64+zstd" + ], + "executable": false, + "lamports": 2088540689624, + "owner": "11111111111111111111111111111111", + "rentEpoch": 12345, + "space": 0 + }"#; + + let result: UiAccount = serde_json::from_str(&response).unwrap(); + assert_eq!(result.rent_epoch, 12345); + } }