Skip to content

Commit

Permalink
Evm utiltity (#1501)
Browse files Browse the repository at this point in the history
* add evm-utiltity

* add keccak256 macro

* use keccak256 macro

* fix tests

* remove primitives/proc-macro

* avoid additional allocation

* fix tests
  • Loading branch information
zjb0807 authored Oct 20, 2021
1 parent 432236b commit 0fe2b2a
Show file tree
Hide file tree
Showing 20 changed files with 168 additions and 63 deletions.
34 changes: 20 additions & 14 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ members = [
"node/service",

"modules/*",
"modules/evm-utiltity/macro",
"inspect",
"primitives",
"primitives/proc-macro",
"rpc",

"runtime/common",
Expand Down
2 changes: 1 addition & 1 deletion modules/evm-bridge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ primitive-types = { version = "0.10.1", default-features = false, features = ["r
impl-trait-for-tuples = "0.2.1"
ethereum-types = { version = "0.12.0", default-features = false }
primitives = { package = "acala-primitives", path = "../../primitives", default-features = false }
primitives-proc-macro = { path = "../../primitives/proc-macro" }
support = { package = "module-support", path = "../support", default-features = false }
module-evm = { path = "../evm", default-features = false }
module-evm-utiltity-macro = { path = "../evm-utiltity/macro" }
num_enum = { version = "0.5.1", default-features = false }

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion modules/evm-bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use support::{EVMBridge as EVMBridgeTrait, ExecutionMode, InvokeContext, EVM};
type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
type BalanceOf<T> = <<T as Config>::EVM as EVM<AccountIdOf<T>>>::Balance;

#[primitives_proc_macro::generate_function_selector]
#[module_evm_utiltity_macro::generate_function_selector]
#[derive(RuntimeDebug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Action {
Expand Down
8 changes: 8 additions & 0 deletions modules/evm-utiltity/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "module-evm-utiltity"
version = "1.5.1"
authors = ["Acala Developers"]
edition = "2018"

[dependencies]
sha3 = { version = "0.9.1" }
14 changes: 14 additions & 0 deletions modules/evm-utiltity/macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "module-evm-utiltity-macro"
version = "1.5.1"
authors = ["Acala Developers"]
edition = "2018"

[lib]
proc-macro = true

[dependencies]
quote = "1.0.10"
syn = { version = "1.0.80", features = ["full", "fold", "extra-traits", "visit"] }
proc-macro2 = "1.0.30"
module-evm-utiltity = { path = ".." }
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
use proc_macro::TokenStream;
use proc_macro2::Literal;
use quote::quote;
use sha3::{Digest, Keccak256};
use std::convert::TryInto;
use syn::{parse_macro_input, Expr, ExprLit, Ident, ItemEnum, Lit};
use syn::{parse_macro_input, Expr, ExprLit, Ident, ItemEnum, Lit, LitByteStr, LitStr};

#[proc_macro_attribute]
pub fn generate_function_selector(_: TokenStream, input: TokenStream) -> TokenStream {
Expand All @@ -41,7 +39,7 @@ pub fn generate_function_selector(_: TokenStream, input: TokenStream) -> TokenSt
for variant in variants {
if let Some((_, Expr::Lit(ExprLit { lit, .. }))) = variant.discriminant {
if let Lit::Str(token) = lit {
let selector = get_function_selector(&token.value());
let selector = module_evm_utiltity::get_function_selector(&token.value());
// println!("method: {:?}, selector: {:?}", token.value(), selector);
ident_expressions.push(variant.ident);
variant_expressions.push(Expr::Lit(ExprLit {
Expand All @@ -67,12 +65,13 @@ pub fn generate_function_selector(_: TokenStream, input: TokenStream) -> TokenSt
.into()
}

fn get_function_selector(s: &str) -> u32 {
// create a SHA3-256 object
let mut hasher = Keccak256::new();
// write input message
hasher.update(s);
// read hash digest
let result = hasher.finalize();
u32::from_be_bytes(result[..4].try_into().unwrap())
#[proc_macro]
pub fn keccak256(input: TokenStream) -> TokenStream {
let lit_str = parse_macro_input!(input as LitStr);

let result = module_evm_utiltity::sha3_256(&lit_str.value());

let eval = Lit::ByteStr(LitByteStr::new(&result.to_vec(), proc_macro2::Span::call_site()));

quote!(#eval).into()
}
54 changes: 54 additions & 0 deletions modules/evm-utiltity/macro/tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// This file is part of Acala.

// Copyright (C) 2020-2021 Acala Foundation.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#[cfg(test)]
mod tests {
#[test]
fn generate_function_selector_works() {
#[module_evm_utiltity_macro::generate_function_selector]
#[derive(Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Action {
Name = "name()",
Symbol = "symbol()",
Decimals = "decimals()",
TotalSupply = "totalSupply()",
BalanceOf = "balanceOf(address)",
Transfer = "transfer(address,uint256)",
}

assert_eq!(Action::Name as u32, 0x06fdde03_u32);
assert_eq!(Action::Symbol as u32, 0x95d89b41_u32);
assert_eq!(Action::Decimals as u32, 0x313ce567_u32);
assert_eq!(Action::TotalSupply as u32, 0x18160ddd_u32);
assert_eq!(Action::BalanceOf as u32, 0x70a08231_u32);
assert_eq!(Action::Transfer as u32, 0xa9059cbb_u32);
}

#[test]
fn keccak256_works() {
assert_eq!(
module_evm_utiltity_macro::keccak256!(""),
&module_evm_utiltity::sha3_256("")
);
assert_eq!(
module_evm_utiltity_macro::keccak256!("keccak256"),
&module_evm_utiltity::sha3_256("keccak256")
);
}
}
42 changes: 42 additions & 0 deletions modules/evm-utiltity/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// This file is part of Acala.

// Copyright (C) 2020-2021 Acala Foundation.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! # Evm utiltity Module
//!
//! A pallet provides some utility methods.
use sha3::{Digest, Keccak256};
use std::convert::TryInto;

pub fn sha3_256(s: &str) -> [u8; 32] {
let mut result = [0u8; 32];

// create a SHA3-256 object
let mut hasher = Keccak256::new();
// write input message
hasher.update(s);
// read hash digest
result.copy_from_slice(&hasher.finalize()[..32]);

result
}

pub fn get_function_selector(s: &str) -> u32 {
let result = sha3_256(s);
u32::from_be_bytes(result[..4].try_into().unwrap())
}
2 changes: 1 addition & 1 deletion primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ ethereum = { git = "https://github.com/PureStake/ethereum", branch = "joshy-scal
evm = { git = "https://github.com/PureStake/evm", branch = "joshy-scale-info", default-features = false, features = ["with-codec"] }

nutsfinance-stable-asset = { version = "0.1.0", default-features = false, path = "../ecosystem-modules/stable-asset/lib/stable-asset", package = "nutsfinance-stable-asset" }
module-evm-utiltity-macro = { path = "../modules/evm-utiltity/macro" }

[dev-dependencies]
serde_json = { version = "1.0.64" }
hex-literal = "0.3.1"
primitives-proc-macro = { path = "./proc-macro" }

[features]
default = ["std"]
Expand Down
15 changes: 0 additions & 15 deletions primitives/proc-macro/Cargo.toml

This file was deleted.

2 changes: 1 addition & 1 deletion primitives/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ fn currency_id_try_into_evm_address_works() {

#[test]
fn generate_function_selector_works() {
#[primitives_proc_macro::generate_function_selector]
#[module_evm_utiltity_macro::generate_function_selector]
#[derive(RuntimeDebug, Eq, PartialEq)]
#[repr(u32)]
pub enum Action {
Expand Down
17 changes: 7 additions & 10 deletions primitives/src/unchecked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use frame_support::{
traits::ExtrinsicCall,
weights::{DispatchInfo, GetDispatchInfo},
};
use module_evm_utiltity_macro::keccak256;
use scale_info::TypeInfo;
use sp_core::{H160, H256, U256};
use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256};
Expand Down Expand Up @@ -206,28 +207,24 @@ fn recover_signer(sig: &[u8; 65], msg_hash: &[u8; 32]) -> Option<H160> {
}

fn verify_eip712_signature(eth_msg: EthereumTransactionMessage, sig: [u8; 65]) -> Option<H160> {
// TODO: do the hash at compile time
let eip712_domain = b"EIP712Domain(string name,string version,uint256 chainId,bytes32 salt)";
let tx_type = b"Transaction(string action,address to,uint256 nonce,uint256 tip,bytes data,uint256 value,uint256 gasLimit,uint256 storageLimit,uint256 validUntil)";

let domain_hash = keccak_256(eip712_domain);
let tx_type_hash = keccak_256(tx_type);
let domain_hash = keccak256!("EIP712Domain(string name,string version,uint256 chainId,bytes32 salt)");
let tx_type_hash = keccak256!("Transaction(string action,address to,uint256 nonce,uint256 tip,bytes data,uint256 value,uint256 gasLimit,uint256 storageLimit,uint256 validUntil)");

let mut domain_seperator_msg = domain_hash.to_vec();
domain_seperator_msg.extend_from_slice(&keccak_256(b"Acala EVM")); // name
domain_seperator_msg.extend_from_slice(&keccak_256(b"1")); // version
domain_seperator_msg.extend_from_slice(keccak256!("Acala EVM")); // name
domain_seperator_msg.extend_from_slice(keccak256!("1")); // version
domain_seperator_msg.extend_from_slice(&to_bytes(eth_msg.chain_id)); // chain id
domain_seperator_msg.extend_from_slice(eth_msg.genesis.as_bytes()); // salt
let domain_separator = keccak_256(domain_seperator_msg.as_slice());

let mut tx_msg = tx_type_hash.to_vec();
match eth_msg.action {
TransactionAction::Call(to) => {
tx_msg.extend_from_slice(&keccak_256(b"Call"));
tx_msg.extend_from_slice(keccak256!("Call"));
tx_msg.extend_from_slice(H256::from(to).as_bytes());
}
TransactionAction::Create => {
tx_msg.extend_from_slice(&keccak_256(b"Create"));
tx_msg.extend_from_slice(keccak256!("Create"));
tx_msg.extend_from_slice(H256::default().as_bytes());
}
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ orml-oracle = { path = "../../orml/oracle", default-features = false }
orml-traits = { path = "../../orml/traits", default-features = false }

module-evm = { path = "../../modules/evm", default-features = false }
module-evm-utiltity-macro = { path = "../../modules/evm-utiltity/macro" }
module-staking-pool = { path = "../../modules/staking-pool", default-features = false }
module-support = { path = "../../modules/support", default-features = false }
primitives = { package = "acala-primitives", path = "../../primitives", default-features = false }
primitives-proc-macro = { path = "../../primitives/proc-macro" }

[dev-dependencies]
serde_json = "1.0.64"
Expand Down
2 changes: 1 addition & 1 deletion runtime/common/src/precompile/dex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub struct DexPrecompile<AccountId, AddressMapping, CurrencyIdMapping, Dex>(
PhantomData<(AccountId, AddressMapping, CurrencyIdMapping, Dex)>,
);

#[primitives_proc_macro::generate_function_selector]
#[module_evm_utiltity_macro::generate_function_selector]
#[derive(RuntimeDebug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Action {
Expand Down
2 changes: 1 addition & 1 deletion runtime/common/src/precompile/multicurrency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct MultiCurrencyPrecompile<AccountId, AddressMapping, CurrencyIdMapping,
PhantomData<(AccountId, AddressMapping, CurrencyIdMapping, MultiCurrency)>,
);

#[primitives_proc_macro::generate_function_selector]
#[module_evm_utiltity_macro::generate_function_selector]
#[derive(RuntimeDebug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum Action {
Expand Down
Loading

0 comments on commit 0fe2b2a

Please sign in to comment.