diff --git a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs index ea438f80552e..3b1779e40b60 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/people/people-westend/src/tests/governance.rs @@ -396,7 +396,7 @@ fn relay_commands_add_remove_username_authority() { ); }); - // Now, remove the username authority with another priviledged XCM call. + // Now, remove the username authority with another privileged XCM call. Westend::execute_with(|| { type Runtime = ::Runtime; type RuntimeCall = ::RuntimeCall; diff --git a/prdoc/pr_6890.prdoc b/prdoc/pr_6890.prdoc new file mode 100644 index 000000000000..286d89222723 --- /dev/null +++ b/prdoc/pr_6890.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Bound resources for nested EVM contract calls + +doc: + - audience: [ Runtime Dev, Runtime User ] + description: | + Implementation of EIP-150 for `pallet-revive`-based EVM contracts. + +crates: + - name: pallet-revive + bump: minor diff --git a/substrate/frame/revive/fixtures/contracts/call.rs b/substrate/frame/revive/fixtures/contracts/call.rs index ee51548879d9..2b41b7d8fe09 100644 --- a/substrate/frame/revive/fixtures/contracts/call.rs +++ b/substrate/frame/revive/fixtures/contracts/call.rs @@ -38,8 +38,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. None, // No deposit limit. &[0u8; 32], // Value transferred to the contract. callee_input, diff --git a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs index 129adde2cec9..1e9048588c5c 100644 --- a/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs +++ b/substrate/frame/revive/fixtures/contracts/call_diverging_out_len.rs @@ -42,8 +42,8 @@ fn assert_call(callee_address: &[u8; 20], expected_output: [u8; api::call( uapi::CallFlags::ALLOW_REENTRY, callee_address, - 0u64, - 0u64, + u64::MAX, + u64::MAX, None, &[0u8; 32], &[], @@ -67,8 +67,8 @@ fn assert_instantiate(expected_output: [u8; BUF_SIZE]) { api::instantiate( &code_hash, - 0u64, - 0u64, + u64::MAX, + u64::MAX, None, &[0; 32], &[0; 32], diff --git a/substrate/frame/revive/fixtures/contracts/call_return_code.rs b/substrate/frame/revive/fixtures/contracts/call_return_code.rs index 2d13b9f70956..4cbc925eaaed 100644 --- a/substrate/frame/revive/fixtures/contracts/call_return_code.rs +++ b/substrate/frame/revive/fixtures/contracts/call_return_code.rs @@ -42,8 +42,8 @@ pub extern "C" fn call() { let err_code = match api::call( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. None, // No deposit limit. value, // Value transferred to the contract. input, diff --git a/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs b/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs index 8c8aee962849..a3e1c2394cfd 100644 --- a/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs +++ b/substrate/frame/revive/fixtures/contracts/call_runtime_and_call.rs @@ -42,8 +42,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), callee_addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. None, // No deposit limit. &[0u8; 32], // Value transferred to the contract. callee_input, diff --git a/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs b/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs index 330393e706e9..703dd00fb7f9 100644 --- a/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs +++ b/substrate/frame/revive/fixtures/contracts/call_with_flags_and_value.rs @@ -40,8 +40,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::from_bits(flags).unwrap(), callee_addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. None, // No deposit limit. &u256_bytes(value), // Value transferred to the contract. forwarded_input, diff --git a/substrate/frame/revive/fixtures/contracts/caller_contract.rs b/substrate/frame/revive/fixtures/contracts/caller_contract.rs index edad43fae251..e5cbbc116997 100644 --- a/substrate/frame/revive/fixtures/contracts/caller_contract.rs +++ b/substrate/frame/revive/fixtures/contracts/caller_contract.rs @@ -42,8 +42,8 @@ pub extern "C" fn call() { // Fail to deploy the contract since it returns a non-zero exit status. let res = api::instantiate( code_hash, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &reverted_input, @@ -57,7 +57,7 @@ pub extern "C" fn call() { let res = api::instantiate( code_hash, 1u64, // too little ref_time weight - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &input, @@ -70,7 +70,7 @@ pub extern "C" fn call() { // 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. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. 1u64, // Too little proof_size weight None, // No deposit limit. &value, @@ -86,8 +86,8 @@ pub extern "C" fn call() { api::instantiate( code_hash, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &input, @@ -101,8 +101,8 @@ pub extern "C" fn call() { let res = api::call( uapi::CallFlags::empty(), &callee, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &reverted_input, @@ -115,7 +115,7 @@ pub extern "C" fn call() { uapi::CallFlags::empty(), &callee, 1u64, // Too little ref_time weight. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &input, @@ -127,7 +127,7 @@ pub extern "C" fn call() { let res = api::call( uapi::CallFlags::empty(), &callee, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. 1u64, // too little proof_size weight None, // No deposit limit. &value, @@ -141,8 +141,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), &callee, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &value, &input, diff --git a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs b/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs index 22d6c5b548d8..a6e4720c0563 100644 --- a/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs +++ b/substrate/frame/revive/fixtures/contracts/chain_extension_temp_storage.rs @@ -54,8 +54,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::ALLOW_REENTRY, &addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = use all. None, // No deposit limit. &[0u8; 32], // Value transferred to the contract. input, diff --git a/substrate/frame/revive/fixtures/contracts/create1_with_value.rs b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs index c6adab828860..29c7b9f2ed81 100644 --- a/substrate/frame/revive/fixtures/contracts/create1_with_value.rs +++ b/substrate/frame/revive/fixtures/contracts/create1_with_value.rs @@ -34,6 +34,6 @@ pub extern "C" fn call() { 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); + let ret = api::instantiate(code_hash, u64::MAX, u64::MAX, None, &value, &[], None, None, None); assert!(ret.is_ok()); } diff --git a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs index a12c36af856a..429efde51c65 100644 --- a/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs +++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_call.rs @@ -43,8 +43,8 @@ pub extern "C" fn call() { let ret = api::call( uapi::CallFlags::empty(), callee, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all resources. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all resources. Some(deposit_limit), &[0u8; 32], // Value transferred to the contract. input, 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 ecc0fc79e6fd..c9ed851076e9 100644 --- a/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs +++ b/substrate/frame/revive/fixtures/contracts/create_storage_and_instantiate.rs @@ -41,8 +41,8 @@ pub extern "C" fn call() { let ret = api::instantiate( code_hash, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. Some(deposit_limit), &value, input, diff --git a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs index d2efb26e5ceb..66a46cf6ac32 100644 --- a/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs +++ b/substrate/frame/revive/fixtures/contracts/create_transient_storage_and_call.rs @@ -49,8 +49,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), callee, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = all. None, &[0u8; 32], // Value transferred to the contract. input, diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs index 0f157f5a18ac..2e43e1d1ff6c 100644 --- a/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs +++ b/substrate/frame/revive/fixtures/contracts/delegate_call_deposit_limit.rs @@ -34,7 +34,7 @@ pub extern "C" fn call() { ); let input = [0u8; 0]; - let ret = api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, Some(&u256_bytes(deposit_limit)), &input, None); + let ret = api::delegate_call(uapi::CallFlags::empty(), address, u64::MAX, u64::MAX, Some(&u256_bytes(deposit_limit)), &input, None); if let Err(code) = ret { api::return_value(uapi::ReturnFlags::REVERT, &(code as u32).to_le_bytes()); diff --git a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs index a8501dad4692..e9c0fb6327bb 100644 --- a/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs +++ b/substrate/frame/revive/fixtures/contracts/delegate_call_simple.rs @@ -32,5 +32,5 @@ pub extern "C" fn call() { // Delegate call into passed address. let input = [0u8; 0]; - api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &input, None).unwrap(); + api::delegate_call(uapi::CallFlags::empty(), address, u64::MAX, u64::MAX, None, &input, None).unwrap(); } diff --git a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs index 8342f4acf952..34ea1510f1a2 100644 --- a/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs +++ b/substrate/frame/revive/fixtures/contracts/destroy_and_transfer.rs @@ -35,8 +35,8 @@ pub extern "C" fn deploy() { api::instantiate( code_hash, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &VALUE, &input, @@ -62,8 +62,8 @@ pub extern "C" fn call() { let res = api::call( uapi::CallFlags::empty(), &callee_addr, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &VALUE, &[0u8; 1], @@ -75,8 +75,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), &callee_addr, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, // How much proof_size weight to devote for the execution. 0 = all. + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &VALUE, &[0u8; 0], diff --git a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs index 9764859c619b..f311f1537b49 100644 --- a/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs +++ b/substrate/frame/revive/fixtures/contracts/instantiate_return_code.rs @@ -33,9 +33,8 @@ pub extern "C" fn call() { let err_code = match api::instantiate( code_hash, - 0u64, // How much ref_time weight to devote for the execution. 0 = all. - 0u64, /* How much proof_size weight to devote for the execution. 0 = - * all. */ + u64::MAX, // How much ref_time weight to devote for the execution. u64::MAX = use all. + u64::MAX, // How much proof_size weight to devote for the execution. u64::MAX = use all. None, // No deposit limit. &u256_bytes(10_000u64), // Value to transfer. input, diff --git a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs index 3d7702c6537a..454c649f636a 100644 --- a/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs +++ b/substrate/frame/revive/fixtures/contracts/locking_delegate_dependency.rs @@ -52,7 +52,7 @@ fn load_input(delegate_call: bool) { } if delegate_call { - api::delegate_call(uapi::CallFlags::empty(), address, 0, 0, None, &[], None).unwrap(); + api::delegate_call(uapi::CallFlags::empty(), address, u64::MAX, u64::MAX, None, &[], None).unwrap(); } } diff --git a/substrate/frame/revive/fixtures/contracts/origin.rs b/substrate/frame/revive/fixtures/contracts/origin.rs index 8e9afd8e8052..bd79c58eff06 100644 --- a/substrate/frame/revive/fixtures/contracts/origin.rs +++ b/substrate/frame/revive/fixtures/contracts/origin.rs @@ -49,8 +49,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::ALLOW_REENTRY, &addr, - 0u64, - 0u64, + u64::MAX, + u64::MAX, None, &[0; 32], &[], diff --git a/substrate/frame/revive/fixtures/contracts/read_only_call.rs b/substrate/frame/revive/fixtures/contracts/read_only_call.rs index ea74d56867f5..79a44f8b1d39 100644 --- a/substrate/frame/revive/fixtures/contracts/read_only_call.rs +++ b/substrate/frame/revive/fixtures/contracts/read_only_call.rs @@ -39,8 +39,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::READ_ONLY, callee_addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = all. + u64::MAX, // How much proof_size to devote for the execution. u64::MAX = all. None, // No deposit limit. &[0u8; 32], // Value transferred to the contract. callee_input, diff --git a/substrate/frame/revive/fixtures/contracts/recurse.rs b/substrate/frame/revive/fixtures/contracts/recurse.rs index 2e70d67d8c73..2e69a777d844 100644 --- a/substrate/frame/revive/fixtures/contracts/recurse.rs +++ b/substrate/frame/revive/fixtures/contracts/recurse.rs @@ -43,8 +43,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::ALLOW_REENTRY, &addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much deposit_limit to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64::MAX = use all resources. + u64::MAX, // How much deposit_limit to devote for the execution. u64::MAX = use all resources. None, // No deposit limit. &[0u8; 32], // Value transferred to the contract. &(calls_left - 1).to_le_bytes(), diff --git a/substrate/frame/revive/fixtures/contracts/return_data_api.rs b/substrate/frame/revive/fixtures/contracts/return_data_api.rs index 2a390296a419..48a411161943 100644 --- a/substrate/frame/revive/fixtures/contracts/return_data_api.rs +++ b/substrate/frame/revive/fixtures/contracts/return_data_api.rs @@ -82,7 +82,7 @@ fn assert_return_data_size_of(expected: u64) { /// Assert the return data to be reset after a balance transfer. fn assert_balance_transfer_does_reset() { - api::call(uapi::CallFlags::empty(), &[0u8; 20], 0, 0, None, &u256_bytes(128), &[], None) + api::call(uapi::CallFlags::empty(), &[0u8; 20], u64::MAX, u64::MAX, None, &u256_bytes(128), &[], None) .unwrap(); assert_return_data_size_of(0); } @@ -113,8 +113,8 @@ pub extern "C" fn call() { let mut instantiate = |exit_flag| { api::instantiate( code_hash, - 0u64, - 0u64, + u64::MAX, + u64::MAX, None, &[0; 32], &construct_input(exit_flag), @@ -127,8 +127,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::empty(), address_buf, - 0u64, - 0u64, + u64::MAX, + u64::MAX, None, &[0; 32], &construct_input(exit_flag), diff --git a/substrate/frame/revive/fixtures/contracts/self_destruct.rs b/substrate/frame/revive/fixtures/contracts/self_destruct.rs index 2f37706634bd..ff969d4c57cc 100644 --- a/substrate/frame/revive/fixtures/contracts/self_destruct.rs +++ b/substrate/frame/revive/fixtures/contracts/self_destruct.rs @@ -42,8 +42,8 @@ pub extern "C" fn call() { api::call( uapi::CallFlags::ALLOW_REENTRY, &addr, - 0u64, // How much ref_time to devote for the execution. 0 = all. - 0u64, // How much proof_size to devote for the execution. 0 = all. + u64::MAX, // How much ref_time to devote for the execution. u64 = all. + u64::MAX, // How much proof_size to devote for the execution. u64 = all. None, // No deposit limit. &[0u8; 32], // Value to transfer. &[0u8; 0], diff --git a/substrate/frame/revive/fixtures/src/lib.rs b/substrate/frame/revive/fixtures/src/lib.rs index 24f6ee547dc7..987903f43800 100644 --- a/substrate/frame/revive/fixtures/src/lib.rs +++ b/substrate/frame/revive/fixtures/src/lib.rs @@ -22,7 +22,7 @@ extern crate alloc; // generated file that tells us where to find the fixtures include!(concat!(env!("OUT_DIR"), "/fixture_location.rs")); -/// Load a given wasm module and returns a wasm binary contents along with it's hash. +/// Load a given wasm module and returns a wasm binary contents along with its hash. #[cfg(feature = "std")] pub fn compile_module(fixture_name: &str) -> anyhow::Result<(Vec, sp_core::H256)> { let out_dir: std::path::PathBuf = FIXTURE_DIR.into(); diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 1fb4d7ab58a4..c114efb41a75 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -1567,8 +1567,8 @@ mod benchmarks { memory.as_mut_slice(), CallFlags::CLONE_INPUT.bits(), // flags 0, // callee_ptr - 0, // ref_time_limit - 0, // proof_size_limit + u64::MAX, // ref_time_limit + u64::MAX, // proof_size_limit callee_len, // deposit_ptr callee_len + deposit_len, // value_ptr 0, // input_data_ptr @@ -1607,8 +1607,8 @@ mod benchmarks { memory.as_mut_slice(), 0, // flags 0, // address_ptr - 0, // ref_time_limit - 0, // proof_size_limit + u64::MAX, // ref_time_limit + u64::MAX, // proof_size_limit address_len, // deposit_ptr 0, // input_data_ptr 0, // input_data_len @@ -1669,8 +1669,8 @@ mod benchmarks { result = runtime.bench_instantiate( memory.as_mut_slice(), 0, // code_hash_ptr - 0, // ref_time_limit - 0, // proof_size_limit + u64::MAX, // ref_time_limit + u64::MAX, // proof_size_limit offset(hash_len), // deposit_ptr offset(deposit_len), // value_ptr offset(value_len), // input_data_ptr diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index b6f0e3ae1a81..b3292d703400 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -53,7 +53,7 @@ use sp_core::{ }; use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256}; use sp_runtime::{ - traits::{BadOrigin, Convert, Dispatchable, Saturating, Zero}, + traits::{BadOrigin, Bounded, Convert, Dispatchable, Saturating, Zero}, DispatchError, SaturatedConversion, }; @@ -885,11 +885,12 @@ where args, value, gas_meter, - Weight::zero(), + Weight::max_value(), storage_meter, - BalanceOf::::zero(), + BalanceOf::::max_value(), false, true, + true, )? else { return Ok(None); @@ -925,6 +926,7 @@ where deposit_limit: BalanceOf, read_only: bool, origin_is_caller: bool, + is_root: bool, ) -> Result, E)>, ExecError> { let (account_id, contract_info, executable, delegate, entry_point) = match frame_args { FrameArgs::Call { dest, cached_info, delegated_call } => { @@ -982,14 +984,25 @@ where }, }; + let nested_gas; + let nested_storage; + + if is_root { + nested_gas = gas_meter.take_all(); + nested_storage = storage_meter.take_all(); + } else { + nested_gas = gas_meter.nested(gas_limit); + nested_storage = storage_meter.nested(deposit_limit); + } + let frame = Frame { delegate, value_transferred, contract_info: CachedContract::Cached(contract_info), account_id, entry_point, - nested_gas: gas_meter.nested(gas_limit), - nested_storage: storage_meter.nested(deposit_limit), + nested_gas, + nested_storage, allows_reentry: true, read_only, last_frame_output: Default::default(), @@ -1037,6 +1050,7 @@ where deposit_limit, read_only, false, + false, )? { self.frames.try_push(frame).map_err(|_| Error::::MaxCallDepthReached)?; Ok(Some(executable)) @@ -1135,7 +1149,7 @@ where let contract = frame.contract_info.as_contract(); frame .nested_storage - .enforce_subcall_limit(contract) + .enforce_limit(contract) .map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?; let account_id = T::AddressMapper::to_address(&frame.account_id); @@ -3098,8 +3112,8 @@ mod tests { let (address, output) = ctx .ext .instantiate( - Weight::zero(), - U256::zero(), + Weight::MAX, + U256::from(u64::MAX), dummy_ch, ::Currency::minimum_balance().into(), vec![], @@ -3802,8 +3816,8 @@ mod tests { let succ_fail_code = MockLoader::insert(Constructor, move |ctx, _| { ctx.ext .instantiate( - Weight::zero(), - U256::zero(), + Weight::MAX, + U256::from(u64::MAX), fail_code, ctx.ext.minimum_balance() * 100, vec![], @@ -3819,8 +3833,8 @@ mod tests { let addr = ctx .ext .instantiate( - Weight::zero(), - U256::zero(), + Weight::MAX, + U256::from(u64::MAX), success_code, ctx.ext.minimum_balance() * 100, vec![], @@ -4597,7 +4611,7 @@ mod tests { // Successful instantiation should set the output let address = ctx .ext - .instantiate(Weight::zero(), U256::zero(), ok_ch, value, vec![], None) + .instantiate(Weight::MAX, U256::from(u64::MAX), ok_ch, value, vec![], None) .unwrap(); assert_eq!( ctx.ext.last_frame_output(), @@ -4607,8 +4621,8 @@ mod tests { // Balance transfers should reset the output ctx.ext .call( - Weight::zero(), - U256::zero(), + Weight::MAX, + U256::from(u64::MAX), &address, U256::from(1), vec![], @@ -4827,7 +4841,7 @@ mod tests { // Constructors can not access the immutable data ctx.ext - .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .instantiate(Weight::MAX, U256::from(u64::MAX), dummy_ch, value, vec![], None) .unwrap(); exec_success() @@ -4944,7 +4958,7 @@ mod tests { move |ctx, _| { let value = ::Currency::minimum_balance().into(); ctx.ext - .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .instantiate(Weight::MAX, U256::from(u64::MAX), dummy_ch, value, vec![], None) .unwrap(); exec_success() @@ -4989,7 +5003,7 @@ mod tests { move |ctx, _| { let value = ::Currency::minimum_balance().into(); ctx.ext - .instantiate(Weight::zero(), U256::zero(), dummy_ch, value, vec![], None) + .instantiate(Weight::MAX, U256::from(u64::MAX), dummy_ch, value, vec![], None) .unwrap(); exec_success() diff --git a/substrate/frame/revive/src/gas.rs b/substrate/frame/revive/src/gas.rs index 9aad84e69201..767165e8f647 100644 --- a/substrate/frame/revive/src/gas.rs +++ b/substrate/frame/revive/src/gas.rs @@ -22,7 +22,7 @@ use frame_support::{ weights::Weight, DefaultNoBound, }; -use sp_runtime::{traits::Zero, DispatchError}; +use sp_runtime::DispatchError; #[cfg(test)] use std::{any::Any, fmt::Debug}; @@ -168,25 +168,18 @@ impl GasMeter { } } - /// Create a new gas meter by removing gas from the current meter. - /// - /// # Note + pub(crate) fn take_all(&mut self) -> Self { + let gas_left = self.gas_left; + self.gas_left -= gas_left; + GasMeter::new(gas_left) + } + + /// Create a new gas meter for a nested call by removing gas from the current meter. /// - /// Passing `0` as amount is interpreted as "all remaining gas". + /// Per [EIP-150](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md), this is + /// capped at 63/64ths of the caller's gas limit. pub fn nested(&mut self, amount: Weight) -> Self { - let amount = Weight::from_parts( - if amount.ref_time().is_zero() { - self.gas_left().ref_time() - } else { - amount.ref_time() - }, - if amount.proof_size().is_zero() { - self.gas_left().proof_size() - } else { - amount.proof_size() - }, - ) - .min(self.gas_left); + let amount = amount.min(self.gas_left - self.gas_left / 64); self.gas_left -= amount; GasMeter::new(amount) } @@ -392,6 +385,52 @@ mod tests { assert!(gas_meter.charge(SimpleToken(1)).is_err()); } + /// Previously, passing a `Weight` of 0 to `nested` would consume all of the meter's current + /// gas. + /// + /// Now, a `Weight` of 0 means no gas for the nested call. + #[test] + fn nested_zero_gas_requested() { + let test_weight = 50000.into(); + let mut gas_meter = GasMeter::::new(test_weight); + let gas_for_nested_call = gas_meter.nested(0.into()); + + assert_eq!(gas_meter.gas_left(), 50000.into()); + assert_eq!(gas_for_nested_call.gas_left(), 0.into()) + } + + #[test] + fn nested_some_gas_requested() { + let test_weight = 50000.into(); + let mut gas_meter = GasMeter::::new(test_weight); + let gas_for_nested_call = gas_meter.nested(10000.into()); + + assert_eq!(gas_meter.gas_left(), 40000.into()); + assert_eq!(gas_for_nested_call.gas_left(), 10000.into()) + } + + #[test] + fn nested_all_gas_requested() { + let test_weight = Weight::from_parts(50000, 50000); + let mut gas_meter = GasMeter::::new(test_weight); + let gas_for_nested_call = gas_meter.nested(test_weight); + + // With EIP-150, it is not possible for subcalls to consume all available gas. + // They are limited to 63/64ths; 50000 / 64 ≈ 781 + assert_eq!(gas_meter.gas_left(), Weight::from_parts(781, 781)); + assert_eq!(gas_for_nested_call.gas_left(), 49219.into()) + } + + #[test] + fn nested_excess_gas_requested() { + let test_weight = Weight::from_parts(50000, 50000); + let mut gas_meter = GasMeter::::new(test_weight); + let gas_for_nested_call = gas_meter.nested(test_weight + 10000.into()); + + assert_eq!(gas_meter.gas_left(), Weight::from_parts(781, 781)); + assert_eq!(gas_for_nested_call.gas_left(), 49219.into()) + } + // Make sure that the gas meter does not charge in case of overcharge #[test] fn overcharge_does_not_charge() { diff --git a/substrate/frame/revive/src/primitives.rs b/substrate/frame/revive/src/primitives.rs index a7127f812b4b..452d2c8a3067 100644 --- a/substrate/frame/revive/src/primitives.rs +++ b/substrate/frame/revive/src/primitives.rs @@ -72,7 +72,7 @@ pub struct ContractResult { /// /// # Note /// - /// This can only different from [`Self::gas_consumed`] when weight pre charging + /// This can only be different from [`Self::gas_consumed`] when weight pre charging /// is used. Currently, only `seal_call_runtime` makes use of pre charging. /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging /// when a non-zero `gas_limit` argument is supplied. diff --git a/substrate/frame/revive/src/storage/meter.rs b/substrate/frame/revive/src/storage/meter.rs index 6eddf048be98..e5319e3cd670 100644 --- a/substrate/frame/revive/src/storage/meter.rs +++ b/substrate/frame/revive/src/storage/meter.rs @@ -100,13 +100,8 @@ pub trait State: private::Sealed {} pub struct Root; /// State parameter that constitutes a meter that is in its nested state. -/// Its value indicates whether the nested meter has its own limit. -#[derive(DefaultNoBound, RuntimeDebugNoBound)] -pub enum Nested { - #[default] - DerivedLimit, - OwnLimit, -} +#[derive(Default, Debug)] +pub struct Nested; impl State for Root {} impl State for Nested {} @@ -126,7 +121,7 @@ pub struct RawMeter { /// limited by the maximum call depth. charges: Vec>, /// We store the nested state to determine if it has a special limit for sub-call. - nested: S, + _nested: PhantomData, /// Type parameter only used in impls. _phantom: PhantomData, } @@ -281,21 +276,22 @@ where S: State + Default + Debug, { /// Create a new child that has its `limit`. - /// Passing `0` as the limit is interpreted as to take whatever is remaining from its parent. /// /// This is called whenever a new subcall is initiated in order to track the storage /// usage for this sub call separately. This is necessary because we want to exchange balance /// with the current contract we are interacting with. + /// + /// Gas for nested calls are capped to 63/64ths of the caller's originally available limit, per + /// EIP-150. pub fn nested(&self, limit: BalanceOf) -> RawMeter { debug_assert!(matches!(self.contract_state(), ContractState::Alive)); + + let available = self.available() - self.available() / (BalanceOf::::from(64u32)); + // If a special limit is specified higher than it is available, // we want to enforce the lesser limit to the nested meter, to fail in the sub-call. - let limit = self.available().min(limit); - if limit.is_zero() { - RawMeter { limit: self.available(), ..Default::default() } - } else { - RawMeter { limit, nested: Nested::OwnLimit, ..Default::default() } - } + let limit = available.min(limit); + RawMeter { limit, ..Default::default() } } /// Absorb a child that was spawned to handle a sub call. @@ -347,6 +343,10 @@ where _ => ContractState::Alive, } } + + pub(crate) fn take_all(&self) -> RawMeter { + RawMeter { limit: self.available(), ..Default::default() } + } } /// Functions that only apply to the root state. @@ -482,8 +482,7 @@ impl> RawMeter { /// /// We normally need to call this **once** for every call stack and not for every cross contract /// call. However, if a dedicated limit is specified for a sub-call, this needs to be called - /// once the sub-call has returned. For this, the [`Self::enforce_subcall_limit`] wrapper is - /// used. + /// once the sub-call has returned. pub fn enforce_limit( &mut self, info: Option<&mut ContractInfo>, @@ -502,18 +501,6 @@ impl> RawMeter { } Ok(()) } - - /// This is a wrapper around [`Self::enforce_limit`] to use on the exit from a sub-call to - /// enforce its special limit if needed. - pub fn enforce_subcall_limit( - &mut self, - info: Option<&mut ContractInfo>, - ) -> Result<(), DispatchError> { - match self.nested { - Nested::OwnLimit => self.enforce_limit(info), - Nested::DerivedLimit => Ok(()), - } - } } impl Ext for ReservingExt { @@ -724,6 +711,49 @@ mod tests { ) } + /// Previously, passing a limit of 0 meant unlimited storage for a nested call. + /// + /// Now, a limit of 0 means the subcall will not be able to use any storage. + #[test] + fn nested_zero_limit_requested() { + clear_ext(); + + let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap(); + assert_eq!(meter.available(), 1_000); + let nested0 = meter.nested(BalanceOf::::zero()); + assert_eq!(nested0.available(), 0); + } + + #[test] + fn nested_some_limit_requested() { + clear_ext(); + + let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap(); + assert_eq!(meter.available(), 1_000); + let nested0 = meter.nested(500); + assert_eq!(nested0.available(), 500); + } + + #[test] + fn nested_all_limit_requested() { + clear_ext(); + + let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap(); + assert_eq!(meter.available(), 1_000); + let nested0 = meter.nested(1_000); + assert_eq!(nested0.available(), 985); + } + + #[test] + fn nested_over_limit_requested() { + clear_ext(); + + let meter = TestMeter::new(&Origin::from_account_id(ALICE), 1_000, 0).unwrap(); + assert_eq!(meter.available(), 1_000); + let nested0 = meter.nested(2_000); + assert_eq!(nested0.available(), 985); + } + #[test] fn empty_charge_works() { clear_ext(); @@ -879,7 +909,7 @@ mod tests { let mut meter = TestMeter::new(&test_case.origin, 1_000, 0).unwrap(); assert_eq!(meter.available(), 1_000); - let mut nested0 = meter.nested(BalanceOf::::zero()); + let mut nested0 = meter.nested(BalanceOf::::max_value()); nested0.charge(&Diff { bytes_added: 5, bytes_removed: 1, @@ -895,7 +925,7 @@ mod tests { items_deposit: 20, immutable_data_len: 0, }); - let mut nested1 = nested0.nested(BalanceOf::::zero()); + let mut nested1 = nested0.nested(BalanceOf::::max_value()); nested1.charge(&Diff { items_removed: 5, ..Default::default() }); nested1.charge(&Diff { bytes_added: 20, ..Default::default() }); nested1.terminate(&nested1_info, CHARLIE);