diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e340b7641..90ff24e80 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "stable" +channel = "1.81" targets = ["wasm32-unknown-unknown"] components = ["rustc", "cargo", "rustfmt", "clippy", "rust-src"] diff --git a/soroban-env-common/env.json b/soroban-env-common/env.json index d421dca2f..d3630dfb6 100644 --- a/soroban-env-common/env.json +++ b/soroban-env-common/env.json @@ -1560,6 +1560,61 @@ ], "return": "Val", "docs": "Calls a function in another contract with arguments contained in vector `args`, returning either the result of the called function or an `Error` if the called function failed. The returned error is either a custom `ContractError` that the called contract returns explicitly, or an error with type `Context` and code `InvalidAction` in case of any other error in the called contract (such as a host function failure that caused a trap). `try_call` might trap in a few scenarios where the error can't be meaningfully recovered from, such as running out of budget." + }, + { + "export": "1", + "name": "call_reentrant", + "args": [ + { + "name": "contract", + "type": "AddressObject" + }, + { + "name": "func", + "type": "Symbol" + }, + { + "name": "args", + "type": "VecObject" + } + ], + "return": "Val", + "docs": "Calls a function in another contract with arguments contained in vector `args`. If the call is successful, returns the result of the called function. Traps otherwise. This functions enables re-entrancy in the immediate cross-contract call.", + "min_supported_protocol": 21 + }, + { + "export": "2", + "name": "try_call_reentrant", + "args": [ + { + "name": "contract", + "type": "AddressObject" + }, + { + "name": "func", + "type": "Symbol" + }, + { + "name": "args", + "type": "VecObject" + } + ], + "return": "Val", + "docs": "Calls a function in another contract with arguments contained in vector `args`, returning either the result of the called function or an `Error` if the called function failed. The returned error is either a custom `ContractError` that the called contract returns explicitly, or an error with type `Context` and code `InvalidAction` in case of any other error in the called contract (such as a host function failure that caused a trap). `try_call` might trap in a few scenarios where the error can't be meaningfully recovered from, such as running out of budget. This functions enables re-entrancy in the immediate cross-contract call.", + "min_supported_protocol": 21 + }, + { + "export": "3", + "name": "set_reentrant", + "args": [ + { + "name": "enabled", + "type": "Bool" + } + ], + "return": "Void", + "docs": "Enables the current contract to specify the reentrancy rules.", + "min_supported_protocol": 21 } ] }, diff --git a/soroban-env-host/src/host.rs b/soroban-env-host/src/host.rs index c371ba460..8fb7aa8e5 100644 --- a/soroban-env-host/src/host.rs +++ b/soroban-env-host/src/host.rs @@ -166,6 +166,9 @@ struct HostImpl { #[doc(hidden)] #[cfg(any(test, feature = "recording_mode"))] need_to_build_module_cache: RefCell, + + // Enables calling modules that link functions that call with reentry. + enable_reentrant: RefCell, } // Host is a newtype on Rc so we can impl Env for it below. @@ -382,6 +385,8 @@ impl Host { suppress_diagnostic_events: RefCell::new(false), #[cfg(any(test, feature = "recording_mode"))] need_to_build_module_cache: RefCell::new(false), + + enable_reentrant: RefCell::new(false), })) } @@ -2369,23 +2374,8 @@ impl VmCallerEnv for Host { func: Symbol, args: VecObject, ) -> Result { - let argvec = self.call_args_from_obj(args)?; - // this is the recommended path of calling a contract, with `reentry` - // always set `ContractReentryMode::Prohibited` - let res = self.call_n_internal( - &self.contract_id_from_address(contract_address)?, - func, - argvec.as_slice(), - CallParams::default_external_call(), - ); - if let Err(e) = &res { - self.error( - e.error, - "contract call failed", - &[func.to_val(), args.to_val()], - ); - } - res + let call_params = CallParams::default_external_call(); + self.call_with_params(contract_address, func, args, call_params) } // Notes on metering: covered by the components. @@ -2396,54 +2386,39 @@ impl VmCallerEnv for Host { func: Symbol, args: VecObject, ) -> Result { - let argvec = self.call_args_from_obj(args)?; - // this is the "loosened" path of calling a contract. - // TODO: A `reentry` flag will be passed from `try_call` into here. - // For now, we are passing in `ContractReentryMode::Prohibited` to disable - // reentry. - let res = self.call_n_internal( - &self.contract_id_from_address(contract_address)?, - func, - argvec.as_slice(), - CallParams::default_external_call(), - ); - match res { - Ok(rv) => Ok(rv), - Err(e) => { - self.error( - e.error, - "contract try_call failed", - &[func.to_val(), args.to_val()], - ); - // Only allow to gracefully handle the recoverable errors. - // Non-recoverable errors should still cause guest to panic and - // abort execution. - if e.is_recoverable() { - // Pass contract error _codes_ through, while switching - // from Err(ce) to Ok(ce), i.e. recovering. - if e.error.is_type(ScErrorType::Contract) { - Ok(e.error.to_val()) - } else { - // Narrow all the remaining host errors down to a single - // error type. We don't want to expose the granular host - // errors to the guest, consistently with how every - // other host function works. This reduces the risk of - // implementation being 'locked' into specific error - // codes due to them being exposed to the guest and - // hashed into blockchain. - // The granular error codes are still observable with - // diagnostic events. - Ok(Error::from_type_and_code( - ScErrorType::Context, - ScErrorCode::InvalidAction, - ) - .to_val()) - } - } else { - Err(e) - } - } - } + let call_params = CallParams::default_external_call(); + self.try_call_with_params(contract_address, func, args, call_params) + } + + fn call_reentrant( + &self, + _vmcaller: &mut VmCaller, + contract_address: AddressObject, + func: Symbol, + args: VecObject, + ) -> Result { + let call_params = CallParams::reentrant_external_call(); + self.call_with_params(contract_address, func, args, call_params) + } + + fn try_call_reentrant( + &self, + _vmcaller: &mut VmCaller, + contract_address: AddressObject, + func: Symbol, + args: VecObject, + ) -> Result { + let call_params = CallParams::reentrant_external_call(); + self.try_call_with_params(contract_address, func, args, call_params) + } + + fn set_reentrant( + &self, + _vmcaller: &mut VmCaller, + enabled: Bool, + ) -> Result { + *self.0.enable_reentrant.borrow_mut() = enabled.try_into()?; + Ok(Void::from(())) } // endregion: "call" module functions diff --git a/soroban-env-host/src/host/frame.rs b/soroban-env-host/src/host/frame.rs index 8a9e8592e..8708b54be 100644 --- a/soroban-env-host/src/host/frame.rs +++ b/soroban-env-host/src/host/frame.rs @@ -1,3 +1,5 @@ +use soroban_env_common::VecObject; + use crate::{ auth::AuthorizationManagerSnapshot, budget::AsBudget, @@ -111,6 +113,14 @@ impl CallParams { } } + pub(crate) fn reentrant_external_call() -> Self { + Self { + reentry_mode: ContractReentryMode::Allowed, + internal_host_call: false, + treat_missing_function_as_noop: false, + } + } + #[allow(unused)] pub(crate) fn default_internal_call() -> Self { Self { @@ -174,6 +184,10 @@ impl Frame { } impl Host { + pub(crate) fn get_reentrancy_flag(&self) -> Result { + Ok(*self.0.enable_reentrant.borrow()) + } + /// Returns if the host currently has a frame on the stack. /// /// A frame being on the stack usually indicates that a contract is currently @@ -676,7 +690,7 @@ impl Host { let args_vec = args.to_vec(); match &instance.executable { ContractExecutable::Wasm(wasm_hash) => { - let vm = self.instantiate_vm(id, wasm_hash)?; + let vm = self.instantiate_vm(id, wasm_hash, true)?; let relative_objects = Vec::new(); self.with_frame( Frame::ContractVM { @@ -699,7 +713,12 @@ impl Host { } } - fn instantiate_vm(&self, id: &Hash, wasm_hash: &Hash) -> Result, HostError> { + fn instantiate_vm( + &self, + id: &Hash, + wasm_hash: &Hash, + reentry_guard: bool, + ) -> Result, HostError> { #[cfg(any(test, feature = "recording_mode"))] { if !self.in_storage_recording_mode()? { @@ -792,7 +811,14 @@ impl Host { #[cfg(not(any(test, feature = "recording_mode")))] let cost_mode = crate::vm::ModuleParseCostMode::Normal; - Vm::new_with_cost_inputs(self, contract_id, code.as_slice(), costs, cost_mode) + Vm::new_with_cost_inputs( + self, + contract_id, + code.as_slice(), + costs, + cost_mode, + reentry_guard, + ) } pub(crate) fn get_contract_protocol_version( @@ -807,13 +833,97 @@ impl Host { let instance = self.retrieve_contract_instance_from_storage(&storage_key)?; match &instance.executable { ContractExecutable::Wasm(wasm_hash) => { - let vm = self.instantiate_vm(contract_id, wasm_hash)?; + let vm = self.instantiate_vm(contract_id, wasm_hash, false)?; Ok(vm.module.proto_version) } ContractExecutable::StellarAsset => self.get_ledger_protocol_version(), } } + pub(crate) fn call_with_params( + &self, + contract_address: AddressObject, + func: Symbol, + args: VecObject, + call_params: CallParams, + ) -> Result { + let argvec = self.call_args_from_obj(args)?; + // this is the recommended path of calling a contract, with `reentry` + // always set `ContractReentryMode::Prohibited` unless the reentrant + // flag is enabled. + let res = self.call_n_internal( + &self.contract_id_from_address(contract_address)?, + func, + argvec.as_slice(), + call_params, + ); + if let Err(e) = &res { + self.error( + e.error, + "contract call failed", + &[func.to_val(), args.to_val()], + ); + } + res + } + + pub(crate) fn try_call_with_params( + &self, + contract_address: AddressObject, + func: Symbol, + args: VecObject, + call_params: CallParams, + ) -> Result { + let argvec = self.call_args_from_obj(args)?; + // this is the "loosened" path of calling a contract. + // TODO: A `reentry` flag will be passed from `try_call` into here. + // Default behaviour is to pass in `ContractReentryMode::Prohibited` to disable + // reentry, but it is the `call_data` parameter that controls this mode. + let res = self.call_n_internal( + &self.contract_id_from_address(contract_address)?, + func, + argvec.as_slice(), + call_params, + ); + match res { + Ok(rv) => Ok(rv), + Err(e) => { + self.error( + e.error, + "contract try_call failed", + &[func.to_val(), args.to_val()], + ); + // Only allow to gracefully handle the recoverable errors. + // Non-recoverable errors should still cause guest to panic and + // abort execution. + if e.is_recoverable() { + // Pass contract error _codes_ through, while switching + // from Err(ce) to Ok(ce), i.e. recovering. + if e.error.is_type(ScErrorType::Contract) { + Ok(e.error.to_val()) + } else { + // Narrow all the remaining host errors down to a single + // error type. We don't want to expose the granular host + // errors to the guest, consistently with how every + // other host function works. This reduces the risk of + // implementation being 'locked' into specific error + // codes due to them being exposed to the guest and + // hashed into blockchain. + // The granular error codes are still observable with + // diagnostic events. + Ok(Error::from_type_and_code( + ScErrorType::Context, + ScErrorCode::InvalidAction, + ) + .to_val()) + } + } else { + Err(e) + } + } + } + } + // Notes on metering: this is covered by the called components. pub(crate) fn call_n_internal( &self, diff --git a/soroban-env-host/src/test/lifecycle.rs b/soroban-env-host/src/test/lifecycle.rs index e3110e269..05aab7378 100644 --- a/soroban-env-host/src/test/lifecycle.rs +++ b/soroban-env-host/src/test/lifecycle.rs @@ -2396,3 +2396,78 @@ mod cap_58_constructor { } } } + +#[allow(unused_imports)] +mod cap_xx_opt_in_reentry { + use crate::{Host, HostError, MeteredOrdMap}; + use soroban_env_common::{AddressObject, Env, Symbol, TryFromVal, TryIntoVal, Val, VecObject}; + use soroban_test_wasms::{ + SIMPLE_NO_REENTRY_CONTRACT_A, SIMPLE_NO_REENTRY_CONTRACT_B, SIMPLE_REENTRY_CONTRACT_A, + SIMPLE_REENTRY_CONTRACT_B, + }; + use stellar_xdr::curr::{ + ContractEvent, ContractEventBody, ContractEventType, ContractEventV0, ExtensionPoint, Hash, + ScSymbol, ScVal, + }; + + #[test] + fn test_reentry_enabled() { + let host = Host::test_host_with_recording_footprint(); + let contract_id_a = host.register_test_contract_wasm(SIMPLE_REENTRY_CONTRACT_A); + let contract_id_b = host.register_test_contract_wasm(SIMPLE_REENTRY_CONTRACT_B); + host.enable_debug().unwrap(); + let args = test_vec![&host, contract_id_b].into(); + + call_contract(&host, contract_id_a, args); + + let event_body = ContractEventBody::V0(ContractEventV0 { + topics: host + .map_err( + vec![ScVal::Symbol(ScSymbol( + "first_soroban_reentry".try_into().unwrap(), + ))] + .try_into(), + ) + .unwrap(), + data: ScVal::Void, + }); + let events = host.get_events().unwrap().0; + match events + .iter() + .find(|he| he.event.type_ == ContractEventType::Contract) + { + Some(he) if he.event.type_ == ContractEventType::Contract => { + assert_eq!(he.event.body, event_body) + } + _ => panic!("missing contract event"), + } + } + + #[test] + #[should_panic] + fn test_reentry_disabled() { + let host = Host::test_host_with_recording_footprint(); + let contract_id_a = host.register_test_contract_wasm(SIMPLE_REENTRY_CONTRACT_A); + let contract_id_b = host.register_test_contract_wasm(SIMPLE_NO_REENTRY_CONTRACT_B); + host.enable_debug().unwrap(); + let args = test_vec![&host, contract_id_b].into(); + call_contract(&host, contract_id_a, args); + } + + #[test] + #[should_panic] + fn test_reentry_disabled_from_caller() { + let host = Host::test_host_with_recording_footprint(); + let contract_id_a = host.register_test_contract_wasm(SIMPLE_NO_REENTRY_CONTRACT_A); + let contract_id_b = host.register_test_contract_wasm(SIMPLE_REENTRY_CONTRACT_B); + host.enable_debug().unwrap(); + let args = test_vec![&host, contract_id_b].into(); + + call_contract(&host, contract_id_a, args); + } + + fn call_contract(host: &Host, called: AddressObject, args: VecObject) { + let fname = Symbol::try_from_val(host, &"test_reentry").unwrap(); + host.call(called, fname, args).unwrap(); + } +} diff --git a/soroban-env-host/src/vm.rs b/soroban-env-host/src/vm.rs index 5e7779a8c..9591fdd62 100644 --- a/soroban-env-host/src/vm.rs +++ b/soroban-env-host/src/vm.rs @@ -102,9 +102,20 @@ impl Host { pub(crate) fn make_linker( engine: &wasmi::Engine, symbols: &BTreeSet<(&str, &str)>, + enable_reentrant_linking: bool, ) -> Result, HostError> { let mut linker = Linker::new(&engine); for hf in HOST_FUNCTIONS { + if !enable_reentrant_linking { + if symbols.contains(&("d", "1")) || symbols.contains(&("d", "2")) { + return Err(crate::Error::from_type_and_code( + ScErrorType::WasmVm, + ScErrorCode::InvalidAction, + ) + .try_into()?); + } + } + if symbols.contains(&(hf.mod_str, hf.fn_str)) { (hf.wrap)(&mut linker).map_err(|le| wasmi::Error::Linker(le))?; } @@ -257,7 +268,7 @@ impl Vm { if let Some(linker) = &*host.try_borrow_linker()? { Self::instantiate(host, contract_id, parsed_module, linker) } else { - let linker = parsed_module.make_linker(host)?; + let linker = parsed_module.make_linker(host, true)?; Self::instantiate(host, contract_id, parsed_module, &linker) } } @@ -286,13 +297,16 @@ impl Vm { let cost_inputs = VersionedContractCodeCostInputs::V0 { wasm_bytes: wasm.len(), }; - Self::new_with_cost_inputs( + + let vm = Self::new_with_cost_inputs( host, contract_id, wasm, cost_inputs, ModuleParseCostMode::Normal, - ) + false, + ); + vm } pub(crate) fn new_with_cost_inputs( @@ -301,11 +315,13 @@ impl Vm { wasm: &[u8], cost_inputs: VersionedContractCodeCostInputs, cost_mode: ModuleParseCostMode, + reentry_guard: bool, ) -> Result, HostError> { let _span = tracy_span!("Vm::new"); VmInstantiationTimer::new(host.clone()); let parsed_module = Self::parse_module(host, wasm, cost_inputs, cost_mode)?; - let linker = parsed_module.make_linker(host)?; + let linker = parsed_module.make_linker(host, reentry_guard)?; + Self::instantiate(host, contract_id, parsed_module, &linker) } diff --git a/soroban-env-host/src/vm/module_cache.rs b/soroban-env-host/src/vm/module_cache.rs index e93df15b9..f798ac7b8 100644 --- a/soroban-env-host/src/vm/module_cache.rs +++ b/soroban-env-host/src/vm/module_cache.rs @@ -132,7 +132,10 @@ impl ModuleCache { } pub fn make_linker(&self, host: &Host) -> Result, HostError> { - self.with_import_symbols(host, |symbols| Host::make_linker(&self.engine, symbols)) + let enable_reentrant_linking = host.get_reentrancy_flag()?; + self.with_import_symbols(host, |symbols| { + Host::make_linker(&self.engine, symbols, enable_reentrant_linking) + }) } pub fn get_module( diff --git a/soroban-env-host/src/vm/parsed_module.rs b/soroban-env-host/src/vm/parsed_module.rs index 3857e2f14..85f278983 100644 --- a/soroban-env-host/src/vm/parsed_module.rs +++ b/soroban-env-host/src/vm/parsed_module.rs @@ -193,9 +193,19 @@ impl ParsedModule { callback(&symbols) } - pub fn make_linker(&self, host: &Host) -> Result, HostError> { + pub fn make_linker( + &self, + host: &Host, + reentry_guard: bool, + ) -> Result, HostError> { self.with_import_symbols(host, |symbols| { - Host::make_linker(self.module.engine(), symbols) + let enable_reentrant_linking = if reentry_guard { + host.get_reentrancy_flag()? + } else { + true + }; + + Host::make_linker(self.module.engine(), symbols, enable_reentrant_linking) }) } diff --git a/soroban-test-wasms/src/lib.rs b/soroban-test-wasms/src/lib.rs index cc3985561..258bbc6c2 100644 --- a/soroban-test-wasms/src/lib.rs +++ b/soroban-test-wasms/src/lib.rs @@ -118,3 +118,16 @@ pub const CONSTRUCTOR_WITH_RESULT: &[u8] = include_bytes!("../wasm-workspace/opt/22/test_constructor_with_result.wasm").as_slice(); pub const CUSTOM_ACCOUNT_CONTEXT_TEST_CONTRACT: &[u8] = include_bytes!("../wasm-workspace/opt/22/test_custom_account_context.wasm").as_slice(); + +// Protocol 23 Wasms. +pub const SIMPLE_REENTRY_CONTRACT_A: &[u8] = + include_bytes!("../wasm-workspace/opt/23/example_reentry_a.wasm").as_slice(); + +pub const SIMPLE_NO_REENTRY_CONTRACT_A: &[u8] = + include_bytes!("../wasm-workspace/opt/23/example_no_reentry_a.wasm").as_slice(); + +pub const SIMPLE_REENTRY_CONTRACT_B: &[u8] = + include_bytes!("../wasm-workspace/opt/23/example_reentry_b.wasm").as_slice(); + +pub const SIMPLE_NO_REENTRY_CONTRACT_B: &[u8] = + include_bytes!("../wasm-workspace/opt/23/example_no_reentry_b.wasm").as_slice(); diff --git a/soroban-test-wasms/wasm-workspace/Cargo.lock b/soroban-test-wasms/wasm-workspace/Cargo.lock index a01fd7d2f..bc0f31938 100644 --- a/soroban-test-wasms/wasm-workspace/Cargo.lock +++ b/soroban-test-wasms/wasm-workspace/Cargo.lock @@ -17,18 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -53,17 +41,11 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - [[package]] name = "auth_test_contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -183,7 +165,7 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" name = "contract_sac_transfer" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -308,6 +290,12 @@ dependencies = [ "syn", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "der" version = "0.7.8" @@ -441,7 +429,7 @@ checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" name = "example_add_f32" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -449,7 +437,7 @@ dependencies = [ name = "example_add_i32" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -457,7 +445,7 @@ dependencies = [ name = "example_alloc" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -465,7 +453,7 @@ dependencies = [ name = "example_complex" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -473,7 +461,7 @@ dependencies = [ name = "example_contract_data" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -481,7 +469,7 @@ dependencies = [ name = "example_create_contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -489,7 +477,7 @@ dependencies = [ name = "example_err" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -497,7 +485,7 @@ dependencies = [ name = "example_fannkuch" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -505,7 +493,7 @@ dependencies = [ name = "example_fib" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -513,7 +501,7 @@ dependencies = [ name = "example_hostile" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -521,7 +509,7 @@ dependencies = [ name = "example_invoke_contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -529,7 +517,39 @@ dependencies = [ name = "example_linear_memory" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", + "soroban-sdk", +] + +[[package]] +name = "example_no_reentry_a" +version = "0.0.0" +dependencies = [ + "soroban-env-common 22.0.0-rc.1", + "soroban-sdk", +] + +[[package]] +name = "example_no_reentry_b" +version = "0.0.0" +dependencies = [ + "soroban-env-common 22.0.0-rc.1", + "soroban-sdk", +] + +[[package]] +name = "example_reentry_a" +version = "0.0.0" +dependencies = [ + "soroban-env-common 22.0.0-rc.1", + "soroban-sdk", +] + +[[package]] +name = "example_reentry_b" +version = "0.0.0" +dependencies = [ + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -537,7 +557,7 @@ dependencies = [ name = "example_simple_account" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -545,7 +565,7 @@ dependencies = [ name = "example_sum_i32" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -553,7 +573,7 @@ dependencies = [ name = "example_updateable_contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -561,7 +581,7 @@ dependencies = [ name = "example_upload_contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -569,7 +589,7 @@ dependencies = [ name = "example_vec" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -647,9 +667,6 @@ name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" -dependencies = [ - "ahash", -] [[package]] name = "hex" @@ -679,7 +696,7 @@ dependencies = [ name = "hostile_large_val" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -740,6 +757,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.11.0" @@ -801,7 +827,7 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" name = "loadgen" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -826,12 +852,6 @@ dependencies = [ "adler", ] -[[package]] -name = "multi-stash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f" - [[package]] name = "num-bigint" version = "0.4.4" @@ -1005,7 +1025,7 @@ dependencies = [ name = "recursive_account" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1044,7 +1064,7 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" name = "sac_reentry_account" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1166,9 +1186,11 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.0.0" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44877373b3dc6c662377cb1600e3a62706d75e484b6064f9cd22e467c676b159" dependencies = [ - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "syn", @@ -1176,7 +1198,9 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.0.0" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "590add16843a61b01844e19e89bccaaee6aa21dc76809017b0662c17dc139ee9" dependencies = [ "arbitrary", "crate-git-revision", @@ -1184,24 +1208,43 @@ dependencies = [ "num-derive", "num-traits", "serde", - "soroban-env-macros", + "soroban-env-macros 21.2.0", "soroban-wasmi", "static_assertions", - "stellar-xdr 21.2.0 (git+https://github.com/stellar/rs-stellar-xdr?rev=953ad1c6103146121871a3e2fa5aaca3d6256891)", + "stellar-xdr 21.2.0", "wasmparser", ] +[[package]] +name = "soroban-env-common" +version = "22.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc59f0172caff4867ea71e0b65ff8a532d10612ff78c791a01e23fc33521a9a" +dependencies = [ + "crate-git-revision", + "ethnum", + "num-derive", + "num-traits", + "soroban-env-macros 22.0.0-rc.1", + "static_assertions", + "stellar-xdr 22.0.0-rc.1", +] + [[package]] name = "soroban-env-guest" -version = "22.0.0" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8dc43acdd6c7e7b371acf44fc1a7dac24934ae3b2f05fafd618818548176" dependencies = [ - "soroban-env-common", + "soroban-env-common 21.2.0", "static_assertions", ] [[package]] name = "soroban-env-host" -version = "22.0.0" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e25aaffe0c62eb65e0e349f725b4b8b13ad0764d78a15aab5bbccb5c4797726" dependencies = [ "backtrace", "curve25519-dalek", @@ -1223,34 +1266,53 @@ dependencies = [ "sha2", "sha3", "soroban-builtin-sdk-macros", - "soroban-env-common", + "soroban-env-common 21.2.0", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.8", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.0.0" +version = "21.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e16b761459fdf3c4b62b24df3941498d14e5246e6fadfb4774ed8114d243aa4" dependencies = [ - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "serde", "serde_json", - "stellar-xdr 21.2.0 (git+https://github.com/stellar/rs-stellar-xdr?rev=953ad1c6103146121871a3e2fa5aaca3d6256891)", + "stellar-xdr 21.2.0", + "syn", +] + +[[package]] +name = "soroban-env-macros" +version = "22.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed871b77a7e06adb5b61f792aac3d23c5180c56b4c9bba59ecdc38d5f468cf5" +dependencies = [ + "itertools 0.10.5", + "proc-macro2", + "quote", + "serde", + "serde_json", + "stellar-xdr 22.0.0-rc.1", "syn", ] [[package]] name = "soroban-ledger-snapshot" -version = "21.4.0" +version = "21.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a46f8b134b1e0b517f70d24dd72399cd263fd18c3c7cfcb5e56ffc6de9dad0c3" dependencies = [ "serde", "serde_json", "serde_with", - "soroban-env-common", + "soroban-env-common 21.2.0", "soroban-env-host", "thiserror", ] @@ -1258,6 +1320,8 @@ dependencies = [ [[package]] name = "soroban-sdk" version = "21.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60cd55eb88cbe1d9e7fe3ab1845c7c10c26b27e2d226e973150e5b55580aa359" dependencies = [ "arbitrary", "bytes-lit", @@ -1270,21 +1334,23 @@ dependencies = [ "soroban-env-host", "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.8", ] [[package]] name = "soroban-sdk-macros" -version = "21.4.0" +version = "21.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f24c6b0c46e41852a8603bb32d43cf6a4046ce65483f6383903ec653118cd90" dependencies = [ "crate-git-revision", "darling", - "itertools", + "itertools 0.11.0", "proc-macro2", "quote", "rustc_version", "sha2", - "soroban-env-common", + "soroban-env-common 21.2.0", "soroban-spec", "soroban-spec-rust", "stellar-xdr 21.2.0", @@ -1293,7 +1359,9 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "21.4.0" +version = "21.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b262c82d840552f71ee9254f2e928622fd803bd4df4815e65f73f73efc2fa9c" dependencies = [ "base64 0.13.1", "stellar-xdr 21.2.0", @@ -1303,7 +1371,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "21.4.0" +version = "21.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a061820c2dd0bd3ece9411e0dd3aeb6ed9ca2b7d64270eda9e798c3b6dec5f" dependencies = [ "prettyplease", "proc-macro2", @@ -1317,16 +1387,13 @@ dependencies = [ [[package]] name = "soroban-wasmi" -version = "0.36.0-soroban.22.0.0" -source = "git+https://github.com/stellar/wasmi?rev=122a74a7c491929e5ac9de876099154ef7c06d06#122a74a7c491929e5ac9de876099154ef7c06d06" +version = "0.31.1-soroban.20.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710403de32d0e0c35375518cb995d4fc056d0d48966f2e56ea471b8cb8fc9719" dependencies = [ - "arrayvec", - "multi-stash", - "num-derive", - "num-traits", "smallvec", "spin", - "wasmi_collections", + "wasmi_arena", "wasmi_core", "wasmparser-nostd", ] @@ -1335,7 +1402,7 @@ dependencies = [ name = "soroban-write-upgrade-bytes-contract" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1373,21 +1440,21 @@ dependencies = [ ] [[package]] -name = "stellar-xdr" -version = "21.2.0" +name = "stellar-strkey" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" dependencies = [ "crate-git-revision", - "escape-bytes", - "hex", - "serde", - "serde_with", - "stellar-strkey", + "data-encoding", + "thiserror", ] [[package]] name = "stellar-xdr" version = "21.2.0" -source = "git+https://github.com/stellar/rs-stellar-xdr?rev=953ad1c6103146121871a3e2fa5aaca3d6256891#953ad1c6103146121871a3e2fa5aaca3d6256891" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2675a71212ed39a806e415b0dbf4702879ff288ec7f5ee996dda42a135512b50" dependencies = [ "arbitrary", "base64 0.13.1", @@ -1396,18 +1463,19 @@ dependencies = [ "hex", "serde", "serde_with", - "stellar-strkey", + "stellar-strkey 0.0.8", ] [[package]] -name = "string-interner" -version = "0.17.0" +name = "stellar-xdr" +version = "22.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e" +checksum = "1946827903a221bf052e24e18f0ed6fb10ca350c9281911f24b7d7a9726ab181" dependencies = [ - "cfg-if", - "hashbrown 0.14.2", - "serde", + "crate-git-revision", + "escape-bytes", + "hex", + "stellar-strkey 0.0.9", ] [[package]] @@ -1437,7 +1505,7 @@ dependencies = [ name = "test_conditional_account" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1445,7 +1513,7 @@ dependencies = [ name = "test_constructor" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1453,7 +1521,7 @@ dependencies = [ name = "test_constructor_with_result" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1461,7 +1529,7 @@ dependencies = [ name = "test_constructor_with_return_value" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1469,7 +1537,7 @@ dependencies = [ name = "test_custom_account_context" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1477,7 +1545,7 @@ dependencies = [ name = "test_delegated_account" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1485,7 +1553,7 @@ dependencies = [ name = "test_deployer" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1493,7 +1561,7 @@ dependencies = [ name = "test_deployer_with_constructor" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1501,7 +1569,7 @@ dependencies = [ name = "test_no_arg_constructor" version = "0.0.0" dependencies = [ - "soroban-env-common", + "soroban-env-common 22.0.0-rc.1", "soroban-sdk", ] @@ -1633,19 +1701,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] -name = "wasmi_collections" -version = "0.36.0-soroban.22.0.0" -source = "git+https://github.com/stellar/wasmi?rev=122a74a7c491929e5ac9de876099154ef7c06d06#122a74a7c491929e5ac9de876099154ef7c06d06" -dependencies = [ - "ahash", - "hashbrown 0.14.2", - "string-interner", -] +name = "wasmi_arena" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104a7f73be44570cac297b3035d76b169d6599637631cf37a1703326a0727073" [[package]] name = "wasmi_core" -version = "0.36.0-soroban.22.0.0" -source = "git+https://github.com/stellar/wasmi?rev=122a74a7c491929e5ac9de876099154ef7c06d06#122a74a7c491929e5ac9de876099154ef7c06d06" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf1a7db34bff95b85c261002720c00c3a6168256dcb93041d3fa2054d19856a" dependencies = [ "downcast-rs", "libm", @@ -1738,28 +1803,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" + +[[patch.unused]] +name = "soroban-env-common" +version = "22.0.0" + +[[patch.unused]] +name = "soroban-env-guest" +version = "22.0.0" + +[[patch.unused]] +name = "soroban-env-host" +version = "22.0.0" + +[[patch.unused]] +name = "soroban-sdk" +version = "22.0.0-rc.3" + +[[patch.unused]] +name = "stellar-xdr" +version = "22.0.0" diff --git a/soroban-test-wasms/wasm-workspace/Cargo.toml b/soroban-test-wasms/wasm-workspace/Cargo.toml index c10342a4a..f2a708459 100644 --- a/soroban-test-wasms/wasm-workspace/Cargo.toml +++ b/soroban-test-wasms/wasm-workspace/Cargo.toml @@ -49,7 +49,11 @@ members = [ "deployer_with_constructor", "constructor_with_return_value", "constructor_with_result", - "custom_account_context" + "custom_account_context", + "reentry_a", + "no_reentry_a", + "no_reentry_b", + "reentry_b", ] [profile.release] opt-level = "z" diff --git a/soroban-test-wasms/wasm-workspace/no_reentry_a/Cargo.toml b/soroban-test-wasms/wasm-workspace/no_reentry_a/Cargo.toml new file mode 100644 index 000000000..3a4b2553d --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/no_reentry_a/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example_no_reentry_a" +version = "0.0.0" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } +soroban-env-common = { workspace = true } + +[features] +next = ["soroban-env-common/next"] diff --git a/soroban-test-wasms/wasm-workspace/no_reentry_a/src/lib.rs b/soroban-test-wasms/wasm-workspace/no_reentry_a/src/lib.rs new file mode 100644 index 000000000..2ba311eae --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/no_reentry_a/src/lib.rs @@ -0,0 +1,31 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Address, Symbol, TryIntoVal, Vec, Val}; + +#[link(wasm_import_module = "d")] +extern "C" { + #[allow(improper_ctypes)] + #[link_name = "_"] + pub fn call_contract(contract: i64, func: i64, args: i64, ) -> i64; +} + +#[contract] +pub struct Contract; + +#[contractimpl] +impl Contract { + pub fn test_reentry(env: Env, called: Address) { + let args: Vec = (env.current_contract_address(), ).try_into_val(&env).unwrap(); + let func = Symbol::new(&env, "do_reentry"); + let called_val = called.as_val().get_payload() as i64; + let func_val = func.as_val().get_payload() as i64; + let args_val = args.as_val().get_payload() as i64; + + unsafe { + call_contract(called_val, func_val, args_val); + }; + } + + pub fn do_nothing(env: Env) { + env.events().publish((Symbol::new(&env, "first_soroban_reentry"),), ()); + } +} diff --git a/soroban-test-wasms/wasm-workspace/no_reentry_b/Cargo.toml b/soroban-test-wasms/wasm-workspace/no_reentry_b/Cargo.toml new file mode 100644 index 000000000..896871a14 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/no_reentry_b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example_no_reentry_b" +version = "0.0.0" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } +soroban-env-common = { workspace = true } + +[features] +next = ["soroban-env-common/next"] diff --git a/soroban-test-wasms/wasm-workspace/no_reentry_b/src/lib.rs b/soroban-test-wasms/wasm-workspace/no_reentry_b/src/lib.rs new file mode 100644 index 000000000..7f87ea143 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/no_reentry_b/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Val, Address, Vec, Symbol, vec}; + +#[link(wasm_import_module = "d")] +extern "C" { + #[allow(improper_ctypes)] + #[link_name = "_"] + pub fn call_reentrant(contract: i64, func: i64, args: i64, ) -> i64; +} + +#[contract] +pub struct Contract; + +#[contractimpl] +impl Contract { + pub fn do_reentry(env: Env, caller: Address) { + let args: Vec = vec![&env]; + let func = Symbol::new(&env, "do_nothing"); + let called_val = caller.as_val().get_payload() as i64; + let func_val = func.as_val().get_payload() as i64; + let args_val = args.as_val().get_payload() as i64; + + unsafe { + call_reentrant(called_val, func_val, args_val); + }; + } +} diff --git a/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_a.wasm b/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_a.wasm new file mode 100755 index 000000000..1165746cd Binary files /dev/null and b/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_a.wasm differ diff --git a/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_b.wasm b/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_b.wasm new file mode 100755 index 000000000..043b6b1b2 Binary files /dev/null and b/soroban-test-wasms/wasm-workspace/opt/23/example_no_reentry_b.wasm differ diff --git a/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_a.wasm b/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_a.wasm new file mode 100755 index 000000000..c1a48c71c Binary files /dev/null and b/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_a.wasm differ diff --git a/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_b.wasm b/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_b.wasm new file mode 100755 index 000000000..6a2e63a7a Binary files /dev/null and b/soroban-test-wasms/wasm-workspace/opt/23/example_reentry_b.wasm differ diff --git a/soroban-test-wasms/wasm-workspace/reentry_a/Cargo.toml b/soroban-test-wasms/wasm-workspace/reentry_a/Cargo.toml new file mode 100644 index 000000000..d725bfddf --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/reentry_a/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example_reentry_a" +version = "0.0.0" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } +soroban-env-common = { workspace = true } + +[features] +next = ["soroban-env-common/next"] diff --git a/soroban-test-wasms/wasm-workspace/reentry_a/src/lib.rs b/soroban-test-wasms/wasm-workspace/reentry_a/src/lib.rs new file mode 100644 index 000000000..f87124a04 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/reentry_a/src/lib.rs @@ -0,0 +1,38 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Address, Symbol, TryIntoVal, Vec, Val}; + +#[link(wasm_import_module = "d")] +extern "C" { + #[allow(improper_ctypes)] + #[link_name = "_"] + pub fn call_contract(contract: i64, func: i64, args: i64, ) -> i64; + + #[allow(improper_ctypes)] + #[link_name = "3"] + pub fn set_reentrant(enabled: i64, ) -> i64; +} + +#[contract] +pub struct Contract; + +#[contractimpl] +impl Contract { + pub fn test_reentry(env: Env, called: Address) { + let args: Vec = (env.current_contract_address(), ).try_into_val(&env).unwrap(); + let func = Symbol::new(&env, "do_reentry"); + let called_val = called.as_val().get_payload() as i64; + let func_val = func.as_val().get_payload() as i64; + let args_val = args.as_val().get_payload() as i64; + + let set_reentrant_flag = Val::from_bool(true).as_val().get_payload() as i64; + + unsafe { + set_reentrant(set_reentrant_flag); + call_contract(called_val, func_val, args_val); + }; + } + + pub fn do_nothing(env: Env) { + env.events().publish((Symbol::new(&env, "first_soroban_reentry"),), ()); + } +} diff --git a/soroban-test-wasms/wasm-workspace/reentry_b/Cargo.toml b/soroban-test-wasms/wasm-workspace/reentry_b/Cargo.toml new file mode 100644 index 000000000..34df73408 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/reentry_b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example_reentry_b" +version = "0.0.0" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +edition = "2021" +publish = false +rust-version.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[dependencies] +soroban-sdk = { workspace = true } +soroban-env-common = { workspace = true } + +[features] +next = ["soroban-env-common/next"] diff --git a/soroban-test-wasms/wasm-workspace/reentry_b/src/lib.rs b/soroban-test-wasms/wasm-workspace/reentry_b/src/lib.rs new file mode 100644 index 000000000..d175d9669 --- /dev/null +++ b/soroban-test-wasms/wasm-workspace/reentry_b/src/lib.rs @@ -0,0 +1,27 @@ +#![no_std] +use soroban_sdk::{contract, contractimpl, Env, Val, Address, Vec, Symbol, vec}; + +#[link(wasm_import_module = "d")] +extern "C" { + #[allow(improper_ctypes)] + #[link_name = "1"] + pub fn call_reentrant(contract: i64, func: i64, args: i64, ) -> i64; +} + +#[contract] +pub struct Contract; + +#[contractimpl] +impl Contract { + pub fn do_reentry(env: Env, caller: Address) { + let args: Vec = vec![&env]; + let func = Symbol::new(&env, "do_nothing"); + let called_val = caller.as_val().get_payload() as i64; + let func_val = func.as_val().get_payload() as i64; + let args_val = args.as_val().get_payload() as i64; + + unsafe { + call_reentrant(called_val, func_val, args_val); + }; + } +}