Skip to content

Commit

Permalink
Add precompile support for Substrate dispatchables (#246)
Browse files Browse the repository at this point in the history
  • Loading branch information
sorpaas authored Dec 16, 2020
1 parent 23cdfb5 commit 25a9c9d
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 22 deletions.
29 changes: 21 additions & 8 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"frame/evm/precompile/ed25519",
"frame/evm/precompile/bn128",
"frame/evm/precompile/blake2",
"frame/evm/precompile/dispatch",
"client/consensus",
"client/rpc-core",
"client/rpc",
Expand Down
2 changes: 1 addition & 1 deletion frame/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ sp-runtime = { version = "2.0.0-dev", default-features = false, git = "https://g
sp-std = { version = "2.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../primitives/evm" }
evm = { version = "0.19.0", features = ["with-codec"], default-features = false }
evm = { version = "0.20.0", features = ["with-codec"], default-features = false }
ethereum = { version = "0.5", default-features = false, features = ["with-codec"] }
ethereum-types = { version = "0.9", default-features = false }
rlp = { version = "0.4", default-features = false }
Expand Down
6 changes: 3 additions & 3 deletions frame/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ sp-io = { version = "2.0.0", default-features = false, git = "https://github.com
fp-evm = { version = "0.8.0", default-features = false, path = "../../primitives/evm" }
primitive-types = { version = "0.7.0", default-features = false, features = ["rlp", "byteorder"] }
rlp = { version = "0.4", default-features = false }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm-runtime = { version = "0.19.0", default-features = false }
evm-gasometer = { version = "0.19.0", default-features = false }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
evm-runtime = { version = "0.20.0", default-features = false }
evm-gasometer = { version = "0.20.0", default-features = false }
sha3 = { version = "0.8", default-features = false }

[features]
Expand Down
2 changes: 1 addition & 1 deletion frame/evm/precompile/blake2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description = "BLAKE2 precompiles for EVM pallet."
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }

[features]
default = ["std"]
Expand Down
2 changes: 1 addition & 1 deletion frame/evm/precompile/bn128/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description = "BN128 precompiles for EVM pallet."
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
bn = { package = "substrate-bn", version = "0.5", default-features = false }

[features]
Expand Down
30 changes: 30 additions & 0 deletions frame/evm/precompile/dispatch/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "pallet-evm-precompile-dispatch"
version = "2.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/substrate/"
description = "DISPATCH precompiles for EVM pallet."

[dependencies]
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
frame-support = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
pallet-evm = { version = "2.0.0", default-features = false, path = "../.." }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
codec = { package = "parity-scale-codec", version = "1.3.5", default-features = false }

[features]
default = ["std"]
std = [
"sp-core/std",
"sp-io/std",
"frame-support/std",
"pallet-evm/std",
"fp-evm/std",
"evm/std",
"codec/std",
]
69 changes: 69 additions & 0 deletions frame/evm/precompile/dispatch/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: Apache-2.0
// This file is part of Frontier.
//
// Copyright (c) 2020 Parity Technologies (UK) Ltd.
//
// 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.

#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

use alloc::vec::Vec;
use core::marker::PhantomData;
use fp_evm::Precompile;
use evm::{ExitSucceed, ExitError, Context};
use frame_support::{dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo}, weights::{Pays, DispatchClass}};
use pallet_evm::AddressMapping;
use codec::Decode;

pub struct Dispatch<T: pallet_evm::Config> {
_marker: PhantomData<T>,
}

impl<T> Precompile for Dispatch<T> where
T: pallet_evm::Config,
T::Call: Dispatchable<PostInfo=PostDispatchInfo> + GetDispatchInfo + Decode,
<T::Call as Dispatchable>::Origin: From<Option<T::AccountId>>,
{
fn execute(
input: &[u8],
target_gas: Option<usize>,
context: &Context,
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
let call = T::Call::decode(&mut &input[..]).map_err(|_| ExitError::Other("decode failed".into()))?;
let info = call.get_dispatch_info();

let valid_call = info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal;
if !valid_call {
return Err(ExitError::Other("invalid call".into()))
}

if let Some(gas) = target_gas {
let valid_weight = info.weight <= gas as u64;
if !valid_weight {
return Err(ExitError::OutOfGas)
}
}

let origin = T::AddressMapping::into_account_id(context.caller);

match call.dispatch(Some(origin).into()) {
Ok(post_info) => {
let cost = post_info.actual_weight.unwrap_or(info.weight) as usize;
Ok((ExitSucceed::Stopped, Default::default(), cost))
},
Err(_) => Err(ExitError::Other("dispatch execution failed".into())),
}
}
}
2 changes: 1 addition & 1 deletion frame/evm/precompile/ed25519/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description = "ED25519 precompiles for EVM pallet."
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
ed25519-dalek = { version = "1.0.0", features = ["alloc", "u64_backend"], default-features = false }

[features]
Expand Down
2 changes: 1 addition & 1 deletion frame/evm/precompile/modexp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description = "MODEXP precompiles for EVM pallet."
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
num = { version = "0.3", features = ["alloc"], default-features = false }

[features]
Expand Down
2 changes: 1 addition & 1 deletion frame/evm/precompile/simple/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description = "Simple precompiles for EVM pallet."
sp-core = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
sp-io = { version = "2.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "frontier" }
fp-evm = { version = "0.8.0", default-features = false, path = "../../../../primitives/evm" }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
ripemd160 = { version = "0.9", default-features = false }

[features]
Expand Down
4 changes: 2 additions & 2 deletions frame/evm/src/runner/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ pub struct Handler<'vicinity, 'config, T: Config> {
gasometer: Gasometer<'config>,
deleted: BTreeSet<H160>,
logs: Vec<Log>,
precompile: fn(H160, &[u8], Option<usize>) ->
precompile: fn(H160, &[u8], Option<usize>, &Context) ->
Option<Result<(ExitSucceed, Vec<u8>, usize), ExitError>>,
is_static: bool,
_marker: PhantomData<T>,
Expand All @@ -299,7 +299,7 @@ impl<'vicinity, 'config, T: Config> Handler<'vicinity, 'config, T> {
gas_limit: usize,
is_static: bool,
config: &'config EvmConfig,
precompile: fn(H160, &[u8], Option<usize>) ->
precompile: fn(H160, &[u8], Option<usize>, &Context) ->
Option<Result<(ExitSucceed, Vec<u8>, usize), ExitError>>,
) -> Self {
Self {
Expand Down
2 changes: 1 addition & 1 deletion primitives/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ sp-core = { version = "2.0.0", git = "https://github.com/paritytech/substrate.gi
sp-std = { version = "2.0.0", git = "https://github.com/paritytech/substrate.git", branch = "frontier", default-features = false }
serde = { version = "1.0.101", optional = true, features = ["derive"] }
codec = { package = "parity-scale-codec", version = "1.3.4", default-features = false }
evm = { version = "0.19.0", default-features = false, features = ["with-codec"] }
evm = { version = "0.20.0", default-features = false, features = ["with-codec"] }
impl-trait-for-tuples = "0.1"

[features]
Expand Down
8 changes: 6 additions & 2 deletions primitives/evm/src/precompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use sp_std::vec::Vec;
use sp_core::H160;
use impl_trait_for_tuples::impl_for_tuples;
use evm::{ExitSucceed, ExitError};
use evm::{ExitSucceed, ExitError, Context};

/// Custom precompiles to be used by EVM engine.
pub trait PrecompileSet {
Expand All @@ -31,6 +31,7 @@ pub trait PrecompileSet {
address: H160,
input: &[u8],
target_gas: Option<usize>,
context: &Context,
) -> Option<core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError>>;
}

Expand All @@ -42,6 +43,7 @@ pub trait Precompile {
fn execute(
input: &[u8],
target_gas: Option<usize>,
context: &Context,
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError>;
}

Expand All @@ -54,13 +56,14 @@ impl PrecompileSet for Tuple {
address: H160,
input: &[u8],
target_gas: Option<usize>,
context: &Context,
) -> Option<core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError>> {
let mut index = 0;

for_tuples!( #(
index += 1;
if address == H160::from_low_u64_be(index) {
return Some(Tuple::execute(input, target_gas))
return Some(Tuple::execute(input, target_gas, context))
}
)* );

Expand All @@ -82,6 +85,7 @@ impl<T: LinearCostPrecompile> Precompile for T {
fn execute(
input: &[u8],
target_gas: Option<usize>,
_: &Context,
) -> core::result::Result<(ExitSucceed, Vec<u8>, usize), ExitError> {
let cost = ensure_linear_cost(target_gas, input.len(), T::BASE, T::WORD)?;

Expand Down

0 comments on commit 25a9c9d

Please sign in to comment.