Skip to content

Commit

Permalink
Add mock for frame Ethereum (#32)
Browse files Browse the repository at this point in the history
* Add mock for frame Ethereum

* Adds tests file for frame ethereum

* Adds tests for frame ethereum

* Updates to rc3

* Adds better test settup for ethereum frame
  • Loading branch information
crystalin authored Jun 12, 2020
1 parent 530b734 commit ad879de
Show file tree
Hide file tree
Showing 6 changed files with 419 additions and 9 deletions.
4 changes: 4 additions & 0 deletions frame/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ description = "Ethereum compatibility full block processing emulation pallet for
license = "GPL-3.0"

[dependencies]
rustc-hex = { version = "2.1.0", default-features = false }
serde = { version = "1.0.101", optional = true }
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false }
frame-support = { version = "2.0.0-dev", default-features = false, path = "../../vendor/substrate/frame/support" }
Expand All @@ -21,6 +22,7 @@ ethereum = { version = "0.2", default-features = false, features = ["codec"] }
ethereum-types = { version = "0.9", default-features = false }
rlp = { version = "0.4", default-features = false }
sha3 = { version = "0.8", default-features = false }
libsecp256k1 = { version = "0.3", default-features = false }
frontier-rpc-primitives = { path = "../../rpc/primitives", default-features = false }

[dev-dependencies]
Expand All @@ -30,6 +32,7 @@ sp-core = { version = "2.0.0-dev", path = "../../vendor/substrate/primitives/cor
default = ["std"]
std = [
"serde",
"rustc-hex/std",
"codec/std",
"sp-runtime/std",
"frame-support/std",
Expand All @@ -43,5 +46,6 @@ std = [
"ethereum-types/std",
"rlp/std",
"sha3/std",
"libsecp256k1/std",
"frontier-rpc-primitives/std",
]
6 changes: 6 additions & 0 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ use sha3::{Digest, Keccak256};
pub use frontier_rpc_primitives::TransactionStatus;
pub use ethereum::{Transaction, Log, Block};

#[cfg(all(feature = "std", test))]
mod tests;

#[cfg(all(feature = "std", test))]
mod mock;

/// A type alias for the balance type from this pallet's point of view.
pub type BalanceOf<T> = <T as pallet_balances::Trait>::Balance;

Expand Down
228 changes: 228 additions & 0 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Frontier.

// Substrate 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.

// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.

//! Test utilities

use super::*;
use crate::{Module, Trait};
use ethereum::{TransactionAction, TransactionSignature};
use frame_support::{impl_outer_origin, parameter_types, weights::Weight};
use pallet_evm::{FeeCalculator, HashTruncateConvertAccountId};
use rlp::*;
use sp_core::{H160, H256, U256};
use sp_runtime::{
testing::Header,
traits::{BlakeTwo256, IdentityLookup},
ModuleId, Perbill,
};

impl_outer_origin! {
pub enum Origin for Test where system = frame_system {}
}

// For testing the pallet, we construct most of a mock runtime. This means
// first constructing a configuration type (`Test`) which `impl`s each of the
// configuration traits of pallets we want to use.
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
}
impl frame_system::Trait for Test {
type Origin = Origin;
type Call = ();
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = H160;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = ();
type BlockExecutionWeight = ();
type ExtrinsicBaseWeight = ();
type MaximumExtrinsicWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
type ModuleToIndex = ();
type AccountData = pallet_balances::AccountData<u64>;
type OnNewAccount = ();
type OnKilledAccount = ();
}

parameter_types! {
pub const ExistentialDeposit: u64 = 500;
}

impl pallet_balances::Trait for Test {
type Balance = u64;
type Event = ();
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
}

parameter_types! {
pub const MinimumPeriod: u64 = 6000 / 2;
}

impl pallet_timestamp::Trait for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = MinimumPeriod;
}

pub struct FixedGasPrice;
impl FeeCalculator for FixedGasPrice {
fn min_gas_price() -> U256 {
1.into()
}
}

parameter_types! {
pub const TransactionByteFee: u64 = 1;
pub const EVMModuleId: ModuleId = ModuleId(*b"py/evmpa");
}

impl pallet_evm::Trait for Test {
type ModuleId = EVMModuleId;
type FeeCalculator = FixedGasPrice;
type ConvertAccountId = HashTruncateConvertAccountId<BlakeTwo256>;
type Currency = Balances;
type Event = ();
type Precompiles = ();
}

impl Trait for Test {
type Event = ();
}

pub type System = frame_system::Module<Test>;
pub type Balances = pallet_balances::Module<Test>;
pub type Ethereum = Module<Test>;
pub type Evm = pallet_evm::Module<Test>;

pub struct AccountInfo {
pub address: H160,
pub private_key: H256,
}

// This function basically just builds a genesis storage key/value store according to
// our desired mockup.
pub fn new_test_ext(accounts_len: usize) -> (Vec<AccountInfo>, sp_io::TestExternalities) {
let ext = frame_system::GenesisConfig::default()
.build_storage::<Test>()
.unwrap()
.into();

let pairs = (0..accounts_len)
.map(|i| {
let private_key = H256::from_slice(&[(i + 1) as u8; 32]); //H256::from_low_u64_be((i + 1) as u64);
let secret_key = secp256k1::SecretKey::parse_slice(&private_key[..]).unwrap();
let public_key = secp256k1::PublicKey::from_secret_key(&secret_key);
let address = H160::from(H256::from_slice(
&Keccak256::digest(&public_key.serialize()[1..])[..],
));
AccountInfo {
private_key: private_key,
address: address,
}
})
.collect::<Vec<_>>();

(pairs, ext)
}

pub fn contract_address(sender: H160, nonce: u64) -> H160 {
let mut rlp = RlpStream::new_list(2);
rlp.append(&sender);
rlp.append(&nonce);

H160::from_slice(&Keccak256::digest(rlp.out().as_slice())[12..])
}

pub fn storage_address(sender: H160, slot: H256) -> H256 {
H256::from_slice(&Keccak256::digest(
[&H256::from(sender)[..], &slot[..]].concat().as_slice(),
))
}

pub struct UnsignedTransaction {
pub nonce: U256,
pub gas_price: U256,
pub gas_limit: U256,
pub action: TransactionAction,
pub value: U256,
pub input: Vec<u8>,
}

impl UnsignedTransaction {
fn signing_rlp_append(&self, s: &mut RlpStream) {
s.begin_list(9);
s.append(&self.nonce);
s.append(&self.gas_price);
s.append(&self.gas_limit);
s.append(&self.action);
s.append(&self.value);
s.append(&self.input);
s.append(&42u8); // TODO: move this chain id into the frame ethereum configuration
s.append(&0u8);
s.append(&0u8);
}

fn signing_hash(&self) -> H256 {
let mut stream = RlpStream::new();
self.signing_rlp_append(&mut stream);
H256::from_slice(&Keccak256::digest(&stream.drain()).as_slice())
}

pub fn sign(self, key: &H256) -> Transaction {
let hash = self.signing_hash();
let msg = {
let mut a = [0u8; 32];
for i in 0..32 {
a[i] = hash[i];
}
secp256k1::Message::parse(&a)
};
let s = secp256k1::sign(&msg, &secp256k1::SecretKey::parse_slice(&key[..]).unwrap());
let sig = s.0.serialize();

let sig = TransactionSignature::new(
0x78,
H256::from_slice(&sig[0..32]),
H256::from_slice(&sig[32..64]),
)
.unwrap();

Transaction {
nonce: self.nonce,
gas_price: self.gas_price,
gas_limit: self.gas_limit,
action: self.action,
value: self.value,
input: self.input,
signature: sig,
}
}
}
Loading

0 comments on commit ad879de

Please sign in to comment.