Skip to content

Commit

Permalink
Merge pull request #929 from galacticcouncil/fix/evm-base-weight-issue
Browse files Browse the repository at this point in the history
fix: OutOfGas error for low weight evm transactions
  • Loading branch information
mrq1911 authored Oct 17, 2024
2 parents ee99573 + c2d54b7 commit 9666945
Show file tree
Hide file tree
Showing 11 changed files with 671 additions and 2,340 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "runtime-integration-tests"
version = "1.24.0"
version = "1.23.7"
description = "Integration tests"
authors = ["GalacticCouncil"]
edition = "2021"
Expand Down
36 changes: 36 additions & 0 deletions integration-tests/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub const TREASURY_ACCOUNT_INIT_BALANCE: Balance = 1000 * UNITS;

mod account_conversion {
use super::*;
use fp_evm::ExitSucceed;
use frame_support::{assert_noop, assert_ok};
use pretty_assertions::assert_eq;

Expand Down Expand Up @@ -285,6 +286,41 @@ mod account_conversion {
});
}

#[test]
fn evm_transaction_with_low_weight_should_work_having_no_out_of_gas_error() {
TestNet::reset();

Hydra::execute_with(|| {
//Arrange
Balances::set_balance(&evm_account(), 1000 * UNITS);

let data =
hex!["4f003679d1d8e31d312a55f7ca994773b6a4fc7a92f07d898ae86bad4f3cab303c49000000000b00a0724e1809"]
.to_vec();

//Act & Assert
let res = hydradx_runtime::Runtime::call(
evm_address(), // from
DISPATCH_ADDR, // to
data, // data
U256::from(0u64),
U256::from(52000u64),
None,
None,
None,
false,
None,
);

assert_eq!(
res.clone().unwrap().exit_reason,
ExitReason::Succeed(ExitSucceed::Stopped)
);

println!("{:?}", res);
});
}

#[test]
fn evm_call_from_runtime_rpc_should_not_be_accepted_from_bound_addresses() {
TestNet::reset();
Expand Down
2 changes: 1 addition & 1 deletion precompiles/call-permit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "pallet-evm-precompile-call-permit"
description = "A Precompile to dispatch a call with a ERC712 permit."
edition = "2021"
version = "0.1.2"
version = "0.1.3"
authors = ["PureStake"]
repository = "https://github.com/PureStake/moonbeam"

Expand Down
2 changes: 1 addition & 1 deletion precompiles/utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "precompile-utils"
description = "Utils to write EVM precompiles."
edition = "2021"
version = "0.1.2"
version = "0.1.3"
authors = ["PureStake"]
repository = "https://github.com/PureStake/moonbeam"

Expand Down
36 changes: 7 additions & 29 deletions precompiles/utils/tests-external/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,7 @@ mod tests {
unimplemented!()
}

fn log(
&mut self,
_: sp_core::H160,
_: Vec<sp_core::H256>,
_: Vec<u8>,
) -> Result<(), evm::ExitError> {
fn log(&mut self, _: sp_core::H160, _: Vec<sp_core::H256>, _: Vec<u8>) -> Result<(), evm::ExitError> {
unimplemented!()
}

Expand Down Expand Up @@ -237,7 +232,7 @@ mod tests {

impl pallet_evm::Config for Runtime {
type FeeCalculator = ();
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type GasWeightMapping = FixedHydraGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
type CallOrigin = EnsureAddressRoot<AccountId>;
type WithdrawOrigin = EnsureAddressNever<AccountId>;
Expand Down Expand Up @@ -312,11 +307,7 @@ mod tests {
fn default_checks_revert_when_called_by_precompile() {
ExtBuilder::default().build().execute_with(|| {
precompiles()
.prepare_test(
H160::from_low_u64_be(1),
H160::from_low_u64_be(1),
PCall::success {},
)
.prepare_test(H160::from_low_u64_be(1), H160::from_low_u64_be(1), PCall::success {})
.with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall"))
.execute_reverts(|r| r == b"Function not callable by precompiles")
})
Expand All @@ -325,10 +316,7 @@ mod tests {
#[test]
fn default_checks_revert_when_called_by_contract() {
ExtBuilder::default().build().execute_with(|| {
pallet_evm::Pallet::<Runtime>::create_account(
Alice.into(),
hex_literal::hex!("1460006000fd").to_vec(),
);
pallet_evm::Pallet::<Runtime>::create_account(Alice.into(), hex_literal::hex!("1460006000fd").to_vec());

precompiles()
.prepare_test(Alice, H160::from_low_u64_be(1), PCall::success {})
Expand All @@ -350,10 +338,7 @@ mod tests {
#[test]
fn callable_by_contract_works() {
ExtBuilder::default().build().execute_with(|| {
pallet_evm::Pallet::<Runtime>::create_account(
Alice.into(),
hex_literal::hex!("1460006000fd").to_vec(),
);
pallet_evm::Pallet::<Runtime>::create_account(Alice.into(), hex_literal::hex!("1460006000fd").to_vec());

precompiles()
.prepare_test(Alice, H160::from_low_u64_be(2), PCall::success {})
Expand All @@ -366,11 +351,7 @@ mod tests {
fn callable_by_precompile_works() {
ExtBuilder::default().build().execute_with(|| {
precompiles()
.prepare_test(
H160::from_low_u64_be(3),
H160::from_low_u64_be(3),
PCall::success {},
)
.prepare_test(H160::from_low_u64_be(3), H160::from_low_u64_be(3), PCall::success {})
.with_subcall_handle(|Subcall { .. }| panic!("there should be no subcall"))
.execute_returns(())
})
Expand Down Expand Up @@ -423,10 +404,7 @@ mod tests {
let addr = H160::repeat_byte(0x1d);

// length > 5
pallet_evm::AccountCodes::<Runtime>::insert(
addr,
vec![0x60, 0x00, 0x60, 0x00, 0xfd, 0xff, 0xff],
);
pallet_evm::AccountCodes::<Runtime>::insert(addr, vec![0x60, 0x00, 0x60, 0x00, 0xfd, 0xff, 0xff]);
assert_eq!(
AddressType::Contract,
get_address_type::<Runtime>(&mut MockPrecompileHandle, addr).expect("OOG")
Expand Down
30 changes: 30 additions & 0 deletions runtime/hydradx/src/evm/gas_to_weight_mapping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use frame_support::weights::Weight;
use pallet_evm::GasWeightMapping;
use sp_core::Get;

pub struct FixedHydraGasWeightMapping<T>(core::marker::PhantomData<T>);

/// This implementation is a copy from the `pallet_evm::FixedHydraGasWeightMapping`,
/// with the only modification of substracting the constant ExtrinsicBaseWeight
impl<T: pallet_evm::Config> GasWeightMapping for FixedHydraGasWeightMapping<T> {
fn gas_to_weight(gas: u64, without_base_weight: bool) -> Weight {
//We use this base weight as we don't wanna include the swap weights of normal substrate transactions
//Otherwise transactions with weight smaller than swap would fail with OutOfGas error, during the tx execution
let base_weight = frame_support::weights::constants::ExtrinsicBaseWeight::get();
let mut weight = T::WeightPerGas::get().saturating_mul(gas);
if without_base_weight {
weight = weight.saturating_sub(base_weight);
}
// Apply a gas to proof size ratio based on BlockGasLimit
let ratio = T::GasLimitPovSizeRatio::get();
if ratio > 0 {
let proof_size = gas.saturating_div(ratio);
*weight.proof_size_mut() = proof_size;
}

weight
}
fn weight_to_gas(weight: Weight) -> u64 {
weight.div(T::WeightPerGas::get().ref_time()).ref_time()
}
}
5 changes: 3 additions & 2 deletions runtime/hydradx/src/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// http://www.apache.org/licenses/LICENSE-2.0

use crate::evm::evm_fee::FeeCurrencyOverrideOrDefault;
use crate::evm::gas_to_weight_mapping::FixedHydraGasWeightMapping;
use crate::evm::runner::WrapRunner;
use crate::types::ShortOraclePrice;
pub use crate::{
Expand All @@ -44,11 +45,11 @@ use pallet_evm::EnsureAddressTruncated;
use pallet_transaction_payment::Multiplier;
use primitives::{constants::chain::MAXIMUM_BLOCK_WEIGHT, AssetId};
use sp_core::{Get, U256};

mod accounts_conversion;
mod erc20_currency;
mod evm_fee;
mod executor;
mod gas_to_weight_mapping;
pub mod permit;
pub mod precompiles;
mod runner;
Expand Down Expand Up @@ -143,7 +144,7 @@ impl pallet_evm::Config for crate::Runtime {
type Currency = WethCurrency;
type FeeCalculator = crate::DynamicEvmFee;
type FindAuthor = FindAuthorTruncated<crate::Runtime, Aura>;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type GasWeightMapping = FixedHydraGasWeightMapping<Self>;
type OnChargeTransaction = evm_fee::TransferEvmFees<
evm_fee::DepositEvmFeeToTreasury,
FeeCurrencyOverrideOrDefault<WethAssetId>, // Get account's fee payment asset
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const { ethers } = require('ethers');
import {ethers} from 'ethers';

async function main() {
// Define the Ethereum RPC URL
//const ethereumRpcUrl = "https://rpc.nice.hydration.cloud"; // Replace with your Ethereum RPC URL
const ethereumRpcUrl = "https://ws.nice.hydration.cloud"; // Replace with your Ethereum RPC URL

const ethereumRpcUrl = "http://127.0.0.1:9988"; // Replace with your Ethereum RPC URL
// const ethereumRpcUrl = "http://127.0.0.1:9988"; // Replace with your Ethereum RPC URL

// Create a provider using the Ethereum RPC URL
const provider = new ethers.JsonRpcProvider(ethereumRpcUrl);
Expand All @@ -27,20 +27,27 @@ async function main() {

try {
// Omnipool sell call encoded
const extrinsicData = '0x3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000'; // Replace with your extrinsic data
//const extrinsicData = '0x3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000'; // Replace with your extrinsic data
//const extrinsicData = '0xcb0014000000'; // Your extrinsic data
const extrinsicData = '0x4f003679d1d8e31d312a55f7ca994773b6a4fc7a92f07d898ae86bad4f3cab303c49000000000b00a0724e1809'; // Your extrinsic data

const nonce = await provider.getTransactionCount(wallet.address, 'latest');


const tx = {
to: dispatchContractAddress,
value: 0,
nonce: nonce,
gasLimit: 100000, // Adjust the gas limit accordingly
gasPrice: ethers.parseUnits('80000000', 'wei'), // Adjust the gas price accordingly
gasLimit: 352000, // Adjust the gas limit accordingly
gasPrice: ethers.parseUnits('180000000', 'wei'), // Adjust the gas price accordingly
data: extrinsicData,
};

const signer= wallet.connect(provider); // Connect the wallet to the provider
await signer.sendTransaction(tx);
let res = await signer.sendTransaction(tx);

console.log("Transaction hash:", res.hash);
console.log("Transaction receipt:", await res.wait());

} catch (error) {
console.error('Error:', error);
Expand Down
55 changes: 55 additions & 0 deletions scripts/init-testnet/evm/estimateGas.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {ethers} from 'ethers';

async function main() {
// Define the Ethereum RPC URL
const ethereumRpcUrl = "https://ws.nice.hydration.cloud"; // Replace with your Ethereum RPC URL
//const ethereumRpcUrl = "https://rpc.hydradx.cloud"; // Replace with your Ethereum RPC URL

//const ethereumRpcUrl = "http://127.0.0.1:9988"; // Replace with your Ethereum RPC URL

// Create a provider using the Ethereum RPC URL
const provider = new ethers.JsonRpcProvider(ethereumRpcUrl);

try {
// Example: Fetch the Ethereum block number
const blockNumber = await provider.getBlockNumber();
console.log("Ethereum Block Number:", blockNumber);

// Example: Fetch the balance of an Ethereum address
const address = "0x222222ff7Be76052e023Ec1a306fCca8F9659D80"; // Replace with the Ethereum address you want to check
const balance = await provider.getBalance(address);
console.log("Ethereum Balance (Wei):", balance.toString());


const privateKey = '42d8d953e4f9246093a33e9ca6daa078501012f784adfe4bbed57918ff13be14';
const wallet = new ethers.Wallet(privateKey, provider);

try {
const dispatchContractAddress = '0x0000000000000000000000000000000000000401';
//const extrinsicData = '0x3b05000000000500000000a0724e18090000000000000000000000000000000000000000000000000000'; // Your extrinsic data
// const extrinsicData = '0xcb0014000000'; // Your extrinsic data
const extrinsicData = '0x4f003679d1d8e31d312a55f7ca994773b6a4fc7a92f07d898ae86bad4f3cab303c49000000000b00a0724e1809'; // Your extrinsic data

const estimateGasParams = {
from: wallet.address, // The address initiating the transaction
to: dispatchContractAddress,
data: extrinsicData,
value: 0 // If you're not sending any Ether with the transaction
};

const estimatedGas = await provider.estimateGas(estimateGasParams);

console.log("Estimated Gas:", estimatedGas.toString());

} catch (error) {
console.error("Error estimating gas:", error);
}



} catch (error) {
console.error("Error:", error);
}
}

main();
Loading

0 comments on commit 9666945

Please sign in to comment.