diff --git a/chain-extensions/types/xvm/src/lib.rs b/chain-extensions/types/xvm/src/lib.rs index 9b6a3c9a4b..42551bbe5d 100644 --- a/chain-extensions/types/xvm/src/lib.rs +++ b/chain-extensions/types/xvm/src/lib.rs @@ -48,6 +48,7 @@ impl From for XvmExecutionResult { FailureReason::Error(FailureError::SameVmCallDenied) => 129, FailureReason::Error(FailureError::ReentranceDenied) => 130, FailureReason::Error(FailureError::VmError(_)) => 131, + FailureReason::Error(FailureError::OutOfGas) => 132, }; Self::Err(error_code) } diff --git a/chain-extensions/xvm/src/lib.rs b/chain-extensions/xvm/src/lib.rs index ac232e4cc0..1c7e5057fb 100644 --- a/chain-extensions/xvm/src/lib.rs +++ b/chain-extensions/xvm/src/lib.rs @@ -23,7 +23,7 @@ use alloc::format; use astar_primitives::{ evm::UnifiedAddressMapper, - xvm::{Context, VmId, XvmCall}, + xvm::{CallFailure, Context, FailureError, VmId, XvmCall}, }; use frame_support::{dispatch::Encode, weights::Weight}; use frame_system::RawOrigin; @@ -78,10 +78,7 @@ where XvmFuncId::Call => { // We need to immediately charge for the worst case scenario. Gas equals Weight in pallet-contracts context. let weight_limit = env.ext().gas_meter().gas_left(); - // TODO: track proof size in align fees ticket - // We don't track used proof size, so we can't refund after. - // So we will charge a 32KB dummy value as a temporary replacement. - let charged_weight = env.charge_weight(weight_limit.set_proof_size(32 * 1024))?; + let charged_weight = env.charge_weight(weight_limit)?; let XvmCallArgs { vm_id, @@ -103,9 +100,16 @@ where ::WeightInfo::to_h160(), ); + if actual_weight.any_gt(weight_limit) { + return out_of_gas_err(actual_weight); + } + if UA::to_h160(&source).is_none() { let weight_of_claim = ::WeightInfo::claim_default_evm_address(); actual_weight.saturating_accrue(weight_of_claim); + if actual_weight.any_gt(weight_limit) { + return out_of_gas_err(actual_weight); + } let claim_result = pallet_unified_accounts::Pallet::::claim_default_evm_address( @@ -122,7 +126,8 @@ where let xvm_context = Context { source_vm_id: VmId::Wasm, - weight_limit, + // Weight limit left for XVM call. + weight_limit: weight_limit.saturating_sub(actual_weight), }; let vm_id = { match TryInto::::try_into(vm_id) { @@ -174,3 +179,14 @@ where } } } + +fn out_of_gas_err(actual_weight: Weight) -> Result { + Ok(RetVal::Diverging { + flags: ReturnFlags::REVERT, + data: format!( + "{:?}", + CallFailure::error(FailureError::OutOfGas, actual_weight) + ) + .into(), + }) +} diff --git a/primitives/src/xvm.rs b/primitives/src/xvm.rs index 9cb3337d9a..6df7e68e7d 100644 --- a/primitives/src/xvm.rs +++ b/primitives/src/xvm.rs @@ -131,6 +131,8 @@ pub enum FailureError { ReentranceDenied, /// The call failed with error on EVM or WASM execution. VmError(Vec), + /// Out of gas. + OutOfGas, } /// XVM call result.