1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
// Copyright 2019-2022 PureStake Inc.
// This file is part Utils package, originally developed by PureStake
// Utils is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Utils is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Utils. If not, see <http://www.gnu.org/licenses/>.
//! Utils related to Substrate features:
//! - Substrate call dispatch.
//! - Substrate DB read and write costs
use crate::{revert, EvmResult};
use core::marker::PhantomData;
use frame_support::{
dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo},
traits::Get,
weights::Weight,
};
use pallet_3vm_evm::GasWeightMapping;
use pallet_3vm_evm_primitives::{ExitError, PrecompileFailure, PrecompileHandle};
/// Helper functions requiring a Substrate runtime.
/// This runtime must of course implement `pallet_3vm_evm::Config`.
#[derive(Clone, Copy, Debug)]
pub struct RuntimeHelper<Runtime>(PhantomData<Runtime>);
/*
impl<Runtime> RuntimeHelper<Runtime>
where
Runtime: pallet_3vm_evm::Config,
Runtime::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
{
/// Try to dispatch a Substrate call.
/// Return an error if there are not enough gas, or if the call fails.
/// If successful returns the used gas using the Runtime GasWeightMapping.
pub fn try_dispatch<RuntimeCall>(
handle: &mut impl PrecompileHandle,
origin: <Runtime::RuntimeCall as Dispatchable>::RuntimeOrigin,
call: RuntimeCall,
) -> EvmResult<()>
where
Runtime::RuntimeCall: From<RuntimeCall>,
{
let call = Runtime::RuntimeCall::from(call);
let dispatch_info = call.get_dispatch_info();
// Make sure there is enough gas.
let remaining_gas = handle.remaining_gas();
let required_gas = Runtime::GasWeightMapping::weight_to_gas(dispatch_info.weight);
if required_gas > remaining_gas {
return Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
});
}
// Dispatch call.
// It may be possible to not record gas cost if the call returns Pays::No.
// However while Substrate handle checking weight while not making the sender pay for it,
// the EVM doesn't. It seems this safer to always record the costs to avoid unmetered
// computations.
let used_weight = call
.dispatch(origin)
.map_err(|e| revert(alloc::format!("Dispatched call failed with error: {:?}", e)))?
.actual_weight;
let used_gas = Runtime::GasWeightMapping::weight_to_gas(used_weight.unwrap_or(dispatch_info.weight));
handle.record_cost(used_gas)?;
Ok(())
}
}
*/
impl<Runtime> RuntimeHelper<Runtime>
where
Runtime: pallet_3vm_evm::Config + frame_system::Config,
{
/// Cost of a Substrate DB write in gas.
pub fn db_write_gas_cost() -> u64 {
<Runtime as pallet_3vm_evm::Config>::GasWeightMapping::weight_to_gas(
<Runtime as frame_system::Config>::DbWeight::get().writes(1),
)
}
/// Cost of a Substrate DB read in gas.
pub fn db_read_gas_cost() -> u64 {
<Runtime as pallet_3vm_evm::Config>::GasWeightMapping::weight_to_gas(
<Runtime as frame_system::Config>::DbWeight::get().reads(1),
)
}
}