From b21da7480899fcfd5f9b8b6f44d54adb118badbb Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler <cyrill@parity.io> Date: Fri, 13 Sep 2024 12:33:51 +0200 Subject: [PATCH] [pallet-revive] uapi: allow create1 equivalent calls (#5701) The salt argument should be optional to allow create1 equivalent calls. --------- Signed-off-by: xermicus <cyrill@parity.io> --- prdoc/pr_5701.prdoc | 14 +++++++ .../fixtures/contracts/caller_contract.rs | 22 ++++++++--- .../fixtures/contracts/create1_with_value.rs | 39 +++++++++++++++++++ .../create_storage_and_instantiate.rs | 2 +- .../contracts/destroy_and_transfer.rs | 2 +- .../contracts/instantiate_return_code.rs | 2 +- substrate/frame/revive/src/tests.rs | 22 +++++++++++ substrate/frame/revive/uapi/src/host.rs | 2 +- .../frame/revive/uapi/src/host/riscv32.rs | 5 ++- 9 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 prdoc/pr_5701.prdoc create mode 100644 substrate/frame/revive/fixtures/contracts/create1_with_value.rs diff --git a/prdoc/pr_5701.prdoc b/prdoc/pr_5701.prdoc new file mode 100644 index 00000000000..3d237eb34e7 --- /dev/null +++ b/prdoc/pr_5701.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] uapi: allow create1 equivalent calls" + +doc: + - audience: Runtime Dev + description: | + The salt argument should be optional to allow create1 equivalent calls. + +crates: + - name: pallet-revive + bump: minor + - name: pallet-revive-uapi + bump: major + - name: pallet-revive-fixtures + bump: patch diff --git a/substrate/frame/revive/fixtures/contracts/caller_contract.rs b/substrate/frame/revive/fixtures/contracts/caller_contract.rs index eb29fca87c1..f9a30b87df4 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_contract.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_contract.rs @@ -49,25 +49,35 @@ pub extern "C" fn call() { &reverted_input, None, None, - &salt, + Some(&salt), ); assert!(matches!(res, Err(ReturnErrorCode::CalleeReverted))); // Fail to deploy the contract due to insufficient ref_time weight. let res = api::instantiate( - code_hash, 1u64, // too little ref_time weight + code_hash, + 1u64, // too little ref_time weight 0u64, // How much proof_size weight to devote for the execution. 0 = all. None, // No deposit limit. - &value, &input, None, None, &salt, + &value, + &input, + None, + None, + Some(&salt), ); assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); // Fail to deploy the contract due to insufficient proof_size weight. let res = api::instantiate( - code_hash, 0u64, // How much ref_time weight to devote for the execution. 0 = all. + code_hash, + 0u64, // How much ref_time weight to devote for the execution. 0 = all. 1u64, // Too little proof_size weight None, // No deposit limit. - &value, &input, None, None, &salt, + &value, + &input, + None, + None, + Some(&salt), ); assert!(matches!(res, Err(ReturnErrorCode::CalleeTrapped))); @@ -83,7 +93,7 @@ pub extern "C" fn call() { &input, Some(&mut callee), None, - &salt, + Some(&salt), ) .unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/create1_with_value.rs b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs new file mode 100644 index 00000000000..644777aff99 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs @@ -0,0 +1,39 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![no_std] +#![no_main] + +use common::{input, u256_bytes}; +use uapi::{HostFn, HostFnImpl as api, ReturnErrorCode}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + input!(code_hash: &[u8; 32],); + + let mut value = [0; 32]; + api::value_transferred(&mut value); + + // Deploy the contract with no salt (equivalent to create1). + let ret = api::instantiate(code_hash, 0u64, 0u64, None, &value, &[], None, None, None); + assert!(ret.is_ok()); +} diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs index e1372e2eb8b..463706457a1 100644 --- a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs +++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs @@ -48,7 +48,7 @@ pub extern "C" fn call() { input, Some(&mut address), None, - &salt, + Some(&salt), ) .unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs index d381db8e398..8342f4acf95 100644 --- a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs +++ b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs @@ -42,7 +42,7 @@ pub extern "C" fn deploy() { &input, Some(&mut address), None, - &salt, + Some(&salt), ) .unwrap(); diff --git a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs index c5736850960..9764859c619 100644 --- a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs +++ b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs @@ -41,7 +41,7 @@ pub extern "C" fn call() { input, None, None, - &[0u8; 32], // Salt. + Some(&[0u8; 32]), // Salt. ) { Ok(_) => 0u32, Err(code) => code as u32, diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 80c49849464..c7185caf0ef 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4232,4 +4232,26 @@ mod run_tests { assert_ok!(builder::call(addr_caller).data(addr_callee.encode()).build()); }); } + + #[test] + fn create1_with_value_works() { + let (code, code_hash) = compile_module("create1_with_value").unwrap(); + let value = 42; + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = <Test as Config>::Currency::set_balance(&ALICE, 1_000_000); + + // Create the contract: Constructor does nothing. + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: Deploys itself using create1 and the expected value + assert_ok!(builder::call(addr).value(value).data(code_hash.encode()).build()); + + // We should see the expected balance at the expected account + let address = crate::address::create1(&addr, 0); + let account_id = <Test as Config>::AddressMapper::to_account_id(&address); + let usable_balance = <Test as Config>::Currency::usable_balance(&account_id); + assert_eq!(usable_balance, value); + }); + } } diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 0c9dce3fb38..538de7ea251 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -409,7 +409,7 @@ pub trait HostFn: private::Sealed { input: &[u8], address: Option<&mut [u8; 20]>, output: Option<&mut &mut [u8]>, - salt: &[u8; 32], + salt: Option<&[u8; 32]>, ) -> Result; /// Checks whether a specified address belongs to a contract. diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index 908d4f52520..0bb0ede4543 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -198,7 +198,7 @@ impl HostFn for HostFnImpl { input: &[u8], mut address: Option<&mut [u8; 20]>, mut output: Option<&mut &mut [u8]>, - salt: &[u8; 32], + salt: Option<&[u8; 32]>, ) -> Result { let address = match address { Some(ref mut data) => data.as_mut_ptr(), @@ -206,6 +206,7 @@ impl HostFn for HostFnImpl { }; let (output_ptr, mut output_len) = ptr_len_or_sentinel(&mut output); let deposit_limit_ptr = ptr_or_sentinel(&deposit_limit); + let salt_ptr = ptr_or_sentinel(&salt); #[repr(packed)] #[allow(dead_code)] struct Args { @@ -232,7 +233,7 @@ impl HostFn for HostFnImpl { address, output: output_ptr, output_len: &mut output_len as *mut _, - salt: salt.as_ptr(), + salt: salt_ptr, }; let ret_code = { unsafe { sys::instantiate(&args as *const Args as *const _) } }; -- GitLab