diff --git a/Cargo.lock b/Cargo.lock index 5104eb1da..2cf6ff1fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1693,7 +1693,6 @@ dependencies = [ [[package]] name = "stellar-xdr" version = "22.1.0" -source = "git+https://github.com/stellar/rs-stellar-xdr?rev=28391e81229ad20a3d9ec56e1e1f382205335085#28391e81229ad20a3d9ec56e1e1f382205335085" dependencies = [ "arbitrary", "base64 0.13.1", diff --git a/Cargo.toml b/Cargo.toml index 04e1eae3f..87de00b16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,9 +45,9 @@ version = "=0.31.1-soroban.20.0.1" git = "https://github.com/stellar/wasmi" rev = "0ed3f3dee30dc41ebe21972399e0a73a41944aa0" -# [patch."https://github.com/stellar/rs-stellar-xdr"] +[patch."https://github.com/stellar/rs-stellar-xdr"] # [patch.crates-io] -# stellar-xdr = { path = "../rs-stellar-xdr" } +stellar-xdr = { path = "../rs-stellar-xdr" } # [patch."https://github.com/stellar/wasmi"] # soroban-wasmi = { path = "../wasmi/crates/wasmi/" } # soroban-wasmi_core = { path = "../wasmi/crates/core/" } diff --git a/soroban-env-common/Cargo.toml b/soroban-env-common/Cargo.toml index cd58077ff..05b935223 100644 --- a/soroban-env-common/Cargo.toml +++ b/soroban-env-common/Cargo.toml @@ -15,7 +15,7 @@ crate-git-revision = "0.0.6" [dependencies] soroban-env-macros = { workspace = true } -stellar-xdr = { workspace = true, default-features = false, features = [ "curr" ] } +stellar-xdr = { workspace = true, default-features = false, features = [ "next" ] } wasmi = { workspace = true, optional = true } wasmparser = { workspace = true, optional = true} serde = { version = "1.0.192", features = ["derive"], optional = true } diff --git a/soroban-env-common/env.json b/soroban-env-common/env.json index c9647e3fd..aed58b5a4 100644 --- a/soroban-env-common/env.json +++ b/soroban-env-common/env.json @@ -2416,6 +2416,19 @@ "return": "Val", "docs": "Returns the executable corresponding to the provided address. When the address does not exist on-chain, returns `Void` value. When it does exist, returns a value of `AddressExecutable` contract type. It is an enum with `Wasm` value and the corresponding Wasm hash for the Wasm contracts, `StellarAsset` value for Stellar Asset contract instances, and `Account` value for the 'classic' (G-) accounts.", "min_supported_protocol": 23 + }, + { + "export": "5", + "name": "muxed_address_to_address", + "args": [ + { + "name": "muxed_address", + "type": "MuxedAddressObject" + } + ], + "return": "AddressObject", + "docs": "", + "min_supported_protocol": 23 } ] }, diff --git a/soroban-env-common/src/compare.rs b/soroban-env-common/src/compare.rs index 0334ac5b7..f8b414dc8 100644 --- a/soroban-env-common/src/compare.rs +++ b/soroban-env-common/src/compare.rs @@ -194,7 +194,8 @@ impl Compare for E { | Tag::SymbolObject | Tag::VecObject | Tag::MapObject - | Tag::AddressObject => Err(self.error_from_error_val(Error::from_type_and_code( + | Tag::AddressObject + | Tag::MuxedAddressObject => Err(self.error_from_error_val(Error::from_type_and_code( ScErrorType::Context, ScErrorCode::InternalError, ))), diff --git a/soroban-env-common/src/convert.rs b/soroban-env-common/src/convert.rs index fe284fb42..1463b957b 100644 --- a/soroban-env-common/src/convert.rs +++ b/soroban-env-common/src/convert.rs @@ -499,6 +499,7 @@ where | Tag::VecObject | Tag::MapObject | Tag::AddressObject + | Tag::MuxedAddressObject | Tag::SmallCodeUpperBound | Tag::ObjectCodeLowerBound | Tag::ObjectCodeUpperBound diff --git a/soroban-env-common/src/env.rs b/soroban-env-common/src/env.rs index f8e58de22..d8794b365 100644 --- a/soroban-env-common/src/env.rs +++ b/soroban-env-common/src/env.rs @@ -5,8 +5,9 @@ use crate::Object; use super::Symbol; use super::{ AddressObject, Bool, BytesObject, DurationObject, Error, I128Object, I256Object, I256Val, - I64Object, MapObject, StorageType, StringObject, SymbolObject, TimepointObject, U128Object, - U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, Void, + I64Object, MapObject, MuxedAddressObject, StorageType, StringObject, SymbolObject, + TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, + Void, }; use crate::xdr::{ScErrorCode, ScErrorType}; @@ -262,6 +263,7 @@ impl_checkedenvarg_for_val_or_wrapper!(Val); impl_checkedenvarg_for_val_or_wrapper!(Symbol); impl_checkedenvarg_for_val_or_wrapper!(AddressObject); +impl_checkedenvarg_for_val_or_wrapper!(MuxedAddressObject); impl_checkedenvarg_for_val_or_wrapper!(BytesObject); impl_checkedenvarg_for_val_or_wrapper!(DurationObject); diff --git a/soroban-env-common/src/hash.rs b/soroban-env-common/src/hash.rs index b8c7a2321..74c057b53 100644 --- a/soroban-env-common/src/hash.rs +++ b/soroban-env-common/src/hash.rs @@ -4,8 +4,8 @@ use crate::{ AddressObject, BytesObject, DurationObject, I128Object, I256Object, I64Object, MapObject, - Object, StringObject, Symbol, SymbolObject, TimepointObject, U128Object, U256Object, U64Object, - Val, VecObject, + MuxedAddressObject, Object, StringObject, Symbol, SymbolObject, TimepointObject, U128Object, + U256Object, U64Object, Val, VecObject, }; impl core::hash::Hash for Val { @@ -40,3 +40,4 @@ impl_hash_for_wrapper!(Symbol); impl_hash_for_wrapper!(VecObject); impl_hash_for_wrapper!(MapObject); impl_hash_for_wrapper!(AddressObject); +impl_hash_for_wrapper!(MuxedAddressObject); diff --git a/soroban-env-common/src/lib.rs b/soroban-env-common/src/lib.rs index 9ff21e563..98b3a69bb 100644 --- a/soroban-env-common/src/lib.rs +++ b/soroban-env-common/src/lib.rs @@ -104,7 +104,7 @@ pub use storage_type::StorageType; // Re-export the XDR definitions of a specific version -- curr or next -- of the xdr crate. #[cfg(not(feature = "next"))] -pub use stellar_xdr::curr as xdr; +pub use stellar_xdr::next as xdr; #[cfg(feature = "next")] pub use stellar_xdr::next as xdr; @@ -113,7 +113,7 @@ pub use val::{ConversionError, Tag, Val}; #[cfg(feature = "wasmi")] pub use val::WasmiMarshal; -pub use val::{AddressObject, MapObject, VecObject}; +pub use val::{AddressObject, MapObject, MuxedAddressObject, VecObject}; pub use val::{Bool, Void}; pub use compare::Compare; diff --git a/soroban-env-common/src/val.rs b/soroban-env-common/src/val.rs index 4224b4c0b..37182be51 100644 --- a/soroban-env-common/src/val.rs +++ b/soroban-env-common/src/val.rs @@ -149,8 +149,10 @@ pub enum Tag { /// Tag for a [Val] that refers to a host-side contract address. AddressObject = 77, + MuxedAddressObject = 78, + /// Code delimiting the upper boundary of "object" types. - ObjectCodeUpperBound = 78, + ObjectCodeUpperBound = 79, /// Code reserved to indicate mis-tagged [`Val`]s. Bad = 0x7f, @@ -238,6 +240,7 @@ impl Tag { Tag::VecObject => Some(ScValType::Vec), Tag::MapObject => Some(ScValType::Map), Tag::AddressObject => Some(ScValType::Address), + Tag::MuxedAddressObject => Some(ScValType::Address), Tag::ObjectCodeUpperBound => None, Tag::Bad => None, } @@ -337,6 +340,7 @@ impl Compare for E { declare_tag_based_object_wrapper!(VecObject); declare_tag_based_object_wrapper!(MapObject); declare_tag_based_object_wrapper!(AddressObject); +declare_tag_based_object_wrapper!(MuxedAddressObject); // This is a 0-arg struct rather than an enum to ensure it completely compiles // away, the same way `()` would, while remaining a separate type to allow @@ -685,7 +689,8 @@ impl Val { | Tag::SymbolObject | Tag::VecObject | Tag::MapObject - | Tag::AddressObject => self.has_minor(0), + | Tag::AddressObject + | Tag::MuxedAddressObject => self.has_minor(0), } } @@ -866,6 +871,7 @@ impl Debug for Val { Tag::VecObject => fmt_obj("Vec", self, f), Tag::MapObject => fmt_obj("Map", self, f), Tag::AddressObject => fmt_obj("Address", self, f), + Tag::MuxedAddressObject => fmt_obj("MuxedAddress", self, f), Tag::Bad | Tag::SmallCodeUpperBound diff --git a/soroban-env-common/src/vmcaller_env.rs b/soroban-env-common/src/vmcaller_env.rs index 933040a40..07e0453e9 100644 --- a/soroban-env-common/src/vmcaller_env.rs +++ b/soroban-env-common/src/vmcaller_env.rs @@ -4,8 +4,9 @@ use crate::xdr::{ScErrorCode, ScErrorType}; use super::{ AddressObject, Bool, BytesObject, DurationObject, Error, I128Object, I256Object, I256Val, - I64Object, MapObject, StorageType, StringObject, SymbolObject, TimepointObject, U128Object, - U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, Void, + I64Object, MapObject, MuxedAddressObject, StorageType, StringObject, SymbolObject, + TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, + Void, }; use crate::call_macro_with_all_host_functions; use crate::{CheckedEnvArg, EnvBase, Symbol}; diff --git a/soroban-env-guest/src/guest.rs b/soroban-env-guest/src/guest.rs index 2415049e0..458dd0a55 100644 --- a/soroban-env-guest/src/guest.rs +++ b/soroban-env-guest/src/guest.rs @@ -4,8 +4,9 @@ use soroban_env_common::call_macro_with_all_host_functions; use super::{ AddressObject, Bool, BytesObject, DurationObject, Error, I128Object, I256Object, I256Val, - I64Object, MapObject, StorageType, StringObject, SymbolObject, TimepointObject, U128Object, - U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, Void, + I64Object, MapObject, MuxedAddressObject, StorageType, StringObject, SymbolObject, + TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, + Void, }; use super::{Env, EnvBase, Symbol}; use static_assertions as sa; @@ -337,7 +338,7 @@ macro_rules! generate_extern_modules { #[allow(unused_imports)] use crate::{I128Object, I256Object, I256Val, I64Object, I64Val, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, StorageType, TimepointObject, DurationObject}; #[allow(unused_imports)] - use crate::{Void,AddressObject,SymbolObject,StringObject,Bool}; + use crate::{Void,AddressObject,MuxedAddressObject,SymbolObject,StringObject,Bool}; #[link(wasm_import_module = $mod_str)] extern "C" { $( diff --git a/soroban-env-host/src/auth.rs b/soroban-env-host/src/auth.rs index 2ca8203ce..a64a7de36 100644 --- a/soroban-env-host/src/auth.rs +++ b/soroban-env-host/src/auth.rs @@ -2030,6 +2030,7 @@ impl AccountAuthorizationTracker { &self.invocation_tracker.root_authorized_invocation, )?; } + ScAddress::MuxedAccount(_) => unreachable!(), } Ok(()) } @@ -2072,8 +2073,6 @@ impl AccountAuthorizationTracker { // - Return budget error in case if it was suppressed above. let _ = acc.metered_clone(host.as_budget())?; } - // We only know for sure that the contract instance and Wasm will be - // loaded. ScAddress::Contract(contract_id) => { let instance_key = host.contract_instance_ledger_key(&contract_id)?; let entry = host @@ -2110,6 +2109,7 @@ impl AccountAuthorizationTracker { ContractExecutable::StellarAsset => (), } } + ScAddress::MuxedAccount(_) => unreachable!(), } Ok(()) } diff --git a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs index 00e8ad6c9..deda769b9 100644 --- a/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs +++ b/soroban-env-host/src/builtin_contracts/stellar_asset_contract/balance.rs @@ -54,6 +54,7 @@ pub(crate) fn read_balance(e: &Host, addr: Address) -> Result { Ok(0) } } + ScAddress::MuxedAccount(_) => unreachable!(), } } @@ -130,6 +131,7 @@ pub(crate) fn receive_balance(e: &Host, addr: Address, amount: i128) -> Result<( balance.amount = new_balance; write_contract_balance(e, addr, balance, &id) } + ScAddress::MuxedAccount(_) => unreachable!(), } } @@ -188,6 +190,7 @@ pub(crate) fn spend_balance_no_authorization_check( } Ok(()) } + ScAddress::MuxedAccount(_) => unreachable!(), } } @@ -219,6 +222,7 @@ pub(crate) fn is_authorized(e: &Host, addr: Address) -> Result Ok(!is_asset_auth_required(e)?) } } + ScAddress::MuxedAccount(_) => unreachable!(), } } @@ -257,6 +261,7 @@ pub(crate) fn write_authorization( write_contract_balance(e, addr, balance, &id) } } + ScAddress::MuxedAccount(_) => unreachable!(), } } @@ -326,6 +331,7 @@ pub(crate) fn check_clawbackable(e: &Host, addr: Address) -> Result<(), HostErro Ok(()) } + ScAddress::MuxedAccount(_) => unreachable!(), } } diff --git a/soroban-env-host/src/events/mod.rs b/soroban-env-host/src/events/mod.rs index b1c880b98..eaa5ea078 100644 --- a/soroban-env-host/src/events/mod.rs +++ b/soroban-env-host/src/events/mod.rs @@ -8,8 +8,8 @@ pub(crate) use internal::{ use crate::{ num::{i256_from_pieces, u256_from_pieces}, xdr::{ - ContractEventBody, ContractEventType, ContractExecutable, PublicKey::PublicKeyTypeEd25519, - ScAddress, ScContractInstance, ScVal, + ContractEventBody, ContractEventType, ContractExecutable, MuxedAccount, + PublicKey::PublicKeyTypeEd25519, ScAddress, ScContractInstance, ScVal, }, Error, Host, HostError, Val, VecObject, }; @@ -35,6 +35,19 @@ fn display_address(addr: &ScAddress, f: &mut std::fmt::Formatter<'_>) -> std::fm let strkey = stellar_strkey::Contract(hash.0); write!(f, "{}", strkey) } + ScAddress::MuxedAccount(muxed_account) => match muxed_account { + MuxedAccount::Ed25519(uint256) => { + let strkey = stellar_strkey::ed25519::PublicKey(uint256.0); + write!(f, "{}", strkey) + } + MuxedAccount::MuxedEd25519(m) => { + let strkey = stellar_strkey::ed25519::MuxedAccount { + ed25519: m.ed25519.0.clone(), + id: m.id.clone(), + }; + write!(f, "{}", strkey) + } + }, } } diff --git a/soroban-env-host/src/host.rs b/soroban-env-host/src/host.rs index 8dc0c20ff..46ef78a89 100644 --- a/soroban-env-host/src/host.rs +++ b/soroban-env-host/src/host.rs @@ -6,7 +6,7 @@ use crate::{ budget::{AsBudget, Budget}, builtin_contracts::common_types::AddressExecutable, events::{diagnostic::DiagnosticLevel, Events, InternalEventsBuffer}, - host_object::{HostMap, HostObject, HostVec}, + host_object::{HostMap, HostObject, HostVec, MuxedScAddress}, impl_bignum_host_fns, impl_bignum_host_fns_rhs_u32, impl_bls12_381_fr_arith_host_fns, impl_wrapping_obj_from_num, impl_wrapping_obj_to_num, num::*, @@ -15,8 +15,8 @@ use crate::{ xdr::{ int128_helpers, AccountId, Asset, ContractCostType, ContractEventType, ContractExecutable, ContractIdPreimage, ContractIdPreimageFromAddress, CreateContractArgsV2, Duration, Hash, - LedgerEntryData, PublicKey, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScString, - ScSymbol, ScVal, TimePoint, Uint256, + LedgerEntryData, MuxedAccount, PublicKey, ScAddress, ScBytes, ScErrorCode, ScErrorType, + ScString, ScSymbol, ScVal, TimePoint, Uint256, }, AddressObject, Bool, BytesObject, Compare, ConversionError, EnvBase, Error, LedgerInfo, MapObject, Object, StorageType, StringObject, Symbol, SymbolObject, SymbolSmall, TryFromVal, @@ -47,6 +47,7 @@ mod validity; pub use error::{ErrorHandler, HostError}; use frame::CallParams; pub use prng::{Seed, SEED_BYTES}; +use soroban_env_common::MuxedAddressObject; pub use trace::{TraceEvent, TraceHook, TraceRecord, TraceState}; use self::{ @@ -112,6 +113,7 @@ struct HostImpl { // `with_debug_mode` callback that switches to the shadow budget. diagnostic_level: RefCell, base_prng: RefCell>, + storage_key_conversion_active: RefCell, // Auth-recording mode generates pseudorandom nonces to populate its output. // We'd like these to be deterministic from one run to the next, but also // completely isolated from any use of the user-accessible PRNGs (either @@ -292,6 +294,13 @@ impl_checked_borrow_helpers!( try_borrow_trace_hook_mut ); +impl_checked_borrow_helpers!( + storage_key_conversion_active, + bool, + try_borrow_storage_key_conversion_active, + try_borrow_storage_key_conversion_active_mut +); + #[cfg(any(test, feature = "testutils"))] impl_checked_borrow_helpers!( top_contract_invocation_hook, @@ -349,6 +358,7 @@ impl Host { ), diagnostic_level: Default::default(), base_prng: RefCell::new(None), + storage_key_conversion_active: RefCell::new(false), #[cfg(any(test, feature = "recording_mode"))] recording_auth_nonce_prng: RefCell::new(None), #[cfg(any(test, feature = "testutils"))] @@ -793,7 +803,8 @@ impl EnvBase for Host { | (HostObject::Bytes(_), Tag::BytesObject) | (HostObject::String(_), Tag::StringObject) | (HostObject::Symbol(_), Tag::SymbolObject) - | (HostObject::Address(_), Tag::AddressObject) => Ok(()), + | (HostObject::Address(_), Tag::AddressObject) + | (HostObject::MuxedAddress(_), Tag::MuxedAddressObject) => Ok(()), _ => Err(self.err( xdr::ScErrorType::Value, xdr::ScErrorCode::InvalidInput, @@ -3221,6 +3232,7 @@ impl VmCallerEnv for Host { ScAddress::Contract(Hash(h)) => stellar_strkey::Strkey::Contract( stellar_strkey::Contract(h.metered_clone(self)?), ), + ScAddress::MuxedAccount(_) => unreachable!(), }; Ok(strkey.to_string()) })?; @@ -3331,6 +3343,7 @@ impl VmCallerEnv for Host { None } } + ScAddress::MuxedAccount(_) => unreachable!(), }; if let Some(exec) = maybe_executable { Val::try_from_val(self, &exec) @@ -3338,6 +3351,25 @@ impl VmCallerEnv for Host { Ok(Val::VOID.into()) } } + + fn muxed_address_to_address( + &self, + _vmcaller: &mut VmCaller, + muxed_address: MuxedAddressObject, + ) -> Result { + let sc_address = self.visit_obj(muxed_address, |addr: &MuxedScAddress| match &addr.0 { + ScAddress::Account(_) | ScAddress::Contract(_) => unreachable!(), + ScAddress::MuxedAccount(muxed_account) => match muxed_account { + MuxedAccount::Ed25519(k) => Ok(ScAddress::Account(AccountId( + PublicKey::PublicKeyTypeEd25519(k.metered_clone(self)?), + ))), + MuxedAccount::MuxedEd25519(m) => Ok(ScAddress::Account(AccountId( + PublicKey::PublicKeyTypeEd25519(m.ed25519.metered_clone(self)?), + ))), + }, + })?; + self.add_host_object(sc_address) + } // endregion: "address" module functions // region: "prng" module functions diff --git a/soroban-env-host/src/host/comparison.rs b/soroban-env-host/src/host/comparison.rs index 9603d3c88..4974c78bc 100644 --- a/soroban-env-host/src/host/comparison.rs +++ b/soroban-env-host/src/host/comparison.rs @@ -2,7 +2,7 @@ use core::cmp::{min, Ordering}; use crate::{ budget::{AsBudget, Budget, DepthLimiter}, - host_object::HostObject, + host_object::{HostObject, MuxedScAddress}, storage::Storage, xdr::{ AccountId, ContractCostType, ContractDataDurability, ContractExecutable, @@ -39,6 +39,7 @@ fn host_obj_discriminant(ho: &HostObject) -> usize { HostObject::Vec(_) => 11, HostObject::Map(_) => 12, HostObject::Address(_) => 13, + HostObject::MuxedAddress(_) => 14, } } @@ -65,6 +66,7 @@ impl Compare for Host { (String(a), String(b)) => self.as_budget().compare(&a.as_slice(), &b.as_slice()), (Symbol(a), Symbol(b)) => self.as_budget().compare(&a.as_slice(), &b.as_slice()), (Address(a), Address(b)) => self.as_budget().compare(a, b), + (MuxedAddress(a), MuxedAddress(b)) => self.as_budget().compare(a, b), // List out at least one side of all the remaining cases here so // we don't accidentally forget to update this when/if a new @@ -82,7 +84,8 @@ impl Compare for Host { | (Bytes(_), _) | (String(_), _) | (Symbol(_), _) - | (Address(_), _) => { + | (Address(_), _) + | (MuxedAddress(_), _) => { let a = host_obj_discriminant(a); let b = host_obj_discriminant(b); Ok(a.cmp(&b)) @@ -131,7 +134,8 @@ impl Compare> for Budg // size for budget charging. debug_assert!( std::mem::size_of::() as u64 <= ::DECLARED_SIZE, - "mem size: {}, declared: {}", + "{}: mem size: {}, declared: {}", + std::any::type_name::(), std::mem::size_of::(), ::DECLARED_SIZE ); @@ -182,6 +186,7 @@ impl_compare_fixed_size_ord_type!(ContractExecutable); impl_compare_fixed_size_ord_type!(AccountId); impl_compare_fixed_size_ord_type!(ScError); impl_compare_fixed_size_ord_type!(ScAddress); +impl_compare_fixed_size_ord_type!(MuxedScAddress); impl_compare_fixed_size_ord_type!(ScNonceKey); impl_compare_fixed_size_ord_type!(PublicKey); impl_compare_fixed_size_ord_type!(TrustLineAsset); @@ -603,9 +608,15 @@ mod tests { let pair_pairs = val_pairs.zip(scval_pairs); for ((val1, val2), (scval1, scval2)) in pair_pairs { - let val_cmp = host.compare(val1, val2).expect("compare"); + let val_cmp = host.compare(val1, val2); + if !val_cmp.is_ok() { + dbg!(scval1); + dbg!(scval2); + let _ = host.compare(val1, val2); + panic!(); + } let scval_cmp = scval1.cmp(scval2); - assert_eq!(val_cmp, scval_cmp); + assert_eq!(val_cmp.unwrap(), scval_cmp); } } @@ -719,6 +730,16 @@ mod tests { &ScVal::Address(xdr::ScAddress::Contract(xdr::Hash([0; 32]))), ) .unwrap(), + Tag::MuxedAddressObject => Val::try_from_val( + host, + &ScVal::Address(xdr::ScAddress::MuxedAccount(xdr::MuxedAccount::MuxedEd25519( + xdr::MuxedAccountMed25519 { + id: 0, + ed25519: xdr::Uint256([0; 32]), + }, + ))), + ) + .unwrap(), Tag::ObjectCodeUpperBound => panic!(), Tag::Bad => panic!(), // NB: do not add a fallthrough case here if new Tag variants are added. diff --git a/soroban-env-host/src/host/conversion.rs b/soroban-env-host/src/host/conversion.rs index f78c4efc7..23d666be3 100644 --- a/soroban-env-host/src/host/conversion.rs +++ b/soroban-env-host/src/host/conversion.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use crate::host_object::MemHostObjectType; +use crate::host_object::{MemHostObjectType, MuxedScAddress}; use crate::{ budget::{AsBudget, DepthLimiter}, err, @@ -160,7 +160,7 @@ impl Host { k: Val, durability: ContractDataDurability, ) -> Result, HostError> { - let key_scval = self.from_host_val(k)?; + let key_scval = self.from_host_val_for_storage(k)?; self.storage_key_from_scval(key_scval, durability) } @@ -271,6 +271,16 @@ impl Host { } Ok(ScMap(self.map_err(mv.try_into())?)) } + + pub(crate) fn instance_storage_map_to_scmap(&self, map: &HostMap) -> Result { + let mut mv = Vec::::with_metered_capacity(map.len(), self)?; + for (k, v) in map.iter(self)? { + let key = self.from_host_val_for_storage(*k)?; + let val = self.from_host_val(*v)?; + mv.push(ScMapEntry { key, val }); + } + Ok(ScMap(self.map_err(mv.try_into())?)) + } } impl Convert<&Object, ScValObject> for Host { @@ -330,6 +340,18 @@ impl Host { Ok(scval) } + pub(crate) fn from_host_val_for_storage(&self, val: Val) -> Result { + let _span = tracy_span!("Val to ScVal"); + *self.try_borrow_storage_key_conversion_active_mut()? = true; + let scval = self.budget_cloned().with_limited_depth(|_| { + ScVal::try_from_val(self, &val) + .map_err(|cerr| self.error(cerr, "failed to convert host value to ScVal", &[val])) + })?; + *self.try_borrow_storage_key_conversion_active_mut()? = false; + self.check_val_representable_scval(&scval)?; + Ok(scval) + } + pub(crate) fn to_host_val(&self, v: &ScVal) -> Result { let _span = tracy_span!("ScVal to Val"); // This is the depth limit checkpoint for `ScVal`->`Val` conversion. @@ -421,6 +443,17 @@ impl Host { HostObject::String(s) => ScVal::String(s.metered_clone(self)?), HostObject::Symbol(s) => ScVal::Symbol(s.metered_clone(self)?), HostObject::Address(addr) => ScVal::Address(addr.metered_clone(self)?), + HostObject::MuxedAddress(addr) => { + if *self.try_borrow_storage_key_conversion_active()? { + return Err(self.err( + ScErrorType::Storage, + ScErrorCode::InvalidInput, + "muxed addresses should not be used in the storage keys", + &[], + )); + } + ScVal::Address(addr.0.metered_clone(self)?) + } }; Ok(ScValObject::unchecked_from_val(val)) }) @@ -506,7 +539,17 @@ impl Host { )?)? .into()), - ScVal::Address(addr) => Ok(self.add_host_object(addr.metered_clone(self)?)?.into()), + ScVal::Address(addr) => { + match addr { + ScAddress::Account(_) | ScAddress::Contract(_) => { + Ok(self.add_host_object(addr.metered_clone(self)?)?.into()) + } + ScAddress::MuxedAccount(_) => Ok(self + .add_host_object(MuxedScAddress(addr.metered_clone(self)?))? + .into()), + } + // , + } // None of the following cases should have made it into this function, they // are excluded by the ScValObjRef::classify function. diff --git a/soroban-env-host/src/host/data_helper.rs b/soroban-env-host/src/host/data_helper.rs index fddcb04a0..18c16e143 100644 --- a/soroban-env-host/src/host/data_helper.rs +++ b/soroban-env-host/src/host/data_helper.rs @@ -451,7 +451,7 @@ impl Host { pub(crate) fn contract_id_from_scaddress(&self, address: ScAddress) -> Result { match address { - ScAddress::Account(_) => Err(self.err( + ScAddress::Account(_) | ScAddress::MuxedAccount(_) => Err(self.err( ScErrorType::Object, ScErrorCode::InvalidInput, "not a contract address", diff --git a/soroban-env-host/src/host/declared_size.rs b/soroban-env-host/src/host/declared_size.rs index c8146c73a..ed8c68aa6 100644 --- a/soroban-env-host/src/host/declared_size.rs +++ b/soroban-env-host/src/host/declared_size.rs @@ -9,7 +9,7 @@ use crate::{ InternalDiagnosticEvent, InternalEvent, }, host::{frame::Context, Events}, - host_object::HostObject, + host_object::{HostObject, MuxedScAddress}, storage::AccessType, xdr::{ AccountEntry, AccountId, Asset, BytesM, ContractCodeCostInputs, ContractCodeEntry, @@ -110,7 +110,7 @@ impl_declared_size_type!(SymbolStr, SCSYMBOL_LIMIT); impl_declared_size_type!(SymbolSmallIter, 8); impl_declared_size_type!(U256, 32); impl_declared_size_type!(I256, 32); -impl_declared_size_type!(HostObject, 48); +impl_declared_size_type!(HostObject, 64); impl_declared_size_type!(HostError, 16); impl_declared_size_type!(Context, 512); impl_declared_size_type!(Address, 16); @@ -123,11 +123,11 @@ impl_declared_size_type!(InternalEvent, 40); impl_declared_size_type!(EventError, 1); impl_declared_size_type!(ContractInvocation, 16); -impl_declared_size_type!(AuthorizedInvocation, 160); +impl_declared_size_type!(AuthorizedInvocation, 176); impl_declared_size_type!(AuthorizedInvocationSnapshot, 32); -impl_declared_size_type!(AccountAuthorizationTracker, 256); +impl_declared_size_type!(AccountAuthorizationTracker, 280); impl_declared_size_type!(AccountAuthorizationTrackerSnapshot, 40); -impl_declared_size_type!(InvokerContractAuthorizationTracker, 216); +impl_declared_size_type!(InvokerContractAuthorizationTracker, 232); impl_declared_size_type!(InternalDiagnosticArg, 64); impl_declared_size_type!(InternalDiagnosticEvent, 88); @@ -147,7 +147,8 @@ impl_declared_size_type!(Int256Parts, 32); impl_declared_size_type!(UInt256Parts, 32); impl_declared_size_type!(ContractExecutable, 33); impl_declared_size_type!(AccountId, 32); -impl_declared_size_type!(ScAddress, 33); +impl_declared_size_type!(ScAddress, 48); +impl_declared_size_type!(MuxedScAddress, 48); impl_declared_size_type!(ScNonceKey, 33); impl_declared_size_type!(PublicKey, 32); impl_declared_size_type!(Asset, 45); @@ -172,10 +173,10 @@ impl_declared_size_type!(ScBytes, 24); impl_declared_size_type!(ScString, 24); impl_declared_size_type!(ScSymbol, 24); impl_declared_size_type!(ScError, 8); -impl_declared_size_type!(CreateContractArgs, 98); -impl_declared_size_type!(CreateContractArgsV2, 128); -impl_declared_size_type!(InvokeContractArgs, 88); -impl_declared_size_type!(ContractIdPreimage, 65); +impl_declared_size_type!(CreateContractArgs, 120); +impl_declared_size_type!(CreateContractArgsV2, 144); +impl_declared_size_type!(InvokeContractArgs, 96); +impl_declared_size_type!(ContractIdPreimage, 80); impl_declared_size_type!(ContractDataDurability, 4); // NB: ExtensionPoint is a 1-variant enum with no payload, which Rust optimizes @@ -252,9 +253,9 @@ impl_declared_size_type!(ContractDataDurability, 4); impl_declared_size_type!(ExtensionPoint, 0); impl_declared_size_type!(ScContractInstance, 64); -impl_declared_size_type!(SorobanAuthorizationEntry, 264); -impl_declared_size_type!(SorobanAuthorizedInvocation, 152); -impl_declared_size_type!(SorobanAuthorizedFunction, 128); +impl_declared_size_type!(SorobanAuthorizationEntry, 296); +impl_declared_size_type!(SorobanAuthorizedInvocation, 168); +impl_declared_size_type!(SorobanAuthorizedFunction, 144); // composite types @@ -405,7 +406,7 @@ mod test { #[rustversion::since(1.77)] #[cfg(target_arch = "x86_64")] fn check_x64_host_object_size_that_changed_at_rust_1_77() { - expect!["48"].assert_eq(size_of::().to_string().as_str()); + expect!["64"].assert_eq(size_of::().to_string().as_str()); } #[cfg(target_arch = "x86_64")] @@ -440,13 +441,13 @@ mod test { expect!["1"].assert_eq(size_of::().to_string().as_str()); expect!["16"].assert_eq(size_of::().to_string().as_str()); - expect!["160"].assert_eq(size_of::().to_string().as_str()); + expect!["176"].assert_eq(size_of::().to_string().as_str()); expect!["32"].assert_eq( size_of::() .to_string() .as_str(), ); - expect!["256"].assert_eq( + expect!["272"].assert_eq( size_of::() .to_string() .as_str(), @@ -456,7 +457,7 @@ mod test { .to_string() .as_str(), ); - expect!["216"].assert_eq( + expect!["232"].assert_eq( size_of::() .to_string() .as_str(), @@ -480,7 +481,7 @@ mod test { expect!["32"].assert_eq(size_of::().to_string().as_str()); expect!["33"].assert_eq(size_of::().to_string().as_str()); expect!["32"].assert_eq(size_of::().to_string().as_str()); - expect!["33"].assert_eq(size_of::().to_string().as_str()); + expect!["48"].assert_eq(size_of::().to_string().as_str()); 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()); @@ -509,7 +510,7 @@ mod test { #[rustversion::since(1.76)] fn check_sizes_that_changed_at_rust_1_76() { expect!["64"].assert_eq(size_of::().to_string().as_str()); - expect!["104"].assert_eq(size_of::().to_string().as_str()); + expect!["120"].assert_eq(size_of::().to_string().as_str()); } check_sizes_that_changed_at_rust_1_76(); @@ -520,20 +521,20 @@ mod test { expect!["24"].assert_eq(size_of::().to_string().as_str()); expect!["24"].assert_eq(size_of::().to_string().as_str()); expect!["8"].assert_eq(size_of::().to_string().as_str()); - expect!["98"].assert_eq(size_of::().to_string().as_str()); - expect!["128"].assert_eq(size_of::().to_string().as_str()); - expect!["88"].assert_eq(size_of::().to_string().as_str()); - expect!["65"].assert_eq(size_of::().to_string().as_str()); + expect!["120"].assert_eq(size_of::().to_string().as_str()); + expect!["144"].assert_eq(size_of::().to_string().as_str()); + expect!["96"].assert_eq(size_of::().to_string().as_str()); + expect!["80"].assert_eq(size_of::().to_string().as_str()); expect!["4"].assert_eq(size_of::().to_string().as_str()); expect!["0"].assert_eq(size_of::().to_string().as_str()); expect!["64"].assert_eq(size_of::().to_string().as_str()); - expect!["264"].assert_eq(size_of::().to_string().as_str()); - expect!["152"].assert_eq( + expect!["296"].assert_eq(size_of::().to_string().as_str()); + expect!["168"].assert_eq( size_of::() .to_string() .as_str(), ); - expect!["128"].assert_eq(size_of::().to_string().as_str()); + expect!["144"].assert_eq(size_of::().to_string().as_str()); // composite types expect!["8"].assert_eq(size_of::>().to_string().as_str()); diff --git a/soroban-env-host/src/host/frame.rs b/soroban-env-host/src/host/frame.rs index 04de34956..d51e0ca64 100644 --- a/soroban-env-host/src/host/frame.rs +++ b/soroban-env-host/src/host/frame.rs @@ -1106,7 +1106,7 @@ impl Host { if !storage.is_modified { return Ok(None); } - Ok(Some(self.host_map_to_scmap(&storage.map)?)) + Ok(Some(self.instance_storage_map_to_scmap(&storage.map)?)) } else { Ok(None) } diff --git a/soroban-env-host/src/host/invocation_metering.rs b/soroban-env-host/src/host/invocation_metering.rs index 376bfbd7c..fdafbebde 100644 --- a/soroban-env-host/src/host/invocation_metering.rs +++ b/soroban-env-host/src/host/invocation_metering.rs @@ -404,8 +404,8 @@ mod test { // contract), so 2 writes/bumps are expected. expect![[r#" InvocationResources { - instructions: 4196698, - mem_bytes: 2863076, + instructions: 4196752, + mem_bytes: 2863204, read_entries: 0, write_entries: 2, read_bytes: 0, @@ -431,8 +431,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 314913, - mem_bytes: 1134843, + instructions: 314943, + mem_bytes: 1134859, read_entries: 3, write_entries: 0, read_bytes: 3132, @@ -456,8 +456,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 318203, - mem_bytes: 1135306, + instructions: 318247, + mem_bytes: 1135322, read_entries: 2, write_entries: 1, read_bytes: 3132, @@ -481,8 +481,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 314214, - mem_bytes: 1134691, + instructions: 314242, + mem_bytes: 1134707, read_entries: 3, write_entries: 0, read_bytes: 3216, @@ -506,8 +506,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 319806, - mem_bytes: 1135662, + instructions: 319864, + mem_bytes: 1135678, read_entries: 2, write_entries: 1, read_bytes: 3132, @@ -531,8 +531,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 314576, - mem_bytes: 1134759, + instructions: 314608, + mem_bytes: 1134775, read_entries: 3, write_entries: 0, read_bytes: 3216, @@ -556,8 +556,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 315621, - mem_bytes: 1135111, + instructions: 315657, + mem_bytes: 1135127, read_entries: 3, write_entries: 0, read_bytes: 3216, @@ -581,8 +581,8 @@ mod test { .unwrap(); expect![[r#" InvocationResources { - instructions: 315741, - mem_bytes: 1135111, + instructions: 315783, + mem_bytes: 1135127, read_entries: 3, write_entries: 0, read_bytes: 3216, @@ -606,8 +606,8 @@ mod test { assert!(res.is_err()); expect![[r#" InvocationResources { - instructions: 315602, - mem_bytes: 1135179, + instructions: 315638, + mem_bytes: 1135195, read_entries: 3, write_entries: 0, read_bytes: 3132, diff --git a/soroban-env-host/src/host/metered_clone.rs b/soroban-env-host/src/host/metered_clone.rs index de89f6a97..8988a2181 100644 --- a/soroban-env-host/src/host/metered_clone.rs +++ b/soroban-env-host/src/host/metered_clone.rs @@ -21,6 +21,7 @@ use std::{cell::RefCell, mem, rc::Rc}; use crate::{ budget::{AsBudget, DepthLimiter}, builtin_contracts::base_types::Address, + host_object::MuxedScAddress, storage::AccessType, xdr::{ AccountEntry, AccountId, Asset, BytesM, ContractCodeCostInputs, ContractCodeEntry, @@ -57,7 +58,8 @@ pub(crate) fn charge_shallow_copy( // means an underestimation of the cost. debug_assert!( mem::size_of::() as u64 <= T::DECLARED_SIZE, - "mem size: {}, declared: {}", + "{}: mem size: {}, declared: {}", + std::any::type_name::(), std::mem::size_of::(), T::DECLARED_SIZE ); @@ -77,7 +79,8 @@ pub(crate) fn charge_heap_alloc( // budget charging. debug_assert!( mem::size_of::() as u64 <= T::DECLARED_SIZE, - "mem size: {}, declared: {}", + "{}: mem size: {}, declared: {}", + std::any::type_name::(), std::mem::size_of::(), T::DECLARED_SIZE ); @@ -320,6 +323,7 @@ impl MeteredClone for ContractCodeEntryV1 {} impl MeteredClone for ContractExecutable {} impl MeteredClone for AccountId {} impl MeteredClone for ScAddress {} +impl MeteredClone for MuxedScAddress {} impl MeteredClone for ScNonceKey {} impl MeteredClone for PublicKey {} impl MeteredClone for TrustLineAsset {} diff --git a/soroban-env-host/src/host_object.rs b/soroban-env-host/src/host_object.rs index 41f7a3895..f217e04da 100644 --- a/soroban-env-host/src/host_object.rs +++ b/soroban-env-host/src/host_object.rs @@ -10,9 +10,10 @@ use crate::{ num::{I256, U256}, xdr::{self, ContractCostType, ScErrorCode, ScErrorType, SCSYMBOL_LIMIT}, AddressObject, BytesObject, Compare, DurationObject, DurationSmall, Host, HostError, - I128Object, I128Small, I256Object, I256Small, I64Object, I64Small, MapObject, Object, - StringObject, SymbolObject, SymbolSmall, SymbolStr, TimepointObject, TimepointSmall, - TryFromVal, U128Object, U128Small, U256Object, U256Small, U64Object, U64Small, Val, VecObject, + I128Object, I128Small, I256Object, I256Small, I64Object, I64Small, MapObject, + MuxedAddressObject, Object, StringObject, SymbolObject, SymbolSmall, SymbolStr, + TimepointObject, TimepointSmall, TryFromVal, U128Object, U128Small, U256Object, U256Small, + U64Object, U64Small, Val, VecObject, }; pub(crate) type HostMap = MeteredOrdMap; @@ -34,6 +35,7 @@ pub(crate) enum HostObject { String(xdr::ScString), Symbol(xdr::ScSymbol), Address(xdr::ScAddress), + MuxedAddress(MuxedScAddress), } impl std::fmt::Debug for HostObject { @@ -53,6 +55,7 @@ impl std::fmt::Debug for HostObject { Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(), Self::Symbol(arg0) => f.debug_tuple("Symbol").field(arg0).finish(), Self::Address(arg0) => f.debug_tuple("Address").field(arg0).finish(), + Self::MuxedAddress(arg0) => f.debug_tuple("MuxedAddress").field(arg0).finish(), } } } @@ -136,7 +139,8 @@ impl HostObject { | HostObject::Map(_) | HostObject::Bytes(_) | HostObject::String(_) - | HostObject::Address(_) => None, + | HostObject::Address(_) + | HostObject::MuxedAddress(_) => None, }; Ok(res) } @@ -208,7 +212,49 @@ declare_host_object_type!(I256, I256Object, I256); declare_mem_host_object_type!(xdr::ScBytes, BytesObject, Bytes); declare_mem_host_object_type!(xdr::ScString, StringObject, String); declare_host_object_type!(xdr::ScSymbol, SymbolObject, Symbol); -declare_host_object_type!(xdr::ScAddress, AddressObject, Address); +// declare_host_object_type!(xdr::ScAddress, AddressObject, Address); +impl HostObjectType for xdr::ScAddress { + type Wrapper = AddressObject; + fn new_from_handle(handle: u32) -> Self::Wrapper { + unsafe { AddressObject::from_handle(handle) } + } + fn inject(self) -> HostObject { + match &self { + xdr::ScAddress::MuxedAccount(_) => unreachable!(), + _ => (), + } + HostObject::Address(self) + } + fn try_extract(obj: &HostObject) -> Option<&Self> { + match obj { + HostObject::Address(v) => Some(v), + _ => None, + } + } +} + +#[derive(Clone, Hash, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub(crate) struct MuxedScAddress(pub(crate) xdr::ScAddress); +// declare_host_object_type!(MuxedScAddress, MuxedAddressObject, MuxedAddress); +impl HostObjectType for MuxedScAddress { + type Wrapper = MuxedAddressObject; + fn new_from_handle(handle: u32) -> Self::Wrapper { + unsafe { MuxedAddressObject::from_handle(handle) } + } + fn inject(self) -> HostObject { + match &self.0 { + xdr::ScAddress::MuxedAccount(_) => (), + _ => unreachable!(), + } + HostObject::MuxedAddress(self) + } + fn try_extract(obj: &HostObject) -> Option<&Self> { + match obj { + HostObject::MuxedAddress(v) => Some(v), + _ => None, + } + } +} impl MemHostObjectType for xdr::ScSymbol { fn try_from_bytes(host: &Host, bytes: Vec) -> Result { diff --git a/soroban-env-host/src/test/dispatch.rs b/soroban-env-host/src/test/dispatch.rs index 09ffb4856..0f5194b40 100644 --- a/soroban-env-host/src/test/dispatch.rs +++ b/soroban-env-host/src/test/dispatch.rs @@ -2,15 +2,17 @@ use soroban_synth_wasm::{Arity, LocalRef, ModEmitter, Operand}; use crate::{ budget::AsBudget, - host_object::{HostMap, HostVec}, + host_object::{HostMap, HostVec, MuxedScAddress}, xdr::{ - Duration, Hash, ScAddress, ScBytes, ScErrorCode, ScErrorType, ScString, ScSymbol, TimePoint, + Duration, Hash, MuxedAccount, MuxedAccountMed25519, ScAddress, ScBytes, ScErrorCode, + ScErrorType, ScString, ScSymbol, TimePoint, Uint256, }, AddressObject, Bool, BytesObject, DurationObject, DurationSmall, DurationVal, Env, Error, Host, HostError, I128Object, I128Small, I128Val, I256Object, I256Small, I256Val, I32Val, I64Object, - I64Small, MapObject, StorageType, StringObject, Symbol, SymbolObject, SymbolSmall, - TimepointObject, TimepointSmall, TimepointVal, U128Object, U128Small, U128Val, U256Object, - U256Small, U256Val, U32Val, U64Object, U64Small, U64Val, Val, VecObject, Void, I256, U256, + I64Small, MapObject, MuxedAddressObject, StorageType, StringObject, Symbol, SymbolObject, + SymbolSmall, TimepointObject, TimepointSmall, TimepointVal, U128Object, U128Small, U128Val, + U256Object, U256Small, U256Val, U32Val, U64Object, U64Small, U64Val, Val, VecObject, Void, + I256, U256, }; use soroban_env_macros::generate_synth_dispatch_host_fn_tests; @@ -179,6 +181,12 @@ impl TestVal for AddressObject { } } +impl TestVal for MuxedAddressObject { + fn test_val() -> Val { + unsafe { MuxedAddressObject::from_handle(123).to_val() } + } +} + impl TestVal for Symbol { fn test_val() -> Val { SymbolSmall::test_val() @@ -319,4 +327,14 @@ impl TestObject for AddressObject { } } +impl TestObject for MuxedAddressObject { + fn test_object(host: &Host) -> Self { + let addr = ScAddress::MuxedAccount(MuxedAccount::MuxedEd25519(MuxedAccountMed25519 { + id: 0, + ed25519: Uint256([0; 32]), + })); + host.add_host_object(MuxedScAddress(addr)).unwrap() + } +} + generate_synth_dispatch_host_fn_tests!("../soroban-env-common/env.json"); diff --git a/soroban-env-host/src/test/event.rs b/soroban-env-host/src/test/event.rs index e3c756ca3..c1f81a586 100644 --- a/soroban-env-host/src/test/event.rs +++ b/soroban-env-host/src/test/event.rs @@ -6,15 +6,16 @@ use crate::{ }, testutils::AsScVal, xdr::{ - ContractCostType, ContractEvent, ContractEventBody, ContractEventType, ContractEventV0, - ExtensionPoint, Hash, ScAddress, ScErrorCode, ScErrorType, ScMap, ScMapEntry, ScVal, + AccountId, ContractCostType, ContractEvent, ContractEventBody, ContractEventType, + ContractEventV0, ExtensionPoint, Hash, MuxedAccount, MuxedAccountMed25519, PublicKey, + ScAddress, ScErrorCode, ScErrorType, ScMap, ScMapEntry, ScVal, Uint256, }, Compare, ContractFunctionSet, Env, Error, ErrorHandler, Host, HostError, Symbol, SymbolSmall, Val, VecObject, }; use expect_test::expect; use more_asserts::assert_le; -use soroban_env_common::EnvBase; +use soroban_env_common::{EnvBase, MuxedAddressObject, TryFromVal, TryIntoVal}; use std::rc::Rc; pub struct ContractWithSingleEvent; @@ -299,6 +300,63 @@ fn nonexistent_topic_obj_handle() -> Result<(), HostError> { Ok(()) } +#[test] +fn muxed_address_event() { + let host = Host::test_host_with_prng(); + let addr_sc_val = ScVal::Address(ScAddress::MuxedAccount(MuxedAccount::MuxedEd25519( + MuxedAccountMed25519 { + id: 123, + ed25519: Uint256([111; 32]), + }, + ))); + let addr_val = Val::try_from_val(&host, &addr_sc_val).unwrap(); + host.contract_event( + test_vec![&host, addr_val].as_object(), + Val::from_u32(789).to_val(), + ) + .unwrap(); + + let events = host.get_events().unwrap(); + assert!(events.0.len() == 1); + assert_eq!( + events.0[0].event, + ContractEvent { + ext: ExtensionPoint::V0, + contract_id: None, + type_: ContractEventType::Contract, + body: ContractEventBody::V0(ContractEventV0 { + topics: vec![addr_sc_val].try_into().unwrap(), + data: ScVal::U32(789), + }) + } + ); + let mux_obj = MuxedAddressObject::try_from_val(&host, &addr_val).unwrap(); + let addr_obj = host.muxed_address_to_address(mux_obj).unwrap(); + host.contract_event( + test_vec![&host, addr_obj].as_object(), + Val::from_u32(789).to_val(), + ) + .unwrap(); + let events = host.get_events().unwrap(); + assert!(events.0.len() == 2); + assert_eq!( + events.0[1].event, + ContractEvent { + ext: ExtensionPoint::V0, + contract_id: None, + type_: ContractEventType::Contract, + body: ContractEventBody::V0(ContractEventV0 { + topics: vec![ScVal::Address(ScAddress::Account(AccountId( + PublicKey::PublicKeyTypeEd25519(Uint256([111; 32])) + ),))] + .try_into() + .unwrap(), + data: ScVal::U32(789), + }) + } + ); +} + #[test] fn too_many_event_topics() -> Result<(), HostError> { let topics: Vec<_> = (0..0x00FFFFFF).map(|u| Val::from_u32(u).to_val()).collect(); diff --git a/soroban-env-host/src/test/hostile.rs b/soroban-env-host/src/test/hostile.rs index 228f8564f..43f4b9e82 100644 --- a/soroban-env-host/src/test/hostile.rs +++ b/soroban-env-host/src/test/hostile.rs @@ -525,85 +525,84 @@ fn excessive_logging() -> Result<(), HostError> { host.switch_to_enforcing_storage()?; let expected_budget = expect![[r#" - ================================================================= - Cpu limit: 2000000; used: 214289 - Mem limit: 500000; used: 166780 - ================================================================= - CostType cpu_insns mem_bytes - WasmInsnExec 300 0 - MemAlloc 16628 67360 - MemCpy 2328 0 - MemCmp 464 0 - DispatchHostFunction 310 0 - VisitObject 244 0 - ValSer 0 0 - ValDeser 0 0 - ComputeSha256Hash 3738 0 - ComputeEd25519PubKey 0 0 - VerifyEd25519Sig 0 0 - VmInstantiation 0 0 - VmCachedInstantiation 0 0 - InvokeVmFunction 1948 14 - ComputeKeccak256Hash 0 0 - DecodeEcdsaCurve256Sig 0 0 - RecoverEcdsaSecp256k1Key 0 0 - Int256AddSub 0 0 - Int256Mul 0 0 - Int256Div 0 0 - Int256Pow 0 0 - Int256Shift 0 0 - ChaCha20DrawBytes 0 0 - ParseWasmInstructions 74665 17967 - ParseWasmFunctions 4224 370 - ParseWasmGlobals 1377 104 - ParseWasmTableEntries 29989 6285 - ParseWasmTypes 8292 505 - ParseWasmDataSegments 0 0 - ParseWasmElemSegments 0 0 - ParseWasmImports 5483 806 - ParseWasmExports 6709 568 - ParseWasmDataSegmentBytes 0 0 - InstantiateWasmInstructions 43030 70704 - InstantiateWasmFunctions 59 114 - InstantiateWasmGlobals 83 53 - InstantiateWasmTableEntries 3300 1025 - InstantiateWasmTypes 0 0 - InstantiateWasmDataSegments 0 0 - InstantiateWasmElemSegments 0 0 - InstantiateWasmImports 6476 762 - InstantiateWasmExports 4642 143 - InstantiateWasmDataSegmentBytes 0 0 - Sec1DecodePointUncompressed 0 0 - VerifyEcdsaSecp256r1Sig 0 0 - Bls12381EncodeFp 0 0 - Bls12381DecodeFp 0 0 - Bls12381G1CheckPointOnCurve 0 0 - Bls12381G1CheckPointInSubgroup 0 0 - Bls12381G2CheckPointOnCurve 0 0 - Bls12381G2CheckPointInSubgroup 0 0 - Bls12381G1ProjectiveToAffine 0 0 - Bls12381G2ProjectiveToAffine 0 0 - Bls12381G1Add 0 0 - Bls12381G1Mul 0 0 - Bls12381G1Msm 0 0 - Bls12381MapFpToG1 0 0 - Bls12381HashToG1 0 0 - Bls12381G2Add 0 0 - Bls12381G2Mul 0 0 - Bls12381G2Msm 0 0 - Bls12381MapFp2ToG2 0 0 - Bls12381HashToG2 0 0 - Bls12381Pairing 0 0 - Bls12381FrFromU256 0 0 - Bls12381FrToU256 0 0 - Bls12381FrAddSub 0 0 - Bls12381FrMul 0 0 - Bls12381FrPow 0 0 - Bls12381FrInv 0 0 - ================================================================= + ================================================================= + Cpu limit: 2000000; used: 214303 + Mem limit: 500000; used: 166812 + ================================================================= + CostType cpu_insns mem_bytes + WasmInsnExec 300 0 + MemAlloc 16632 67392 + MemCpy 2330 0 + MemCmp 472 0 + DispatchHostFunction 310 0 + VisitObject 244 0 + ValSer 0 0 + ValDeser 0 0 + ComputeSha256Hash 3738 0 + ComputeEd25519PubKey 0 0 + VerifyEd25519Sig 0 0 + VmInstantiation 0 0 + VmCachedInstantiation 0 0 + InvokeVmFunction 1948 14 + ComputeKeccak256Hash 0 0 + DecodeEcdsaCurve256Sig 0 0 + RecoverEcdsaSecp256k1Key 0 0 + Int256AddSub 0 0 + Int256Mul 0 0 + Int256Div 0 0 + Int256Pow 0 0 + Int256Shift 0 0 + ChaCha20DrawBytes 0 0 + ParseWasmInstructions 74665 17967 + ParseWasmFunctions 4224 370 + ParseWasmGlobals 1377 104 + ParseWasmTableEntries 29989 6285 + ParseWasmTypes 8292 505 + ParseWasmDataSegments 0 0 + ParseWasmElemSegments 0 0 + ParseWasmImports 5483 806 + ParseWasmExports 6709 568 + ParseWasmDataSegmentBytes 0 0 + InstantiateWasmInstructions 43030 70704 + InstantiateWasmFunctions 59 114 + InstantiateWasmGlobals 83 53 + InstantiateWasmTableEntries 3300 1025 + InstantiateWasmTypes 0 0 + InstantiateWasmDataSegments 0 0 + InstantiateWasmElemSegments 0 0 + InstantiateWasmImports 6476 762 + InstantiateWasmExports 4642 143 + InstantiateWasmDataSegmentBytes 0 0 + Sec1DecodePointUncompressed 0 0 + VerifyEcdsaSecp256r1Sig 0 0 + Bls12381EncodeFp 0 0 + Bls12381DecodeFp 0 0 + Bls12381G1CheckPointOnCurve 0 0 + Bls12381G1CheckPointInSubgroup 0 0 + Bls12381G2CheckPointOnCurve 0 0 + Bls12381G2CheckPointInSubgroup 0 0 + Bls12381G1ProjectiveToAffine 0 0 + Bls12381G2ProjectiveToAffine 0 0 + Bls12381G1Add 0 0 + Bls12381G1Mul 0 0 + Bls12381G1Msm 0 0 + Bls12381MapFpToG1 0 0 + Bls12381HashToG1 0 0 + Bls12381G2Add 0 0 + Bls12381G2Mul 0 0 + Bls12381G2Msm 0 0 + Bls12381MapFp2ToG2 0 0 + Bls12381HashToG2 0 0 + Bls12381Pairing 0 0 + Bls12381FrFromU256 0 0 + Bls12381FrToU256 0 0 + Bls12381FrAddSub 0 0 + Bls12381FrMul 0 0 + Bls12381FrPow 0 0 + Bls12381FrInv 0 0 + ================================================================= "#]]; - // moderate logging { host.clear_module_cache()?; diff --git a/soroban-env-host/src/vm/dispatch.rs b/soroban-env-host/src/vm/dispatch.rs index 39997adf6..4e5efc5c1 100644 --- a/soroban-env-host/src/vm/dispatch.rs +++ b/soroban-env-host/src/vm/dispatch.rs @@ -5,9 +5,9 @@ use crate::{ }; use crate::{ AddressObject, Bool, BytesObject, DurationObject, Error, ErrorHandler, I128Object, I256Object, - I256Val, I64Object, MapObject, StorageType, StringObject, Symbol, SymbolObject, - TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, VecObject, - Void, + I256Val, I64Object, MapObject, MuxedAddressObject, StorageType, StringObject, Symbol, + SymbolObject, TimepointObject, U128Object, U256Object, U256Val, U32Val, U64Object, U64Val, Val, + VecObject, Void, }; use core::fmt::Debug; use soroban_env_common::{call_macro_with_all_host_functions, WasmiMarshal}; @@ -96,6 +96,7 @@ impl_relative_object_conversion!(Val); impl_relative_object_conversion!(Symbol); impl_relative_object_conversion!(AddressObject); +impl_relative_object_conversion!(MuxedAddressObject); impl_relative_object_conversion!(BytesObject); impl_relative_object_conversion!(DurationObject); diff --git a/soroban-env-macros/Cargo.toml b/soroban-env-macros/Cargo.toml index d4ad528d1..9d6993f0d 100644 --- a/soroban-env-macros/Cargo.toml +++ b/soroban-env-macros/Cargo.toml @@ -13,7 +13,7 @@ rust-version.workspace = true proc-macro = true [dependencies] -stellar-xdr = { workspace = true, features = ["curr", "std"] } +stellar-xdr = { workspace = true, features = ["next", "std"] } syn = {version="2.0.39",features=["full"]} quote = "1.0.33" proc-macro2 = "1.0.69" diff --git a/soroban-env-macros/src/lib.rs b/soroban-env-macros/src/lib.rs index 3a3e7b568..cf04f62e0 100644 --- a/soroban-env-macros/src/lib.rs +++ b/soroban-env-macros/src/lib.rs @@ -13,7 +13,7 @@ use syn::{parse::Parse, parse_macro_input, Ident, LitInt, LitStr, Token}; // Import the XDR definitions of a specific version -- curr or next -- of the xdr crate. #[cfg(not(feature = "next"))] -use stellar_xdr::curr as xdr; +use stellar_xdr::next as xdr; #[cfg(feature = "next")] use stellar_xdr::next as xdr;