From 020cda338b0c3a5c46d488d4bbf8efc339f05d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Thei=C3=9Fen?= <alex.theissen@me.com> Date: Tue, 3 Sep 2024 12:26:00 +0200 Subject: [PATCH] revive: Make `salt` salt optional to allow for CREATE1 semantics (#5556) Before we only supported CREATE2 semantics for contract address derivations. In order to be compatible we also want to allow CREATE1 semantics. We accomplish this to make the salt an `Option` in all places where it is used. Supplying `None` will use CREATE1 semantics by just using the deployers account nonce. ## Todo - [x] Add new tests specific for CREATE1 --- prdoc/pr_5556.prdoc | 11 ++++ substrate/bin/node/runtime/src/lib.rs | 2 +- substrate/frame/revive/src/address.rs | 1 - .../frame/revive/src/benchmarking/mod.rs | 10 ++- substrate/frame/revive/src/exec.rs | 45 +++++++------ substrate/frame/revive/src/lib.rs | 24 +++---- .../frame/revive/src/test_utils/builder.rs | 12 ++-- substrate/frame/revive/src/tests.rs | 63 +++++++++++++++---- .../frame/revive/src/tests/test_debug.rs | 4 +- substrate/frame/revive/src/wasm/runtime.rs | 32 ++++++---- 10 files changed, 133 insertions(+), 71 deletions(-) create mode 100644 prdoc/pr_5556.prdoc diff --git a/prdoc/pr_5556.prdoc b/prdoc/pr_5556.prdoc new file mode 100644 index 00000000000..4865ec1e338 --- /dev/null +++ b/prdoc/pr_5556.prdoc @@ -0,0 +1,11 @@ +title: Make salt optional + +doc: + - audience: Runtime Dev + description: | + By making salt optional we allow clients to use CREATE1 semantics + when deploying a new contract. + +crates: + - name: pallet-revive + bump: major diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 7ef0779dd9b..31584427b3b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -3017,7 +3017,7 @@ impl_runtime_apis! { storage_deposit_limit: Option<Balance>, code: pallet_revive::Code, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> pallet_revive::ContractInstantiateResult<Balance, EventRecord> { Revive::bare_instantiate( diff --git a/substrate/frame/revive/src/address.rs b/substrate/frame/revive/src/address.rs index f1bd36dcbba..c51940ba771 100644 --- a/substrate/frame/revive/src/address.rs +++ b/substrate/frame/revive/src/address.rs @@ -76,7 +76,6 @@ impl AddressMapper<AccountId32> for DefaultAddressMapper { } /// Determine the address of a contract using CREATE semantics. -#[allow(dead_code)] pub fn create1(deployer: &H160, nonce: u64) -> H160 { let mut list = rlp::RlpStream::new_list(2); list.append(&deployer.as_bytes()); diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 409d53b8a06..3ffd53e3561 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -94,7 +94,7 @@ where data: Vec<u8>, ) -> Result<Contract<T>, &'static str> { T::Currency::set_balance(&caller, caller_funding::<T>()); - let salt = [0xffu8; 32]; + let salt = Some([0xffu8; 32]); let outcome = Contracts::<T>::bare_instantiate( RawOrigin::Signed(caller.clone()).into(), @@ -344,7 +344,6 @@ mod benchmarks { // `c`: Size of the code in bytes. // `i`: Size of the input in bytes. - // `s`: Size of the salt in bytes. #[benchmark(pov_mode = Measured)] fn instantiate_with_code( c: Linear<0, { T::MaxCodeLen::get() }>, @@ -362,7 +361,7 @@ mod benchmarks { let account_id = T::AddressMapper::to_account_id_contract(&addr); let storage_deposit = default_deposit_limit::<T>(); #[extrinsic_call] - _(origin, value, Weight::MAX, storage_deposit, code, input, salt); + _(origin, value, Weight::MAX, storage_deposit, code, input, Some(salt)); let deposit = T::Currency::balance_on_hold(&HoldReason::StorageDepositReserve.into(), &account_id); @@ -378,7 +377,7 @@ mod benchmarks { } // `i`: Size of the input in bytes. - // `s`: Size of the salt in bytes. + // `s`: Size of e salt in bytes. #[benchmark(pov_mode = Measured)] fn instantiate(i: Linear<0, { limits::MEMORY_BYTES }>) -> Result<(), BenchmarkError> { let input = vec![42u8; i as usize]; @@ -403,7 +402,7 @@ mod benchmarks { storage_deposit, hash, input, - salt, + Some(salt), ); let deposit = @@ -1529,7 +1528,6 @@ mod benchmarks { // t: value to transfer // i: size of input in bytes - // s: size of salt in bytes #[benchmark(pov_mode = Measured)] fn seal_instantiate(i: Linear<0, { limits::MEMORY_BYTES }>) -> Result<(), BenchmarkError> { let code = WasmModule::dummy(); diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 54019a6ba99..649479f7790 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -54,7 +54,7 @@ use sp_core::{ use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::{ traits::{BadOrigin, Convert, Dispatchable, Zero}, - DispatchError, + DispatchError, SaturatedConversion, }; pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId; @@ -213,7 +213,7 @@ pub trait Ext: sealing::Sealed { code: H256, value: BalanceOf<Self::T>, input_data: Vec<u8>, - salt: &[u8; 32], + salt: Option<&[u8; 32]>, ) -> Result<(H160, ExecReturnValue), ExecError>; /// Transfer all funds to `beneficiary` and delete the contract. @@ -573,7 +573,7 @@ enum FrameArgs<'a, T: Config, E> { /// The executable whose `deploy` function is run. executable: E, /// A salt used in the contract address derivation of the new contract. - salt: &'a [u8; 32], + salt: Option<&'a [u8; 32]>, /// The input data is used in the contract address derivation of the new contract. input_data: &'a [u8], }, @@ -750,7 +750,7 @@ where storage_meter: &'a mut storage::meter::Meter<T>, value: BalanceOf<T>, input_data: Vec<u8>, - salt: &[u8; 32], + salt: Option<&[u8; 32]>, debug_message: Option<&'a mut DebugBuffer>, ) -> Result<(H160, ExecReturnValue), ExecError> { let (mut stack, executable) = Self::new( @@ -863,7 +863,12 @@ where }, FrameArgs::Instantiate { sender, executable, salt, input_data } => { let deployer = T::AddressMapper::to_address(&sender); - let address = address::create2(&deployer, executable.code(), input_data, salt); + let account_nonce = <System<T>>::account_nonce(&sender); + let address = if let Some(salt) = salt { + address::create2(&deployer, executable.code(), input_data, salt) + } else { + address::create1(&deployer, account_nonce.saturated_into()) + }; let contract = ContractInfo::new( &address, <System<T>>::account_nonce(&sender), @@ -1321,7 +1326,7 @@ where code_hash: H256, value: BalanceOf<T>, input_data: Vec<u8>, - salt: &[u8; 32], + salt: Option<&[u8; 32]>, ) -> Result<(H160, ExecReturnValue), ExecError> { let executable = E::from_storage(code_hash, self.gas_meter_mut())?; let sender = &self.top_frame().account_id; @@ -2088,7 +2093,7 @@ mod tests { &mut storage_meter, min_balance, vec![1, 2, 3, 4], - &[0; 32], + Some(&[0; 32]), None, ); assert_matches!(result, Ok(_)); @@ -2497,7 +2502,7 @@ mod tests { &mut storage_meter, 0, // <- zero value vec![], - &[0; 32], + Some(&[0; 32]), None, ), Err(_) @@ -2533,7 +2538,7 @@ mod tests { min_balance, vec![], - &[0;32], + Some(&[0 ;32]), None, ), Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address @@ -2587,7 +2592,7 @@ mod tests { min_balance, vec![], - &[0;32], + Some(&[0; 32]), None, ), Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address @@ -2620,7 +2625,7 @@ mod tests { dummy_ch, <Test as Config>::Currency::minimum_balance(), vec![], - &[48; 32], + Some(&[48; 32]), ) .unwrap(); @@ -2698,7 +2703,7 @@ mod tests { dummy_ch, <Test as Config>::Currency::minimum_balance(), vec![], - &[0; 32], + Some(&[0; 32]), ), Err(ExecError { error: DispatchError::Other("It's a trap!"), @@ -2771,7 +2776,7 @@ mod tests { &mut storage_meter, 100, vec![], - &[0; 32], + Some(&[0; 32]), None, ), Err(Error::<Test>::TerminatedInConstructor.into()) @@ -2882,7 +2887,7 @@ mod tests { &mut storage_meter, min_balance, vec![], - &[0; 32], + Some(&[0; 32]), None, ); assert_matches!(result, Ok(_)); @@ -3250,7 +3255,7 @@ mod tests { fail_code, ctx.ext.minimum_balance() * 100, vec![], - &[0; 32], + Some(&[0; 32]), ) .ok(); exec_success() @@ -3267,7 +3272,7 @@ mod tests { success_code, ctx.ext.minimum_balance() * 100, vec![], - &[0; 32], + Some(&[0; 32]), ) .unwrap(); @@ -3318,7 +3323,7 @@ mod tests { &mut storage_meter, min_balance * 100, vec![], - &[0; 32], + Some(&[0; 32]), None, ) .ok(); @@ -3331,7 +3336,7 @@ mod tests { &mut storage_meter, min_balance * 100, vec![], - &[0; 32], + Some(&[0; 32]), None, )); assert_eq!(System::account_nonce(&ALICE), 1); @@ -3343,7 +3348,7 @@ mod tests { &mut storage_meter, min_balance * 200, vec![], - &[0; 32], + Some(&[0; 32]), None, )); assert_eq!(System::account_nonce(&ALICE), 2); @@ -3355,7 +3360,7 @@ mod tests { &mut storage_meter, min_balance * 200, vec![], - &[0; 32], + Some(&[0; 32]), None, )); assert_eq!(System::account_nonce(&ALICE), 3); diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs index 359434b9abd..9a99b01776c 100644 --- a/substrate/frame/revive/src/lib.rs +++ b/substrate/frame/revive/src/lib.rs @@ -824,7 +824,7 @@ pub mod pallet { /// must be supplied. #[pallet::call_index(1)] #[pallet::weight( - T::WeightInfo::instantiate(data.len() as u32, salt.len() as u32).saturating_add(*gas_limit) + T::WeightInfo::instantiate(data.len() as u32, 32).saturating_add(*gas_limit) )] pub fn instantiate( origin: OriginFor<T>, @@ -833,10 +833,9 @@ pub mod pallet { #[pallet::compact] storage_deposit_limit: BalanceOf<T>, code_hash: sp_core::H256, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> DispatchResultWithPostInfo { let data_len = data.len() as u32; - let salt_len = salt.len() as u32; let mut output = Self::bare_instantiate( origin, value, @@ -856,7 +855,7 @@ pub mod pallet { dispatch_result( output.result.map(|result| result.result), output.gas_consumed, - T::WeightInfo::instantiate(data_len, salt_len), + T::WeightInfo::instantiate(data_len, 32), ) } @@ -875,7 +874,9 @@ pub mod pallet { /// from the caller to pay for the storage consumed. /// * `code`: The contract code to deploy in raw bytes. /// * `data`: The input data to pass to the contract constructor. - /// * `salt`: Used for the address derivation. See [`crate::address::create2`]. + /// * `salt`: Used for the address derivation. If `Some` is supplied then `CREATE2` + /// semantics are used. If `None` then `CRATE1` is used. + /// /// /// Instantiation is executed as follows: /// @@ -887,7 +888,7 @@ pub mod pallet { /// - The `deploy` function is executed in the context of the newly-created account. #[pallet::call_index(2)] #[pallet::weight( - T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, salt.len() as u32) + T::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32, 32) .saturating_add(*gas_limit) )] pub fn instantiate_with_code( @@ -897,11 +898,10 @@ pub mod pallet { #[pallet::compact] storage_deposit_limit: BalanceOf<T>, code: Vec<u8>, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> DispatchResultWithPostInfo { let code_len = code.len() as u32; let data_len = data.len() as u32; - let salt_len = salt.len() as u32; let mut output = Self::bare_instantiate( origin, value, @@ -921,7 +921,7 @@ pub mod pallet { dispatch_result( output.result.map(|result| result.result), output.gas_consumed, - T::WeightInfo::instantiate_with_code(code_len, data_len, salt_len), + T::WeightInfo::instantiate_with_code(code_len, data_len, 32), ) } @@ -1122,7 +1122,7 @@ impl<T: Config> Pallet<T> { mut storage_deposit_limit: BalanceOf<T>, code: Code, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, ) -> ContractInstantiateResult<BalanceOf<T>, EventRecordOf<T>> { @@ -1158,7 +1158,7 @@ impl<T: Config> Pallet<T> { &mut storage_meter, value, data, - &salt, + salt.as_ref(), debug_message.as_mut(), ); storage_deposit = storage_meter @@ -1298,7 +1298,7 @@ sp_api::decl_runtime_apis! { storage_deposit_limit: Option<Balance>, code: Code, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> ContractInstantiateResult<Balance, EventRecord>; /// Upload new code without instantiating a contract from it. diff --git a/substrate/frame/revive/src/test_utils/builder.rs b/substrate/frame/revive/src/test_utils/builder.rs index 76b4c98d4cb..b17067769c0 100644 --- a/substrate/frame/revive/src/test_utils/builder.rs +++ b/substrate/frame/revive/src/test_utils/builder.rs @@ -88,7 +88,7 @@ builder!( storage_deposit_limit: BalanceOf<T>, code: Vec<u8>, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> DispatchResultWithPostInfo; /// Create an [`InstantiateWithCodeBuilder`] with default values. @@ -100,7 +100,7 @@ builder!( storage_deposit_limit: deposit_limit::<T>(), code, data: vec![], - salt: [0; 32], + salt: Some([0; 32]), } } ); @@ -113,7 +113,7 @@ builder!( storage_deposit_limit: BalanceOf<T>, code_hash: sp_core::H256, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, ) -> DispatchResultWithPostInfo; /// Create an [`InstantiateBuilder`] with default values. @@ -125,7 +125,7 @@ builder!( storage_deposit_limit: deposit_limit::<T>(), code_hash, data: vec![], - salt: [0; 32], + salt: Some([0; 32]), } } ); @@ -138,7 +138,7 @@ builder!( storage_deposit_limit: BalanceOf<T>, code: Code, data: Vec<u8>, - salt: [u8; 32], + salt: Option<[u8; 32]>, debug: DebugInfo, collect_events: CollectEvents, ) -> ContractInstantiateResult<BalanceOf<T>, EventRecordOf<T>>; @@ -164,7 +164,7 @@ builder!( storage_deposit_limit: deposit_limit::<T>(), code, data: vec![], - salt: [0; 32], + salt: Some([0; 32]), debug: DebugInfo::UnsafeDebug, collect_events: CollectEvents::Skip, } diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index a37e9842a2c..447d55f0dd8 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -26,7 +26,7 @@ use self::{ }; use crate::{ self as pallet_revive, - address::AddressMapper, + address::{create1, create2, AddressMapper}, chain_extension::{ ChainExtension, Environment, Ext, RegisteredChainExtension, Result as ExtensionResult, RetVal, ReturnFlags, @@ -771,6 +771,47 @@ mod run_tests { }); } + #[test] + fn create1_address_from_extrinsic() { + let (wasm, code_hash) = compile_module("dummy").unwrap(); + + ExtBuilder::default().existential_deposit(1).build().execute_with(|| { + let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000); + + assert_ok!(Contracts::upload_code( + RuntimeOrigin::signed(ALICE), + wasm.clone(), + deposit_limit::<Test>(), + )); + + assert_eq!(System::account_nonce(&ALICE), 0); + + for nonce in 0..3 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Existing(code_hash)) + .salt(None) + .build_and_unwrap_contract(); + assert!(ContractInfoOf::<Test>::contains_key(&addr)); + assert_eq!( + addr, + create1(&<Test as Config>::AddressMapper::to_address(&ALICE), nonce) + ); + } + assert_eq!(System::account_nonce(&ALICE), 3); + + for nonce in 3..6 { + let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) + .salt(None) + .build_and_unwrap_contract(); + assert!(ContractInfoOf::<Test>::contains_key(&addr)); + assert_eq!( + addr, + create1(&<Test as Config>::AddressMapper::to_address(&ALICE), nonce) + ); + } + assert_eq!(System::account_nonce(&ALICE), 6); + }); + } + #[test] fn deposit_event_max_value_limit() { let (wasm, _code_hash) = compile_module("event_size").unwrap(); @@ -1023,7 +1064,7 @@ mod run_tests { .value(100_000) .build_and_unwrap_contract(); - let callee_addr = crate::address::create2( + let callee_addr = create2( &caller_addr, &callee_wasm, &[0, 1, 34, 51, 68, 85, 102, 119], // hard coded in wasm @@ -1410,7 +1451,7 @@ mod run_tests { // Check that the CHARLIE contract has been instantiated. let salt = [47; 32]; // hard coded in fixture. - let addr_charlie = crate::address::create2(&addr_bob, &callee_wasm, &[], &salt); + let addr_charlie = create2(&addr_bob, &callee_wasm, &[], &salt); get_contract(&addr_charlie); // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. @@ -1759,7 +1800,7 @@ mod run_tests { for i in 0..3u8 { let contract = builder::bare_instantiate(Code::Upload(code.clone())) .value(min_balance * 100) - .salt([i; 32]) + .salt(Some([i; 32])) .build_and_unwrap_contract(); let info = get_contract(&contract.addr); @@ -2000,7 +2041,7 @@ mod run_tests { for i in 0..3u8 { let Contract { addr, .. } = builder::bare_instantiate(Code::Upload(code.clone())) .value(min_balance * 100) - .salt([i; 32]) + .salt(Some([i; 32])) .build_and_unwrap_contract(); let info = get_contract(&addr); @@ -2042,19 +2083,19 @@ mod run_tests { let Contract { addr: addr0, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) .value(min_balance * 100) - .salt([0; 32]) + .salt(Some([0; 32])) .build_and_unwrap_contract(); let Contract { addr: addr1, .. } = builder::bare_instantiate(Code::Upload(wasm.clone())) .value(min_balance * 100) - .salt([1; 32]) + .salt(Some([1; 32])) .build_and_unwrap_contract(); assert_refcount!(code_hash, 2); // Sharing should also work with the usual instantiate call let Contract { addr: addr2, .. } = builder::bare_instantiate(Code::Existing(code_hash)) .value(min_balance * 100) - .salt([2; 32]) + .salt(Some([2; 32])) .build_and_unwrap_contract(); assert_refcount!(code_hash, 3); @@ -2241,7 +2282,7 @@ mod run_tests { let Contract { addr: addr_caller, .. } = builder::bare_instantiate(Code::Upload(caller_code)) .value(min_balance * 100) - .salt([0; 32]) + .salt(Some([0; 32])) .build_and_unwrap_contract(); // Call something trivial with a huge gas limit so that we can observe the effects @@ -2279,13 +2320,13 @@ mod run_tests { let Contract { addr: addr_caller, .. } = builder::bare_instantiate(Code::Upload(caller_code)) .value(min_balance * 100) - .salt([0; 32]) + .salt(Some([0; 32])) .build_and_unwrap_contract(); let Contract { addr: addr_callee, .. } = builder::bare_instantiate(Code::Upload(callee_code)) .value(min_balance * 100) - .salt([1; 32]) + .salt(Some([1; 32])) .build_and_unwrap_contract(); // Call pallet_revive call() dispatchable diff --git a/substrate/frame/revive/src/tests/test_debug.rs b/substrate/frame/revive/src/tests/test_debug.rs index e3571b7f21e..7885d681e48 100644 --- a/substrate/frame/revive/src/tests/test_debug.rs +++ b/substrate/frame/revive/src/tests/test_debug.rs @@ -122,7 +122,7 @@ mod run_tests { deposit_limit::<Test>(), Code::Upload(wasm), vec![], - [0u8; 32], + Some([0u8; 32]), DebugInfo::Skip, CollectEvents::Skip, ) @@ -207,7 +207,7 @@ mod run_tests { Code::Upload(wasm), vec![], // some salt to ensure that the address of this contract is unique among all tests - [0x41; 32], + Some([0x41; 32]), DebugInfo::Skip, CollectEvents::Skip, ) diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 70d405da989..533baf8d2c8 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -327,8 +327,8 @@ pub enum RuntimeCosts { CallTransferSurcharge, /// Weight per byte that is cloned by supplying the `CLONE_INPUT` flag. CallInputCloned(u32), - /// Weight of calling `seal_instantiate` for the given input length and salt. - Instantiate { input_data_len: u32, salt_len: u32 }, + /// Weight of calling `seal_instantiate` for the given input lenth. + Instantiate { input_data_len: u32 }, /// Weight of calling `seal_hash_sha_256` for the given input size. HashSha256(u32), /// Weight of calling `seal_hash_keccak_256` for the given input size. @@ -453,8 +453,7 @@ impl<T: Config> Token<T> for RuntimeCosts { DelegateCallBase => T::WeightInfo::seal_delegate_call(), CallTransferSurcharge => cost_args!(seal_call, 1, 0), CallInputCloned(len) => cost_args!(seal_call, 0, len), - Instantiate { input_data_len, salt_len } => - T::WeightInfo::seal_instantiate(input_data_len, salt_len), + Instantiate { input_data_len } => T::WeightInfo::seal_instantiate(input_data_len, 32), HashSha256(len) => T::WeightInfo::seal_hash_sha2_256(len), HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len), HashBlake256(len) => T::WeightInfo::seal_hash_blake2_256(len), @@ -1015,9 +1014,8 @@ impl<'a, E: Ext, M: ?Sized + Memory<E::T>> Runtime<'a, E, M> { output_ptr: u32, output_len_ptr: u32, salt_ptr: u32, - salt_len: u32, ) -> Result<ReturnErrorCode, TrapReason> { - self.charge_gas(RuntimeCosts::Instantiate { input_data_len, salt_len })?; + self.charge_gas(RuntimeCosts::Instantiate { input_data_len })?; let deposit_limit: BalanceOf<<E as Ext>::T> = if deposit_ptr == SENTINEL { BalanceOf::<<E as Ext>::T>::zero() } else { @@ -1026,10 +1024,21 @@ impl<'a, E: Ext, M: ?Sized + Memory<E::T>> Runtime<'a, E, M> { let value: BalanceOf<<E as Ext>::T> = memory.read_as(value_ptr)?; let code_hash: H256 = memory.read_as(code_hash_ptr)?; let input_data = memory.read(input_data_ptr, input_data_len)?; - let mut salt = [0u8; 32]; - memory.read_into_buf(salt_ptr, salt.as_mut_slice())?; - let instantiate_outcome = - self.ext.instantiate(weight, deposit_limit, code_hash, value, input_data, &salt); + let salt = if salt_ptr == SENTINEL { + None + } else { + let mut salt = [0u8; 32]; + memory.read_into_buf(salt_ptr, salt.as_mut_slice())?; + Some(salt) + }; + let instantiate_outcome = self.ext.instantiate( + weight, + deposit_limit, + code_hash, + value, + input_data, + salt.as_ref(), + ); if let Ok((address, output)) = &instantiate_outcome { if !output.flags.contains(ReturnFlags::REVERT) { self.write_sandbox_output( @@ -1253,7 +1262,7 @@ pub mod env { output_ptr: u32, output_len_ptr: u32, salt_ptr: u32, - salt_len: u32, + _salt_len: u32, ) -> Result<ReturnErrorCode, TrapReason> { self.instantiate( memory, @@ -1268,7 +1277,6 @@ pub mod env { output_ptr, output_len_ptr, salt_ptr, - salt_len, ) } -- GitLab