diff --git a/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs b/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs index 2ac3862b8..b000994c9 100644 --- a/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs +++ b/cmd/soroban-rpc/lib/preflight/src/ledger_storage.rs @@ -1,6 +1,6 @@ use sha2::Digest; use soroban_env_host::storage::SnapshotSource; -use soroban_env_host::xdr::ContractDataDurability::Persistent; +use soroban_env_host::xdr::ContractDataDurability::{Persistent, Temporary}; use soroban_env_host::xdr::{ ConfigSettingEntry, ConfigSettingId, Error as XdrError, ExpirationEntry, Hash, LedgerEntry, LedgerEntryData, LedgerKey, LedgerKeyConfigSetting, LedgerKeyExpiration, ReadXdr, ScError, @@ -28,6 +28,8 @@ extern "C" { pub(crate) enum Error { #[error("not found")] NotFound, + #[error("entry expired")] + EntryExpired, #[error("xdr processing error: {0}")] Xdr(#[from] XdrError), #[error("nul error: {0}")] @@ -43,7 +45,9 @@ pub(crate) enum Error { impl From for HostError { fn from(value: Error) -> Self { match value { - Error::NotFound => ScError::Storage(ScErrorCode::MissingValue).into(), + Error::NotFound | Error::EntryExpired => { + ScError::Storage(ScErrorCode::MissingValue).into() + } Error::Xdr(_) => ScError::Value(ScErrorCode::InvalidInput).into(), _ => ScError::Context(ScErrorCode::InternalError).into(), } @@ -182,7 +186,7 @@ impl LedgerStorage { && expiration_seq.is_some() && has_expired(expiration_seq.unwrap(), self.current_ledger_sequence) { - return Err(Error::NotFound); + return Err(Error::EntryExpired); } let entry = LedgerEntry::from_xdr(xdr)?; @@ -227,28 +231,35 @@ impl LedgerStorage { impl SnapshotSource for LedgerStorage { fn get(&self, key: &Rc) -> Result<(Rc, Option), HostError> { - let mut entry_and_expiration = - ::get(self, key, self.restore_tracker.is_some())?; if let Some(ref tracker) = self.restore_tracker { + let mut entry_and_expiration = self.get(key, true)?; + // Explicitly discard temporary expired entries + if let Ok(expirable_entry) = + TryInto::>::try_into(&entry_and_expiration) + { + if expirable_entry.durability() == Temporary + && expirable_entry.has_expired(self.current_ledger_sequence) + { + return Err(HostError::from(Error::EntryExpired)); + } + } // If the entry expired, we modify the expiration to make it seem like it was restored entry_and_expiration.1 = tracker.track_and_restore(self.current_ledger_sequence, key, &entry_and_expiration); + return Ok((entry_and_expiration.0.into(), entry_and_expiration.1)); } - Ok((entry_and_expiration.0.into(), entry_and_expiration.1)) + let entry_and_expiration = + ::get(self, key, false).map_err(HostError::from)?; + return Ok((entry_and_expiration.0.into(), entry_and_expiration.1)); } fn has(&self, key: &Rc) -> Result { - let entry_and_expiration = - match ::get(self, key, self.restore_tracker.is_some()) { - Err(e) => match e { - Error::NotFound => return Ok(false), - _ => return Err(HostError::from(e)), - }, - Ok(le) => le, - }; - if let Some(ref tracker) = self.restore_tracker { - _ = tracker.track_and_restore(self.current_ledger_sequence, key, &entry_and_expiration); + let result = ::get(self, key); + if let Err(ref host_error) = result { + if host_error.error.is_code(ScErrorCode::MissingValue) { + return Ok(false); + } } - Ok(true) + return result.map(|_| true); } }