Skip to content

Commit 71e440d

Browse files
add precompiles on-chain storage
1 parent 58c5689 commit 71e440d

File tree

5 files changed

+87
-26
lines changed

5 files changed

+87
-26
lines changed

frame/evm/precompile/dispatch/src/tests.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
7373
}
7474
.assimilate_storage(&mut t)
7575
.expect("Pallet balances storage can be assimilated");
76-
GenesisBuild::<Test>::assimilate_storage(&pallet_evm::GenesisConfig { accounts }, &mut t)
77-
.unwrap();
76+
GenesisBuild::<Test>::assimilate_storage(
77+
&pallet_evm::GenesisConfig {
78+
accounts,
79+
precompiles: vec![],
80+
},
81+
&mut t,
82+
)
83+
.unwrap();
7884
t.into()
7985
}
8086

frame/evm/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ pub mod pallet {
467467
#[cfg_attr(feature = "std", derive(Default))]
468468
pub struct GenesisConfig {
469469
pub accounts: std::collections::BTreeMap<H160, GenesisAccount>,
470+
pub precompiles: Vec<(Vec<u8>, H160)>,
470471
}
471472

472473
#[pallet::genesis_build]
@@ -497,6 +498,10 @@ pub mod pallet {
497498
<AccountStorages<T>>::insert(address, index, value);
498499
}
499500
}
501+
502+
for (label, address) in &self.precompiles {
503+
Pallet::<T>::add_precompile(label, address);
504+
}
500505
}
501506
}
502507

@@ -508,6 +513,17 @@ pub mod pallet {
508513
#[pallet::getter(fn account_storages)]
509514
pub type AccountStorages<T: Config> =
510515
StorageDoubleMap<_, Blake2_128Concat, H160, Blake2_128Concat, H256, H256, ValueQuery>;
516+
517+
/// Allows for precompiles to have arbitrary addresses, potentially more than one.
518+
/// `k1`: precompile label, e.g.: `b"Sha3FIPS256".to_vec()`
519+
/// `k2`: precompile address
520+
///
521+
/// Please note that adding a new precompile label here is not enough to guarantee its execution
522+
/// It is also required to list the new label on the implementation of `PrecompileSet::execute()`
523+
#[pallet::storage]
524+
#[pallet::getter(fn precompiles)]
525+
pub type Precompiles<T: Config> =
526+
StorageDoubleMap<_, Blake2_128Concat, Vec<u8>, Blake2_128Concat, H160, (), OptionQuery>;
511527
}
512528

513529
/// Type alias for currency balance.
@@ -671,6 +687,16 @@ impl<T: Config> GasWeightMapping for FixedGasWeightMapping<T> {
671687
static LONDON_CONFIG: EvmConfig = EvmConfig::london();
672688

673689
impl<T: Config> Pallet<T> {
690+
/// Add a precompile to storage
691+
pub fn add_precompile(label: &Vec<u8>, address: &H160) {
692+
Precompiles::<T>::set(label, address, Some(()));
693+
}
694+
695+
/// Remove a precompile from storage
696+
pub fn remove_precompile(label: &Vec<u8>, address: &H160) {
697+
Precompiles::<T>::remove(label, address);
698+
}
699+
674700
/// Check whether an account is empty.
675701
pub fn is_account_empty(address: &H160) -> bool {
676702
let (account, _) = Self::account_basic(address);

frame/evm/src/tests.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
6767
},
6868
);
6969

70+
let precompiles = vec![];
71+
7072
pallet_balances::GenesisConfig::<Test> {
7173
// Create the block author account with some balance.
7274
balances: vec![(
@@ -76,7 +78,14 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
7678
}
7779
.assimilate_storage(&mut t)
7880
.expect("Pallet balances storage can be assimilated");
79-
GenesisBuild::<Test>::assimilate_storage(&crate::GenesisConfig { accounts }, &mut t).unwrap();
81+
GenesisBuild::<Test>::assimilate_storage(
82+
&crate::GenesisConfig {
83+
accounts,
84+
precompiles,
85+
},
86+
&mut t,
87+
)
88+
.unwrap();
8089
t.into()
8190
}
8291

template/node/src/chain_spec.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,17 @@ fn testnet_genesis(
250250
);
251251
map
252252
},
253+
precompiles: vec![
254+
// Ethereum precompiles :
255+
(b"ECRecover".to_vec(), H160::from_low_u64_be(1)),
256+
(b"Sha256".to_vec(), H160::from_low_u64_be(2)),
257+
(b"Ripemd160".to_vec(), H160::from_low_u64_be(3)),
258+
(b"Identity".to_vec(), H160::from_low_u64_be(4)),
259+
(b"Modexp".to_vec(), H160::from_low_u64_be(5)),
260+
// Non-Frontier specific nor Ethereum precompiles :
261+
(b"Sha3FIPS256".to_vec(), H160::from_low_u64_be(1024)),
262+
(b"Sha3FIPS256".to_vec(), H160::from_low_u64_be(1025)),
263+
],
253264
},
254265
ethereum: Default::default(),
255266
dynamic_fee: Default::default(),

template/runtime/src/precompiles.rs

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use pallet_evm::{Precompile, PrecompileHandle, PrecompileResult, PrecompileSet};
22
use sp_core::H160;
33
use sp_std::marker::PhantomData;
44

5+
use pallet_evm::Precompiles;
56
use pallet_evm_precompile_modexp::Modexp;
67
use pallet_evm_precompile_sha3fips::Sha3FIPS256;
78
use pallet_evm_precompile_simple::{ECRecover, ECRecoverPublicKey, Identity, Ripemd160, Sha256};
@@ -15,17 +16,6 @@ where
1516
pub fn new() -> Self {
1617
Self(Default::default())
1718
}
18-
pub fn used_addresses() -> [H160; 7] {
19-
[
20-
hash(1),
21-
hash(2),
22-
hash(3),
23-
hash(4),
24-
hash(5),
25-
hash(1024),
26-
hash(1025),
27-
]
28-
}
2919
}
3020
impl<R> PrecompileSet for FrontierPrecompiles<R>
3121
where
@@ -34,23 +24,42 @@ where
3424
fn execute(&self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
3525
match handle.code_address() {
3626
// Ethereum precompiles :
37-
a if a == hash(1) => Some(ECRecover::execute(handle)),
38-
a if a == hash(2) => Some(Sha256::execute(handle)),
39-
a if a == hash(3) => Some(Ripemd160::execute(handle)),
40-
a if a == hash(4) => Some(Identity::execute(handle)),
41-
a if a == hash(5) => Some(Modexp::execute(handle)),
27+
a if Precompiles::<R>::contains_key(b"ECRecover".to_vec(), a) => {
28+
Some(ECRecover::execute(handle))
29+
}
30+
a if Precompiles::<R>::contains_key(b"Sha256".to_vec(), a) => {
31+
Some(Sha256::execute(handle))
32+
}
33+
a if Precompiles::<R>::contains_key(b"Ripemd160".to_vec(), a) => {
34+
Some(Ripemd160::execute(handle))
35+
}
36+
a if Precompiles::<R>::contains_key(b"Identity".to_vec(), a) => {
37+
Some(Identity::execute(handle))
38+
}
39+
a if Precompiles::<R>::contains_key(b"Modexp".to_vec(), a) => {
40+
Some(Modexp::execute(handle))
41+
}
4242
// Non-Frontier specific nor Ethereum precompiles :
43-
a if a == hash(1024) => Some(Sha3FIPS256::execute(handle)),
44-
a if a == hash(1025) => Some(ECRecoverPublicKey::execute(handle)),
43+
a if Precompiles::<R>::contains_key(b"Sha3FIPS256".to_vec(), a) => {
44+
Some(Sha3FIPS256::execute(handle))
45+
}
46+
a if Precompiles::<R>::contains_key(b"ECRecoverPublicKey".to_vec(), a) => {
47+
Some(ECRecoverPublicKey::execute(handle))
48+
}
4549
_ => None,
4650
}
4751
}
4852

4953
fn is_precompile(&self, address: H160) -> bool {
50-
Self::used_addresses().contains(&address)
54+
match address {
55+
a if Precompiles::<R>::contains_key(b"ECRecover".to_vec(), a) => true,
56+
a if Precompiles::<R>::contains_key(b"Sha256".to_vec(), a) => true,
57+
a if Precompiles::<R>::contains_key(b"Ripemd160".to_vec(), a) => true,
58+
a if Precompiles::<R>::contains_key(b"Identity".to_vec(), a) => true,
59+
a if Precompiles::<R>::contains_key(b"Modexp".to_vec(), a) => true,
60+
a if Precompiles::<R>::contains_key(b"Sha3FIPS256".to_vec(), a) => true,
61+
a if Precompiles::<R>::contains_key(b"ECRecoverPublicKey".to_vec(), a) => true,
62+
_ => false,
63+
}
5164
}
5265
}
53-
54-
fn hash(a: u64) -> H160 {
55-
H160::from_low_u64_be(a)
56-
}

0 commit comments

Comments
 (0)