Skip to content

Commit 0385ffe

Browse files
authored
Merge pull request #1362 from opentensor/chore/refactor-precompiles
Refactor precompiles
2 parents b6bf2c6 + a0ed6fb commit 0385ffe

File tree

9 files changed

+231
-238
lines changed

9 files changed

+231
-238
lines changed

precompiles/src/balance_transfer.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use core::marker::PhantomData;
22

33
use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo};
4+
use frame_system::RawOrigin;
45
use pallet_evm::PrecompileHandle;
56
use precompile_utils::EvmResult;
67
use sp_core::{H256, U256};
78
use sp_runtime::traits::{Dispatchable, StaticLookup, UniqueSaturatedInto};
89

9-
use crate::parser::{contract_to_origin, parse_pubkey};
1010
use crate::{PrecompileExt, PrecompileHandleExt};
1111

1212
pub(crate) struct BalanceTransferPrecompile<R>(PhantomData<R>);
1313

14-
impl<R> PrecompileExt for BalanceTransferPrecompile<R>
14+
impl<R> PrecompileExt<R::AccountId> for BalanceTransferPrecompile<R>
1515
where
1616
R: frame_system::Config + pallet_balances::Config + pallet_evm::Config,
1717
R::AccountId: From<[u8; 32]>,
@@ -24,11 +24,6 @@ where
2424
<R as pallet_balances::Config>::Balance: TryFrom<U256>,
2525
{
2626
const INDEX: u64 = 2048;
27-
const ADDRESS_SS58: Option<[u8; 32]> = Some([
28-
0x07, 0xec, 0x71, 0x2a, 0x5d, 0x38, 0x43, 0x4d, 0xdd, 0x03, 0x3f, 0x8f, 0x02, 0x4e, 0xcd,
29-
0xfc, 0x4b, 0xb5, 0x95, 0x1c, 0x13, 0xc3, 0x08, 0x5c, 0x39, 0x9c, 0x8a, 0x5f, 0x62, 0x93,
30-
0x70, 0x5d,
31-
]);
3227
}
3328

3429
#[precompile_utils::precompile]
@@ -53,18 +48,13 @@ where
5348
return Ok(());
5449
}
5550

56-
let dest = parse_pubkey::<R::AccountId>(address.as_bytes())?.0.into();
51+
let dest = R::AccountId::from(address.0).into();
5752

5853
let call = pallet_balances::Call::<R>::transfer_allow_death {
5954
dest,
6055
value: amount_sub.unique_saturated_into(),
6156
};
6257

63-
handle.try_dispatch_runtime_call::<R, _>(
64-
call,
65-
contract_to_origin(
66-
&Self::ADDRESS_SS58.expect("ADDRESS_SS58 is defined for BalanceTransferPrecompile"),
67-
)?,
68-
)
58+
handle.try_dispatch_runtime_call::<R, _>(call, RawOrigin::Signed(Self::account_id()))
6959
}
7060
}

precompiles/src/ed25519.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,26 @@
11
extern crate alloc;
22

33
use alloc::vec::Vec;
4+
use core::marker::PhantomData;
45

56
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
67
use fp_evm::{ExitError, ExitSucceed, LinearCostPrecompile, PrecompileFailure};
78

89
use crate::PrecompileExt;
9-
use crate::parser::parse_slice;
1010

11-
pub(crate) struct Ed25519Verify;
11+
pub(crate) struct Ed25519Verify<A>(PhantomData<A>);
1212

13-
impl PrecompileExt for Ed25519Verify {
13+
impl<A> PrecompileExt<A> for Ed25519Verify<A>
14+
where
15+
A: From<[u8; 32]>,
16+
{
1417
const INDEX: u64 = 1026;
15-
const ADDRESS_SS58: Option<[u8; 32]> = None;
1618
}
1719

18-
impl LinearCostPrecompile for Ed25519Verify {
20+
impl<A> LinearCostPrecompile for Ed25519Verify<A>
21+
where
22+
A: From<[u8; 32]>,
23+
{
1924
const BASE: u64 = 15;
2025
const WORD: u64 = 3;
2126

@@ -47,3 +52,21 @@ impl LinearCostPrecompile for Ed25519Verify {
4752
Ok((ExitSucceed::Returned, buf.to_vec()))
4853
}
4954
}
55+
56+
/// Takes a slice from bytes with PrecompileFailure as Error
57+
fn parse_slice(data: &[u8], from: usize, to: usize) -> Result<&[u8], PrecompileFailure> {
58+
let maybe_slice = data.get(from..to);
59+
if let Some(slice) = maybe_slice {
60+
Ok(slice)
61+
} else {
62+
log::error!(
63+
"fail to get slice from data, {:?}, from {}, to {}",
64+
&data,
65+
from,
66+
to
67+
);
68+
Err(PrecompileFailure::Error {
69+
exit_status: ExitError::InvalidRange,
70+
})
71+
}
72+
}

precompiles/src/extensions.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
extern crate alloc;
2+
3+
use alloc::format;
4+
5+
use frame_support::dispatch::{GetDispatchInfo, Pays, PostDispatchInfo};
6+
use frame_system::RawOrigin;
7+
use pallet_evm::{
8+
AddressMapping, BalanceConverter, ExitError, GasWeightMapping, PrecompileFailure,
9+
PrecompileHandle,
10+
};
11+
use precompile_utils::EvmResult;
12+
use sp_core::{H160, U256, blake2_256};
13+
use sp_runtime::traits::Dispatchable;
14+
use sp_std::vec::Vec;
15+
16+
pub(crate) trait PrecompileHandleExt: PrecompileHandle {
17+
fn caller_account_id<R>(&self) -> R::AccountId
18+
where
19+
R: frame_system::Config + pallet_evm::Config,
20+
<R as pallet_evm::Config>::AddressMapping: AddressMapping<R::AccountId>,
21+
{
22+
<R as pallet_evm::Config>::AddressMapping::into_account_id(self.context().caller)
23+
}
24+
25+
fn try_convert_apparent_value<R>(&self) -> EvmResult<U256>
26+
where
27+
R: pallet_evm::Config,
28+
{
29+
let amount = self.context().apparent_value;
30+
<R as pallet_evm::Config>::BalanceConverter::into_substrate_balance(amount).ok_or(
31+
PrecompileFailure::Error {
32+
exit_status: ExitError::Other(
33+
"error converting balance from ETH to subtensor".into(),
34+
),
35+
},
36+
)
37+
}
38+
39+
/// Dispatches a runtime call, but also checks and records the gas costs.
40+
fn try_dispatch_runtime_call<R, Call>(
41+
&mut self,
42+
call: Call,
43+
origin: RawOrigin<R::AccountId>,
44+
) -> EvmResult<()>
45+
where
46+
R: frame_system::Config + pallet_evm::Config,
47+
R::RuntimeCall: From<Call>,
48+
R::RuntimeCall: GetDispatchInfo + Dispatchable<PostInfo = PostDispatchInfo>,
49+
R::RuntimeOrigin: From<RawOrigin<R::AccountId>>,
50+
{
51+
let call = R::RuntimeCall::from(call);
52+
let info = GetDispatchInfo::get_dispatch_info(&call);
53+
54+
let target_gas = self.gas_limit();
55+
if let Some(gas) = target_gas {
56+
let valid_weight =
57+
<R as pallet_evm::Config>::GasWeightMapping::gas_to_weight(gas, false).ref_time();
58+
if info.weight.ref_time() > valid_weight {
59+
return Err(PrecompileFailure::Error {
60+
exit_status: ExitError::OutOfGas,
61+
});
62+
}
63+
}
64+
65+
self.record_external_cost(
66+
Some(info.weight.ref_time()),
67+
Some(info.weight.proof_size()),
68+
None,
69+
)?;
70+
71+
match call.dispatch(R::RuntimeOrigin::from(origin)) {
72+
Ok(post_info) => {
73+
if post_info.pays_fee(&info) == Pays::Yes {
74+
let actual_weight = post_info.actual_weight.unwrap_or(info.weight);
75+
let cost =
76+
<R as pallet_evm::Config>::GasWeightMapping::weight_to_gas(actual_weight);
77+
self.record_cost(cost)?;
78+
79+
self.refund_external_cost(
80+
Some(
81+
info.weight
82+
.ref_time()
83+
.saturating_sub(actual_weight.ref_time()),
84+
),
85+
Some(
86+
info.weight
87+
.proof_size()
88+
.saturating_sub(actual_weight.proof_size()),
89+
),
90+
);
91+
}
92+
93+
log::info!("Dispatch succeeded. Post info: {:?}", post_info);
94+
95+
Ok(())
96+
}
97+
Err(e) => {
98+
log::error!("Dispatch failed. Error: {:?}", e);
99+
log::warn!("Returning error PrecompileFailure::Error");
100+
Err(PrecompileFailure::Error {
101+
exit_status: ExitError::Other(
102+
format!("dispatch execution failed: {}", <&'static str>::from(e)).into(),
103+
),
104+
})
105+
}
106+
}
107+
}
108+
}
109+
110+
impl<T> PrecompileHandleExt for T where T: PrecompileHandle {}
111+
112+
pub(crate) trait PrecompileExt<AccountId: From<[u8; 32]>> {
113+
const INDEX: u64;
114+
115+
// ss58 public key i.e., the contract sends funds it received to the destination address from
116+
// the method parameter.
117+
fn account_id() -> AccountId {
118+
let hash = H160::from_low_u64_be(Self::INDEX);
119+
let prefix = b"evm:";
120+
121+
// Concatenate prefix and ethereum address
122+
let mut combined = Vec::new();
123+
combined.extend_from_slice(prefix);
124+
combined.extend_from_slice(hash.as_bytes());
125+
126+
let hash = blake2_256(&combined);
127+
128+
hash.into()
129+
}
130+
}
131+
132+
#[cfg(test)]
133+
mod test {
134+
use super::*;
135+
136+
use sp_core::crypto::AccountId32;
137+
138+
#[test]
139+
fn ss58_address_from_index_works() {
140+
assert_eq!(
141+
TestPrecompile::account_id(),
142+
AccountId32::from([
143+
0x3a, 0x86, 0x18, 0xfb, 0xbb, 0x1b, 0xbc, 0x47, 0x86, 0x64, 0xff, 0x53, 0x46, 0x18,
144+
0x0c, 0x35, 0xd0, 0x9f, 0xac, 0x26, 0xf2, 0x02, 0x70, 0x85, 0xb3, 0x1c, 0x56, 0xc1,
145+
0x06, 0x3c, 0x1c, 0xd3,
146+
])
147+
);
148+
}
149+
150+
struct TestPrecompile;
151+
152+
impl PrecompileExt<AccountId32> for TestPrecompile {
153+
const INDEX: u64 = 2051;
154+
}
155+
}

0 commit comments

Comments
 (0)