From da41c453cd7f4afe773c61c73758ba82d012be77 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 17 Jul 2020 16:41:04 +0200 Subject: [PATCH 1/4] pallet-evm: add support for tuple-based precompile declarations --- frame/evm/src/lib.rs | 26 +----------- frame/evm/src/precompiles.rs | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 frame/evm/src/precompiles.rs diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 1ecd65e193f7a..8ffbb96050bf9 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -21,8 +21,10 @@ #![cfg_attr(not(feature = "std"), no_std)] mod backend; +mod precompiles; mod tests; +pub use crate::precompiles::{Precompile, Precompiles}; pub use crate::backend::{Account, Log, Vicinity, Backend}; use sp_std::{vec::Vec, marker::PhantomData}; @@ -96,30 +98,6 @@ impl> ConvertAccountId for HashTruncateConvertAccou } } -/// Custom precompiles to be used by EVM engine. -pub trait Precompiles { - /// Try to execute the code address as precompile. If the code address is not - /// a precompile or the precompile is not yet available, return `None`. - /// Otherwise, calculate the amount of gas needed with given `input` and - /// `target_gas`. Return `Some(Ok(status, output, gas_used))` if the execution - /// is successful. Otherwise return `Some(Err(_))`. - fn execute( - address: H160, - input: &[u8], - target_gas: Option - ) -> Option, usize), ExitError>>; -} - -impl Precompiles for () { - fn execute( - _address: H160, - _input: &[u8], - _target_gas: Option - ) -> Option, usize), ExitError>> { - None - } -} - /// Substrate system chain ID. pub struct SystemChainId; diff --git a/frame/evm/src/precompiles.rs b/frame/evm/src/precompiles.rs new file mode 100644 index 0000000000000..11f344216a983 --- /dev/null +++ b/frame/evm/src/precompiles.rs @@ -0,0 +1,78 @@ +use sp_std::vec::Vec; +use sp_core::H160; +use evm::{ExitError, ExitSucceed}; + +/// Custom precompiles to be used by EVM engine. +pub trait Precompiles { + /// Try to execute the code address as precompile. If the code address is not + /// a precompile or the precompile is not yet available, return `None`. + /// Otherwise, calculate the amount of gas needed with given `input` and + /// `target_gas`. Return `Some(Ok(status, output, gas_used))` if the execution + /// is successful. Otherwise return `Some(Err(_))`. + fn execute( + address: H160, + input: &[u8], + target_gas: Option, + ) -> Option, usize), ExitError>>; +} + +impl Precompiles for () { + fn execute( + _address: H160, + _input: &[u8], + _target_gas: Option + ) -> Option, usize), ExitError>> { + None + } +} + +/// One single precompile used by EVM engine. +pub trait Precompile { + /// Try to execute the precompile. Calculate the amount of gas needed with given `input` and + /// `target_gas`. Return `Ok(status, output, gas_used)` if the execution is + /// successful. Otherwise return `Err(_)`. + fn execute( + input: &[u8], + target_gas: Option, + ) -> core::result::Result<(ExitSucceed, Vec, usize), ExitError>; +} + +macro_rules! impl_precompile_tuple { + ( ($($item:ident,)+) ) => { + impl<$($item: Precompile,)+> Precompiles for ($($item,)+) { + fn execute( + address: H160, + input: &[u8], + target_gas: Option, + ) -> Option, usize), ExitError>> { + let mut index = 0; + + $( + index += 1; + if address == H160::from_low_u64_be(index) { + return Some($item::execute(input, target_gas)) + } + )+ + + None + } + } + }; +} + +impl_precompile_tuple!((A,)); +impl_precompile_tuple!((A,B,)); +impl_precompile_tuple!((A,B,C,)); +impl_precompile_tuple!((A,B,C,D,)); +impl_precompile_tuple!((A,B,C,D,E,)); +impl_precompile_tuple!((A,B,C,D,E,F,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,)); +impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,)); From 8654cb85ce8263af0ef29f0073b7eb45f43c660d Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 23 Jul 2020 16:54:10 +0200 Subject: [PATCH 2/4] Add missing license header --- frame/evm/src/precompiles.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/frame/evm/src/precompiles.rs b/frame/evm/src/precompiles.rs index 11f344216a983..a4f2044c3837f 100644 --- a/frame/evm/src/precompiles.rs +++ b/frame/evm/src/precompiles.rs @@ -1,3 +1,20 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2020 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + use sp_std::vec::Vec; use sp_core::H160; use evm::{ExitError, ExitSucceed}; From 549f464fbe011f329f8124ea9ba10d188df6e520 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 23 Jul 2020 17:14:23 +0200 Subject: [PATCH 3/4] Switch to use impl_for_tuples --- Cargo.lock | 1 + frame/evm/Cargo.toml | 1 + frame/evm/src/precompiles.rs | 54 +++++++++++++----------------------- 3 files changed, 21 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e8a21ea6dd489..ab8124cb1d82c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4354,6 +4354,7 @@ dependencies = [ "evm", "frame-support", "frame-system", + "impl-trait-for-tuples", "pallet-balances", "pallet-timestamp", "parity-scale-codec", diff --git a/frame/evm/Cargo.toml b/frame/evm/Cargo.toml index 768d85bc94ba6..05f44f6ec02fa 100644 --- a/frame/evm/Cargo.toml +++ b/frame/evm/Cargo.toml @@ -26,6 +26,7 @@ primitive-types = { version = "0.7.0", default-features = false, features = ["rl rlp = { version = "0.4", default-features = false } evm = { version = "0.17", default-features = false } sha3 = { version = "0.8", default-features = false } +impl-trait-for-tuples = "0.1" [features] default = ["std"] diff --git a/frame/evm/src/precompiles.rs b/frame/evm/src/precompiles.rs index a4f2044c3837f..de13d93b30620 100644 --- a/frame/evm/src/precompiles.rs +++ b/frame/evm/src/precompiles.rs @@ -18,6 +18,7 @@ use sp_std::vec::Vec; use sp_core::H160; use evm::{ExitError, ExitSucceed}; +use impl_trait_for_tuples::impl_for_tuples; /// Custom precompiles to be used by EVM engine. pub trait Precompiles { @@ -54,42 +55,25 @@ pub trait Precompile { ) -> core::result::Result<(ExitSucceed, Vec, usize), ExitError>; } -macro_rules! impl_precompile_tuple { - ( ($($item:ident,)+) ) => { - impl<$($item: Precompile,)+> Precompiles for ($($item,)+) { - fn execute( - address: H160, - input: &[u8], - target_gas: Option, - ) -> Option, usize), ExitError>> { - let mut index = 0; +#[impl_for_tuples(1, 16)] +#[tuple_types_no_default_trait_bound] +impl Precompiles for Tuple { + for_tuples!( where #( Tuple: Precompile )* ); - $( - index += 1; - if address == H160::from_low_u64_be(index) { - return Some($item::execute(input, target_gas)) - } - )+ + fn execute( + address: H160, + input: &[u8], + target_gas: Option, + ) -> Option, usize), ExitError>> { + let mut index = 0; - None + for_tuples!( #( + index += 1; + if address == H160::from_low_u64_be(index) { + return Some(Tuple::execute(input, target_gas)) } - } - }; -} + )* ); -impl_precompile_tuple!((A,)); -impl_precompile_tuple!((A,B,)); -impl_precompile_tuple!((A,B,C,)); -impl_precompile_tuple!((A,B,C,D,)); -impl_precompile_tuple!((A,B,C,D,E,)); -impl_precompile_tuple!((A,B,C,D,E,F,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,)); -impl_precompile_tuple!((A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,)); + None + } +} From 032ac624061ba5bac9159938a27ffa21f170b506 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 27 Jul 2020 16:15:39 +0200 Subject: [PATCH 4/4] Remove unnecessary impl for () --- frame/evm/src/precompiles.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/frame/evm/src/precompiles.rs b/frame/evm/src/precompiles.rs index de13d93b30620..a6a10d45a2083 100644 --- a/frame/evm/src/precompiles.rs +++ b/frame/evm/src/precompiles.rs @@ -34,16 +34,6 @@ pub trait Precompiles { ) -> Option, usize), ExitError>>; } -impl Precompiles for () { - fn execute( - _address: H160, - _input: &[u8], - _target_gas: Option - ) -> Option, usize), ExitError>> { - None - } -} - /// One single precompile used by EVM engine. pub trait Precompile { /// Try to execute the precompile. Calculate the amount of gas needed with given `input` and @@ -55,7 +45,7 @@ pub trait Precompile { ) -> core::result::Result<(ExitSucceed, Vec, usize), ExitError>; } -#[impl_for_tuples(1, 16)] +#[impl_for_tuples(16)] #[tuple_types_no_default_trait_bound] impl Precompiles for Tuple { for_tuples!( where #( Tuple: Precompile )* );