diff --git a/soroban-env-host/src/e2e_invoke.rs b/soroban-env-host/src/e2e_invoke.rs index ae2ede775..2ac267370 100644 --- a/soroban-env-host/src/e2e_invoke.rs +++ b/soroban-env-host/src/e2e_invoke.rs @@ -336,23 +336,6 @@ fn extract_diagnostic_events(events: &Events, diagnostic_events: &mut Vec Result<(), HostError> { - if !matches!( - key, - LedgerKey::Account(_) - | LedgerKey::Trustline(_) - | LedgerKey::ContractData(_) - | LedgerKey::ContractCode(_) - ) { - // We expect santized inputs here, so just indicate that something - // is setup incorrectly with internal ('should never happen') error. - return Err( - Error::from_type_and_code(ScErrorType::Storage, ScErrorCode::InternalError).into(), - ); - } - Ok(()) -} - fn ledger_entry_to_ledger_key(le: &LedgerEntry, budget: &Budget) -> Result { match &le.data { LedgerEntryData::Account(a) => Ok(LedgerKey::Account(LedgerKeyAccount { @@ -387,18 +370,18 @@ fn build_storage_footprint_from_xdr( let mut footprint_map = FootprintMap::new(); for key in footprint.read_write.as_vec() { - validate_footprint_key(&key)?; + Storage::check_supported_ledger_key_type(&key)?; footprint_map = footprint_map.insert( - Rc::metered_new_from_ref(key, budget)?, + Rc::metered_new(key.metered_clone(budget)?, budget)?, AccessType::ReadWrite, budget, )?; } for key in footprint.read_only.as_vec() { - validate_footprint_key(&key)?; + Storage::check_supported_ledger_key_type(&key)?; footprint_map = footprint_map.insert( - Rc::metered_new_from_ref(key, budget)?, + Rc::metered_new(key.metered_clone(budget)?, budget)?, AccessType::ReadOnly, budget, )?; diff --git a/soroban-env-host/src/host/comparison.rs b/soroban-env-host/src/host/comparison.rs index 01ca2e18b..c802d9440 100644 --- a/soroban-env-host/src/host/comparison.rs +++ b/soroban-env-host/src/host/comparison.rs @@ -1,22 +1,16 @@ use core::cmp::{min, Ordering}; -use soroban_env_common::{ - xdr::{ - AccountEntry, AccountId, ClaimableBalanceEntry, ConfigSettingEntry, ContractCostType, - ContractDataDurability, ContractExecutable, CreateContractArgs, DataEntry, DepthLimiter, - Duration, ExtensionPoint, Hash, LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerKey, - LedgerKeyAccount, LedgerKeyClaimableBalance, LedgerKeyConfigSetting, LedgerKeyContractCode, - LedgerKeyData, LedgerKeyLiquidityPool, LedgerKeyOffer, LedgerKeyTrustLine, - LiquidityPoolEntry, OfferEntry, PublicKey, ScAddress, ScErrorCode, ScErrorType, ScMap, - ScMapEntry, ScNonceKey, ScVal, ScVec, TimePoint, TrustLineAsset, TrustLineEntry, Uint256, - }, - Compare, SymbolStr, I256, U256, -}; - use crate::{ budget::{AsBudget, Budget}, host_object::HostObject, - Host, HostError, + storage::Storage, + xdr::{ + AccountId, ContractCostType, ContractDataDurability, ContractExecutable, + CreateContractArgs, DepthLimiter, Duration, Hash, LedgerKey, LedgerKeyAccount, + LedgerKeyContractCode, LedgerKeyTrustLine, PublicKey, ScAddress, ScErrorCode, ScErrorType, + ScMap, ScMapEntry, ScNonceKey, ScVal, ScVec, TimePoint, TrustLineAsset, Uint256, + }, + Compare, Host, HostError, SymbolStr, I256, U256, }; use super::declared_size::DeclaredSizeForMetering; @@ -185,27 +179,12 @@ impl_compare_fixed_size_ord_type!(ScNonceKey); impl_compare_fixed_size_ord_type!(PublicKey); impl_compare_fixed_size_ord_type!(TrustLineAsset); impl_compare_fixed_size_ord_type!(ContractDataDurability); +impl_compare_fixed_size_ord_type!(CreateContractArgs); impl_compare_fixed_size_ord_type!(LedgerKeyAccount); impl_compare_fixed_size_ord_type!(LedgerKeyTrustLine); -impl_compare_fixed_size_ord_type!(LedgerKeyOffer); -impl_compare_fixed_size_ord_type!(LedgerKeyData); -impl_compare_fixed_size_ord_type!(LedgerKeyClaimableBalance); -impl_compare_fixed_size_ord_type!(LedgerKeyLiquidityPool); +// NB: LedgerKeyContractData is not here: it has a variable-size ScVal. impl_compare_fixed_size_ord_type!(LedgerKeyContractCode); -impl_compare_fixed_size_ord_type!(LedgerKeyConfigSetting); - -impl_compare_fixed_size_ord_type!(LedgerEntryExt); - -impl_compare_fixed_size_ord_type!(AccountEntry); -impl_compare_fixed_size_ord_type!(TrustLineEntry); -impl_compare_fixed_size_ord_type!(OfferEntry); -impl_compare_fixed_size_ord_type!(DataEntry); -impl_compare_fixed_size_ord_type!(ClaimableBalanceEntry); -impl_compare_fixed_size_ord_type!(LiquidityPoolEntry); -impl_compare_fixed_size_ord_type!(ConfigSettingEntry); -impl_compare_fixed_size_ord_type!(CreateContractArgs); -impl_compare_fixed_size_ord_type!(ExtensionPoint); impl Compare for Budget { type Error = HostError; @@ -314,80 +293,38 @@ impl Compare for Budget { type Error = HostError; fn compare(&self, a: &LedgerKey, b: &LedgerKey) -> Result { + Storage::check_supported_ledger_key_type(a)?; + Storage::check_supported_ledger_key_type(b)?; use LedgerKey::*; match (a, b) { (Account(a), Account(b)) => self.compare(&a, &b), (Trustline(a), Trustline(b)) => self.compare(&a, &b), - (Offer(a), Offer(b)) => self.compare(&a, &b), - (Data(a), Data(b)) => self.compare(&a, &b), - (ClaimableBalance(a), ClaimableBalance(b)) => self.compare(&a, &b), - (LiquidityPool(a), LiquidityPool(b)) => self.compare(&a, &b), (ContractData(a), ContractData(b)) => self.compare( &(&a.contract, &a.key, &a.durability), &(&b.contract, &b.key, &b.durability), ), (ContractCode(a), ContractCode(b)) => self.compare(&a, &b), - (ConfigSetting(a), ConfigSetting(b)) => self.compare(&a, &b), - // List out one side of each remaining unequal-discriminant case so - // we remember to update this code if LedgerKey changes. We don't - // charge for these since they're just 1-integer compares. - (Account(_), _) - | (Trustline(_), _) - | (Offer(_), _) + // All these cases should have been rejected above by check_supported_ledger_key_type. + (Offer(_), _) | (Data(_), _) | (ClaimableBalance(_), _) | (LiquidityPool(_), _) - | (ContractData(_), _) - | (ContractCode(_), _) | (ConfigSetting(_), _) - | (Ttl(_), _) => Ok(a.cmp(b)), - } - } -} - -impl Compare for Budget { - type Error = HostError; - - fn compare(&self, a: &LedgerEntry, b: &LedgerEntry) -> Result { - self.compare( - &(a.last_modified_ledger_seq, &a.data, &a.ext), - &(b.last_modified_ledger_seq, &b.data, &b.ext), - ) - } -} - -impl Compare for Budget { - type Error = HostError; + | (Ttl(_), _) + | (_, Offer(_)) + | (_, Data(_)) + | (_, ClaimableBalance(_)) + | (_, LiquidityPool(_)) + | (_, ConfigSetting(_)) + | (_, Ttl(_)) => Err((ScErrorType::Value, ScErrorCode::InternalError).into()), - fn compare(&self, a: &LedgerEntryData, b: &LedgerEntryData) -> Result { - use LedgerEntryData::*; - match (a, b) { - (Account(a), Account(b)) => self.compare(&a, &b), - (Trustline(a), Trustline(b)) => self.compare(&a, &b), - (Offer(a), Offer(b)) => self.compare(&a, &b), - (Data(a), Data(b)) => self.compare(&a, &b), - (ClaimableBalance(a), ClaimableBalance(b)) => self.compare(&a, &b), - (LiquidityPool(a), LiquidityPool(b)) => self.compare(&a, &b), - (ContractData(a), ContractData(b)) => self.compare( - &(&a.contract, &a.key, &a.durability, &a.val), - &(&b.contract, &b.key, &b.durability, &b.val), - ), - (ContractCode(a), ContractCode(b)) => { - self.compare(&(&a.ext, &a.hash), &(&b.ext, &b.hash)) + // List out one side of each remaining unequal-discriminant case so + // we remember to update this code if LedgerKey changes. We don't + // charge for these since they're just 1-integer compares. + (Account(_), _) | (Trustline(_), _) | (ContractData(_), _) | (ContractCode(_), _) => { + Ok(a.cmp(b)) } - (ConfigSetting(a), ConfigSetting(b)) => self.compare(&a, &b), - - (Account(_), _) - | (Trustline(_), _) - | (Offer(_), _) - | (Data(_), _) - | (ClaimableBalance(_), _) - | (LiquidityPool(_), _) - | (ContractData(_), _) - | (ContractCode(_), _) - | (ConfigSetting(_), _) - | (Ttl(_), _) => Ok(a.cmp(b)), } } } diff --git a/soroban-env-host/src/host/declared_size.rs b/soroban-env-host/src/host/declared_size.rs index f131f6b9e..c87b71bfa 100644 --- a/soroban-env-host/src/host/declared_size.rs +++ b/soroban-env-host/src/host/declared_size.rs @@ -9,14 +9,12 @@ use crate::{ native_contract::base_types::Address, storage::AccessType, xdr::{ - AccountEntry, AccountId, Asset, BytesM, ClaimableBalanceEntry, ConfigSettingEntry, - ContractCodeEntry, ContractDataDurability, ContractEvent, ContractExecutable, - ContractIdPreimage, CreateContractArgs, DataEntry, Duration, ExtensionPoint, Hash, - LedgerEntry, LedgerEntryExt, LedgerKey, LedgerKeyAccount, LedgerKeyClaimableBalance, - LedgerKeyConfigSetting, LedgerKeyContractCode, LedgerKeyData, LedgerKeyLiquidityPool, - LedgerKeyOffer, LedgerKeyTrustLine, LiquidityPoolEntry, OfferEntry, PublicKey, ScAddress, - ScBytes, ScContractInstance, ScMap, ScMapEntry, ScNonceKey, ScString, ScSymbol, ScVal, - ScVec, SorobanAuthorizationEntry, SorobanAuthorizedInvocation, StringM, TimePoint, + AccountEntry, AccountId, Asset, BytesM, ContractCodeEntry, ContractDataDurability, + ContractEvent, ContractExecutable, ContractIdPreimage, CreateContractArgs, Duration, + ExtensionPoint, Hash, LedgerEntry, LedgerEntryExt, LedgerKey, LedgerKeyAccount, + LedgerKeyContractCode, LedgerKeyTrustLine, PublicKey, ScAddress, ScBytes, + ScContractInstance, ScMap, ScMapEntry, ScNonceKey, ScString, ScSymbol, ScVal, ScVec, + Signer, SorobanAuthorizationEntry, SorobanAuthorizedInvocation, StringM, TimePoint, TrustLineAsset, TrustLineEntry, TtlEntry, Uint256, SCSYMBOL_LIMIT, }, AddressObject, Bool, BytesObject, DurationObject, DurationSmall, DurationVal, Error, HostError, @@ -121,26 +119,23 @@ impl_declared_size_type!(ScAddress, 33); impl_declared_size_type!(ScNonceKey, 33); impl_declared_size_type!(PublicKey, 32); impl_declared_size_type!(TrustLineAsset, 45); +impl_declared_size_type!(Signer, 72); + impl_declared_size_type!(LedgerKeyAccount, 32); impl_declared_size_type!(LedgerKeyTrustLine, 77); -impl_declared_size_type!(LedgerKeyOffer, 40); -impl_declared_size_type!(LedgerKeyData, 56); -impl_declared_size_type!(LedgerKeyClaimableBalance, 32); -impl_declared_size_type!(LedgerKeyLiquidityPool, 32); impl_declared_size_type!(LedgerKeyContractCode, 36); -impl_declared_size_type!(LedgerKeyConfigSetting, 4); + impl_declared_size_type!(LedgerEntryExt, 33); impl_declared_size_type!(AccountEntry, 216); impl_declared_size_type!(TrustLineEntry, 128); -impl_declared_size_type!(OfferEntry, 152); -impl_declared_size_type!(DataEntry, 80); -impl_declared_size_type!(ClaimableBalanceEntry, 120); -impl_declared_size_type!(LiquidityPoolEntry, 160); impl_declared_size_type!(ContractCodeEntry, 64); -impl_declared_size_type!(ConfigSettingEntry, 96); +// TtlEntry must be declared as it's used in e2e to build +// The TtlEntryMap, but is not otherwise cloned anywhere. impl_declared_size_type!(TtlEntry, 36); + impl_declared_size_type!(LedgerKey, 120); impl_declared_size_type!(LedgerEntry, 256); + impl_declared_size_type!(AccessType, 1); impl_declared_size_type!(InternalContractEvent, 40); impl_declared_size_type!(ContractEvent, 128); @@ -319,23 +314,14 @@ mod test { expect!["8"].assert_eq(size_of::().to_string().as_str()); expect!["32"].assert_eq(size_of::().to_string().as_str()); expect!["45"].assert_eq(size_of::().to_string().as_str()); + expect!["72"].assert_eq(size_of::().to_string().as_str()); expect!["32"].assert_eq(size_of::().to_string().as_str()); expect!["77"].assert_eq(size_of::().to_string().as_str()); - expect!["40"].assert_eq(size_of::().to_string().as_str()); - expect!["56"].assert_eq(size_of::().to_string().as_str()); - expect!["32"].assert_eq(size_of::().to_string().as_str()); - expect!["32"].assert_eq(size_of::().to_string().as_str()); expect!["32"].assert_eq(size_of::().to_string().as_str()); - expect!["4"].assert_eq(size_of::().to_string().as_str()); expect!["33"].assert_eq(size_of::().to_string().as_str()); expect!["216"].assert_eq(size_of::().to_string().as_str()); expect!["128"].assert_eq(size_of::().to_string().as_str()); - expect!["152"].assert_eq(size_of::().to_string().as_str()); - expect!["80"].assert_eq(size_of::().to_string().as_str()); - expect!["120"].assert_eq(size_of::().to_string().as_str()); - expect!["160"].assert_eq(size_of::().to_string().as_str()); expect!["56"].assert_eq(size_of::().to_string().as_str()); - expect!["96"].assert_eq(size_of::().to_string().as_str()); expect!["36"].assert_eq(size_of::().to_string().as_str()); expect!["112"].assert_eq(size_of::().to_string().as_str()); expect!["256"].assert_eq(size_of::().to_string().as_str()); @@ -486,23 +472,14 @@ mod test { assert_mem_size_le_declared_size!(ScNonceKey); assert_mem_size_le_declared_size!(PublicKey); assert_mem_size_le_declared_size!(TrustLineAsset); + assert_mem_size_le_declared_size!(Signer); assert_mem_size_le_declared_size!(LedgerKeyAccount); assert_mem_size_le_declared_size!(LedgerKeyTrustLine); - assert_mem_size_le_declared_size!(LedgerKeyOffer); - assert_mem_size_le_declared_size!(LedgerKeyData); - assert_mem_size_le_declared_size!(LedgerKeyClaimableBalance); - assert_mem_size_le_declared_size!(LedgerKeyLiquidityPool); assert_mem_size_le_declared_size!(LedgerKeyContractCode); - assert_mem_size_le_declared_size!(LedgerKeyConfigSetting); assert_mem_size_le_declared_size!(LedgerEntryExt); assert_mem_size_le_declared_size!(AccountEntry); assert_mem_size_le_declared_size!(TrustLineEntry); - assert_mem_size_le_declared_size!(OfferEntry); - assert_mem_size_le_declared_size!(DataEntry); - assert_mem_size_le_declared_size!(ClaimableBalanceEntry); - assert_mem_size_le_declared_size!(LiquidityPoolEntry); assert_mem_size_le_declared_size!(ContractCodeEntry); - assert_mem_size_le_declared_size!(ConfigSettingEntry); assert_mem_size_le_declared_size!(TtlEntry); assert_mem_size_le_declared_size!(LedgerKey); assert_mem_size_le_declared_size!(LedgerEntry); diff --git a/soroban-env-host/src/host/metered_clone.rs b/soroban-env-host/src/host/metered_clone.rs index 72ae4680e..fc38ef8b6 100644 --- a/soroban-env-host/src/host/metered_clone.rs +++ b/soroban-env-host/src/host/metered_clone.rs @@ -1,7 +1,5 @@ use std::{iter::FromIterator, mem, rc::Rc}; -use soroban_env_common::xdr::TtlEntry; - use crate::{ budget::AsBudget, events::{EventError, HostEvent, InternalContractEvent, InternalEvent}, @@ -10,15 +8,14 @@ use crate::{ native_contract::base_types::Address, storage::AccessType, xdr::{ - AccountEntry, AccountId, Asset, BytesM, ClaimableBalanceEntry, ConfigSettingEntry, - ContractCodeEntry, ContractCostType, ContractEvent, ContractEventBody, ContractEventType, - ContractExecutable, ContractIdPreimage, CreateContractArgs, DataEntry, DepthLimiter, - Duration, Hash, LedgerEntry, LedgerEntryData, LedgerEntryExt, LedgerKey, LedgerKeyAccount, - LedgerKeyClaimableBalance, LedgerKeyConfigSetting, LedgerKeyContractCode, LedgerKeyData, - LedgerKeyLiquidityPool, LedgerKeyOffer, LedgerKeyTrustLine, LiquidityPoolEntry, OfferEntry, + AccountEntry, AccountId, Asset, BytesM, ContractCodeEntry, ContractCostType, ContractEvent, + ContractEventBody, ContractEventType, ContractExecutable, ContractIdPreimage, + CreateContractArgs, DepthLimiter, Duration, Hash, LedgerEntry, LedgerEntryData, + LedgerEntryExt, LedgerKey, LedgerKeyAccount, LedgerKeyContractCode, LedgerKeyTrustLine, PublicKey, ScAddress, ScBytes, ScContractInstance, ScErrorCode, ScErrorType, ScMap, - ScMapEntry, ScNonceKey, ScString, ScSymbol, ScVal, ScVec, SorobanAuthorizationEntry, - SorobanAuthorizedInvocation, StringM, TimePoint, TrustLineAsset, TrustLineEntry, Uint256, + ScMapEntry, ScNonceKey, ScString, ScSymbol, ScVal, ScVec, Signer, + SorobanAuthorizationEntry, SorobanAuthorizedInvocation, StringM, TimePoint, TrustLineAsset, + TrustLineEntry, Uint256, }, AddressObject, Bool, BytesObject, DurationObject, DurationSmall, DurationVal, Error, HostError, I128Object, I128Small, I128Val, I256Object, I256Small, I256Val, I32Val, I64Object, I64Small, @@ -75,21 +72,15 @@ pub(crate) fn charge_heap_alloc( ) } -pub trait MeteredAlloc: Sized { +pub trait MeteredAlloc: Sized { fn metered_new(value: T, budget: impl AsBudget) -> Result; - - fn metered_new_from_ref(value: &T, budget: impl AsBudget) -> Result; } -impl MeteredAlloc for Rc { +impl MeteredAlloc for Rc { fn metered_new(value: T, budget: impl AsBudget) -> Result { charge_heap_alloc::(1, budget)?; Ok(Rc::new(value)) } - - fn metered_new_from_ref(value: &T, budget: impl AsBudget) -> Result { - Self::metered_new(value.metered_clone(budget.clone())?, budget) - } } /// Represents a collection type which can be created from an iterator, and provides @@ -274,24 +265,17 @@ impl MeteredClone for ScAddress {} impl MeteredClone for ScNonceKey {} impl MeteredClone for PublicKey {} impl MeteredClone for TrustLineAsset {} +impl MeteredClone for Signer {} + impl MeteredClone for LedgerKeyAccount {} impl MeteredClone for LedgerKeyTrustLine {} -impl MeteredClone for LedgerKeyOffer {} -impl MeteredClone for LedgerKeyData {} -impl MeteredClone for LedgerKeyClaimableBalance {} -impl MeteredClone for LedgerKeyLiquidityPool {} impl MeteredClone for LedgerKeyContractCode {} -impl MeteredClone for LedgerKeyConfigSetting {} + impl MeteredClone for LedgerEntryExt {} impl MeteredClone for AccountEntry {} impl MeteredClone for TrustLineEntry {} -impl MeteredClone for OfferEntry {} -impl MeteredClone for DataEntry {} -impl MeteredClone for ClaimableBalanceEntry {} -impl MeteredClone for LiquidityPoolEntry {} impl MeteredClone for ContractCodeEntry {} -impl MeteredClone for ConfigSettingEntry {} -impl MeteredClone for TtlEntry {} + impl MeteredClone for AccessType {} impl MeteredClone for InternalContractEvent {} impl MeteredClone for EventError {} @@ -303,8 +287,6 @@ impl MeteredClone for Asset {} // composite types // cloning Rc is just a ref-count bump impl MeteredClone for Rc {} -// cloning a slice is just cloning the reference -impl MeteredClone for &[T] {} impl MeteredClone for (K, V) where @@ -540,17 +522,13 @@ impl MeteredClone for LedgerKey { const IS_SHALLOW: bool = false; fn charge_for_substructure(&self, budget: impl AsBudget) -> Result<(), HostError> { + use LedgerKey::*; match self { - LedgerKey::ContractData(d) => d.key.charge_for_substructure(budget), - LedgerKey::Account(_) - | LedgerKey::Trustline(_) - | LedgerKey::Offer(_) - | LedgerKey::Data(_) - | LedgerKey::ClaimableBalance(_) - | LedgerKey::LiquidityPool(_) - | LedgerKey::ContractCode(_) - | LedgerKey::ConfigSetting(_) - | LedgerKey::Ttl(_) => Ok(()), + ContractData(d) => d.key.charge_for_substructure(budget), + ContractCode(_) | Account(_) | Trustline(_) => Ok(()), + + Offer(_) | Data(_) | ClaimableBalance(_) | LiquidityPool(_) | ConfigSetting(_) + | Ttl(_) => Err((ScErrorType::Value, ScErrorCode::InternalError).into()), } } } @@ -569,8 +547,14 @@ impl MeteredClone for LedgerEntry { c.charge_for_substructure(budget)?; Ok(()) } - Account(_) | Trustline(_) | Offer(_) | Data(_) | ClaimableBalance(_) - | LiquidityPool(_) | ConfigSetting(_) | Ttl(_) => Ok(()), + Account(ae) => { + ae.signers.charge_for_substructure(budget.clone())?; + Ok(()) + } + Trustline(_) => Ok(()), + + Offer(_) | Data(_) | ClaimableBalance(_) | LiquidityPool(_) | ConfigSetting(_) + | Ttl(_) => Err((ScErrorType::Value, ScErrorCode::InternalError).into()), } } } diff --git a/soroban-env-host/src/storage.rs b/soroban-env-host/src/storage.rs index f365d88c2..d5b730521 100644 --- a/soroban-env-host/src/storage.rs +++ b/soroban-env-host/src/storage.rs @@ -154,6 +154,34 @@ pub struct Storage { // Notes on metering: all storage operations: `put`, `get`, `del`, `has` are // covered by the underlying [MeteredOrdMap] and the [Footprint]'s own map. impl Storage { + /// Only a subset of Stellar's XDR ledger key or entry types are supported + /// by Soroban: accounts, trustlines, contract code and data. The rest are + /// never used by stellar-core when interacting with the Soroban host, nor + /// does the Soroban host ever generate any. Therefore the storage system + /// will reject them with [ScErrorCode::InternalError] if they ever occur. + pub fn check_supported_ledger_entry_type(le: &LedgerEntry) -> Result<(), HostError> { + use crate::xdr::LedgerEntryData::*; + match le.data { + Account(_) | Trustline(_) | ContractData(_) | ContractCode(_) => Ok(()), + Offer(_) | Data(_) | ClaimableBalance(_) | LiquidityPool(_) | ConfigSetting(_) + | Ttl(_) => Err((ScErrorType::Storage, ScErrorCode::InternalError).into()), + } + } + + /// Only a subset of Stellar's XDR ledger key or entry types are supported + /// by Soroban: accounts, trustlines, contract code and data. The rest are + /// never used by stellar-core when interacting with the Soroban host, nor + /// does the Soroban host ever generate any. Therefore the storage system + /// will reject them with [ScErrorCode::InternalError] if they ever occur. + pub fn check_supported_ledger_key_type(lk: &LedgerKey) -> Result<(), HostError> { + use LedgerKey::*; + match lk { + Account(_) | Trustline(_) | ContractData(_) | ContractCode(_) => Ok(()), + Offer(_) | Data(_) | ClaimableBalance(_) | LiquidityPool(_) | ConfigSetting(_) + | Ttl(_) => Err((ScErrorType::Storage, ScErrorCode::InternalError).into()), + } + } + /// Constructs a new [Storage] in [FootprintMode::Enforcing] using a /// given [Footprint] and a storage map populated with all the keys /// listed in the [Footprint]. @@ -182,6 +210,7 @@ impl Storage { budget: &Budget, ) -> Result, HostError> { let _span = tracy_span!("storage get"); + Self::check_supported_ledger_key_type(key)?; self.prepare_read_only_access(key, budget)?; match self.map.get::>(key, budget)? { // Key has to be in the storage map at this point due to @@ -252,6 +281,10 @@ impl Storage { val: Option, budget: &Budget, ) -> Result<(), HostError> { + Self::check_supported_ledger_key_type(key)?; + if let Some(le) = &val { + Self::check_supported_ledger_entry_type(&le.0)?; + } let ty = AccessType::ReadWrite; match self.mode { FootprintMode::Recording(_) => { @@ -310,6 +343,7 @@ impl Storage { /// declared in the [Footprint]. pub fn has(&mut self, key: &Rc, budget: &Budget) -> Result { let _span = tracy_span!("storage has"); + Self::check_supported_ledger_key_type(key)?; self.prepare_read_only_access(key, budget)?; Ok(self .map @@ -337,6 +371,7 @@ impl Storage { extend_to: u32, ) -> Result<(), HostError> { let _span = tracy_span!("extend key"); + Self::check_supported_ledger_key_type(&key)?; if threshold > extend_to { return Err(host.err(