Skip to content

Commit ed6ba75

Browse files
authored
Merge pull request #1208 from opentensor/fix/evm-gas-estimation
Replace frontier's RuntimeHelper with manual dispatcher
2 parents b1e7fab + 5a1f1f2 commit ed6ba75

File tree

5 files changed

+97
-104
lines changed

5 files changed

+97
-104
lines changed

Cargo.lock

-45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/Cargo.toml

+7-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ name = "spec_version"
2020
path = "src/spec_version.rs"
2121

2222
[dependencies]
23-
ed25519-dalek = { workspace = true, default-features = false, features = ["alloc"] }
23+
ed25519-dalek = { workspace = true, default-features = false, features = [
24+
"alloc",
25+
] }
2426
subtensor-macros.workspace = true
2527
subtensor-custom-rpc-runtime-api = { path = "../pallets/subtensor/runtime-api", default-features = false }
2628
smallvec = { workspace = true }
@@ -98,7 +100,6 @@ pallet-commitments = { default-features = false, path = "../pallets/commitments"
98100
fp-evm = { workspace = true }
99101
fp-rpc = { workspace = true }
100102
fp-self-contained = { workspace = true }
101-
precompile-utils = { workspace = true }
102103

103104
# Frontier FRAME
104105
pallet-base-fee = { workspace = true }
@@ -133,9 +134,7 @@ substrate-wasm-builder = { workspace = true, optional = true }
133134
[features]
134135
default = ["std"]
135136
pow-faucet = ["pallet-subtensor/pow-faucet"]
136-
fast-blocks = [
137-
"pallet-subtensor/fast-blocks"
138-
]
137+
fast-blocks = ["pallet-subtensor/fast-blocks"]
139138
std = [
140139
"frame-try-runtime?/std",
141140
"frame-system-benchmarking?/std",
@@ -192,7 +191,6 @@ std = [
192191
"fp-evm/std",
193192
"fp-rpc/std",
194193
"fp-self-contained/std",
195-
"precompile-utils/std",
196194
# Frontier FRAME
197195
"pallet-base-fee/std",
198196
"pallet-dynamic-fee/std",
@@ -211,7 +209,7 @@ std = [
211209
"hex/std",
212210
"rand_chacha/std",
213211
"sha2/std",
214-
"w3f-bls/std"
212+
"w3f-bls/std",
215213
]
216214
runtime-benchmarks = [
217215
"frame-benchmarking/runtime-benchmarks",
@@ -240,7 +238,7 @@ runtime-benchmarks = [
240238
"pallet-ethereum/runtime-benchmarks",
241239
"pallet-evm/runtime-benchmarks",
242240
"pallet-hotfix-sufficients/runtime-benchmarks",
243-
"pallet-drand/runtime-benchmarks"
241+
"pallet-drand/runtime-benchmarks",
244242
]
245243
try-runtime = [
246244
"frame-try-runtime/try-runtime",
@@ -276,6 +274,6 @@ try-runtime = [
276274
"pallet-ethereum/try-runtime",
277275
"pallet-evm/try-runtime",
278276
"pallet-evm-chain-id/try-runtime",
279-
"pallet-drand/try-runtime"
277+
"pallet-drand/try-runtime",
280278
]
281279
metadata-hash = ["substrate-wasm-builder/metadata-hash"]

runtime/src/precompiles/balance_transfer.rs

+10-22
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use frame_system::RawOrigin;
22
use pallet_evm::{
3-
BalanceConverter, ExitError, ExitSucceed, PrecompileFailure, PrecompileHandle,
4-
PrecompileOutput, PrecompileResult,
3+
BalanceConverter, ExitError, ExitSucceed, PrecompileHandle, PrecompileOutput, PrecompileResult,
54
};
6-
use precompile_utils::prelude::RuntimeHelper;
7-
use sp_core::U256;
85
use sp_runtime::traits::UniqueSaturatedInto;
96
use sp_std::vec;
107

11-
use crate::precompiles::{bytes_to_account_id, get_method_id, get_slice};
12-
use crate::{Runtime, RuntimeCall};
8+
use crate::precompiles::{
9+
bytes_to_account_id, get_method_id, get_slice, try_dispatch_runtime_call,
10+
};
11+
use crate::Runtime;
1312

1413
pub const BALANCE_TRANSFER_INDEX: u64 = 2048;
1514

@@ -37,7 +36,7 @@ impl BalanceTransferPrecompile {
3736
}
3837

3938
// Forward all received value to the destination address
40-
let amount: U256 = handle.context().apparent_value;
39+
let amount = handle.context().apparent_value;
4140

4241
// Use BalanceConverter to convert EVM amount to Substrate balance
4342
let amount_sub =
@@ -55,23 +54,12 @@ impl BalanceTransferPrecompile {
5554
let account_id_src = bytes_to_account_id(&CONTRACT_ADDRESS_SS58)?;
5655
let account_id_dst = bytes_to_account_id(address_bytes_dst)?;
5756

58-
let call = RuntimeCall::Balances(pallet_balances::Call::<Runtime>::transfer_allow_death {
57+
let call = pallet_balances::Call::<Runtime>::transfer_allow_death {
5958
dest: account_id_dst.into(),
6059
value: amount_sub.unique_saturated_into(),
61-
});
60+
};
61+
let origin = RawOrigin::Signed(account_id_src);
6262

63-
// Dispatch the call
64-
RuntimeHelper::<Runtime>::try_dispatch(
65-
handle,
66-
RawOrigin::Signed(account_id_src).into(),
67-
call,
68-
)
69-
.map(|_| PrecompileOutput {
70-
exit_status: ExitSucceed::Returned,
71-
output: vec![],
72-
})
73-
.map_err(|_| PrecompileFailure::Error {
74-
exit_status: ExitError::OutOfFund,
75-
})
63+
try_dispatch_runtime_call(handle, call, origin)
7664
}
7765
}

runtime/src/precompiles/mod.rs

+78-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
extern crate alloc;
2+
3+
use alloc::format;
14
use core::marker::PhantomData;
2-
use sp_core::{hashing::keccak_256, H160};
3-
use sp_runtime::AccountId32;
45

6+
use frame_support::dispatch::{GetDispatchInfo, Pays};
7+
use frame_system::RawOrigin;
58
use pallet_evm::{
6-
ExitError, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
7-
PrecompileResult, PrecompileSet,
9+
ExitError, ExitSucceed, GasWeightMapping, IsPrecompileResult, Precompile, PrecompileFailure,
10+
PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
811
};
912
use pallet_evm_precompile_modexp::Modexp;
1013
use pallet_evm_precompile_sha3fips::Sha3FIPS256;
1114
use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
15+
use sp_core::{hashing::keccak_256, H160};
16+
use sp_runtime::{traits::Dispatchable, AccountId32};
17+
18+
use crate::{Runtime, RuntimeCall};
1219

1320
// Include custom precompiles
1421
mod balance_transfer;
@@ -130,3 +137,70 @@ pub fn get_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], Precompil
130137
})
131138
}
132139
}
140+
141+
/// Dispatches a runtime call, but also checks and records the gas costs.
142+
fn try_dispatch_runtime_call(
143+
handle: &mut impl PrecompileHandle,
144+
call: impl Into<RuntimeCall>,
145+
origin: RawOrigin<AccountId32>,
146+
) -> PrecompileResult {
147+
let call = Into::<RuntimeCall>::into(call);
148+
let info = call.get_dispatch_info();
149+
150+
let target_gas = handle.gas_limit();
151+
if let Some(gas) = target_gas {
152+
let valid_weight =
153+
<Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(gas, false).ref_time();
154+
if info.weight.ref_time() > valid_weight {
155+
return Err(PrecompileFailure::Error {
156+
exit_status: ExitError::OutOfGas,
157+
});
158+
}
159+
}
160+
161+
handle.record_external_cost(
162+
Some(info.weight.ref_time()),
163+
Some(info.weight.proof_size()),
164+
None,
165+
)?;
166+
167+
match call.dispatch(origin.into()) {
168+
Ok(post_info) => {
169+
if post_info.pays_fee(&info) == Pays::Yes {
170+
let actual_weight = post_info.actual_weight.unwrap_or(info.weight);
171+
let cost =
172+
<Runtime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(actual_weight);
173+
handle.record_cost(cost)?;
174+
175+
handle.refund_external_cost(
176+
Some(
177+
info.weight
178+
.ref_time()
179+
.saturating_sub(actual_weight.ref_time()),
180+
),
181+
Some(
182+
info.weight
183+
.proof_size()
184+
.saturating_sub(actual_weight.proof_size()),
185+
),
186+
);
187+
}
188+
189+
log::info!("Dispatch succeeded. Post info: {:?}", post_info);
190+
191+
Ok(PrecompileOutput {
192+
exit_status: ExitSucceed::Returned,
193+
output: Default::default(),
194+
})
195+
}
196+
Err(e) => {
197+
log::error!("Dispatch failed. Error: {:?}", e);
198+
log::warn!("Returning error PrecompileFailure::Error");
199+
Err(PrecompileFailure::Error {
200+
exit_status: ExitError::Other(
201+
format!("dispatch execution failed: {}", <&'static str>::from(e)).into(),
202+
),
203+
})
204+
}
205+
}
206+
}

runtime/src/precompiles/staking.rs

+2-24
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,14 @@ use pallet_evm::{
3030
AddressMapping, BalanceConverter, ExitError, ExitSucceed, HashedAddressMapping,
3131
PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
3232
};
33-
use precompile_utils::prelude::RuntimeHelper;
3433
use sp_core::crypto::Ss58Codec;
3534
use sp_core::U256;
3635
use sp_runtime::traits::{BlakeTwo256, Dispatchable, StaticLookup, UniqueSaturatedInto};
3736
use sp_runtime::AccountId32;
3837
use sp_std::vec;
3938

4039
use crate::{
41-
precompiles::{get_method_id, get_slice},
40+
precompiles::{get_method_id, get_slice, try_dispatch_runtime_call},
4241
ProxyType, Runtime, RuntimeCall,
4342
};
4443

@@ -214,28 +213,7 @@ impl StakingPrecompile {
214213
Self::transfer_back_to_caller(&account_id, amount)?;
215214
}
216215

217-
match RuntimeHelper::<Runtime>::try_dispatch(
218-
handle,
219-
RawOrigin::Signed(account_id.clone()).into(),
220-
call,
221-
) {
222-
Ok(post_info) => {
223-
log::info!("Dispatch succeeded. Post info: {:?}", post_info);
224-
225-
Ok(PrecompileOutput {
226-
exit_status: ExitSucceed::Returned,
227-
output: vec![],
228-
})
229-
}
230-
231-
Err(dispatch_error) => {
232-
log::error!("Dispatch failed. Error: {:?}", dispatch_error);
233-
log::warn!("Returning error PrecompileFailure::Error");
234-
Err(PrecompileFailure::Error {
235-
exit_status: ExitError::Other("Subtensor call failed".into()),
236-
})
237-
}
238-
}
216+
try_dispatch_runtime_call(handle, call, RawOrigin::Signed(account_id.clone()))
239217
}
240218

241219
fn transfer_back_to_caller(

0 commit comments

Comments
 (0)