Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EthRelay module tests #142

Merged
merged 9 commits into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

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

30 changes: 15 additions & 15 deletions core/sr-eth-primitives/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ enum Seal {

#[derive(Default, PartialEq, Eq, Clone, Encode, Decode, RlpEncodable, RlpDecodable, RuntimeDebug)]
pub struct EthHeader {
parent_hash: H256,
timestamp: u64,
number: BlockNumber,
author: Address,
transactions_root: H256,
uncles_hash: H256,
extra_data: Bytes,
state_root: H256,
receipts_root: H256,
log_bloom: Bloom,
gas_used: U256,
gas_limit: U256,
difficulty: U256,
seal: Vec<Bytes>,
hash: Option<H256>,
pub parent_hash: H256,
pub timestamp: u64,
pub number: BlockNumber,
pub author: Address,
pub transactions_root: H256,
pub uncles_hash: H256,
pub extra_data: Bytes,
pub state_root: H256,
pub receipts_root: H256,
pub log_bloom: Bloom,
pub gas_used: U256,
pub gas_limit: U256,
pub difficulty: U256,
pub seal: Vec<Bytes>,
pub hash: Option<H256>,
}

/// Alter value of given field, reset memoised hash if changed.
Expand Down
9 changes: 9 additions & 0 deletions srml/eth-relay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ rlp = { package = "rlp", git = "https://github.com/darwinia-network/parity-commo
ethash = { git = "https://github.com/hammeWang/ethash-rs.git", rev = "70a4f078", default-features = false}
merkle-patricia-trie = { path = "../../core/merkle-patricia-trie", default-features = false}

[dev-dependencies]
runtime-io = { package = "sr-io", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop"}
primitives = { package = "substrate-primitives", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop" }
transaction-payment = { package = "srml-transaction-payment", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop" }
rustc-hex = "2.0"
keccak-hasher = "0.15.2"
triehash = { package = "triehash", git = "https://github.com/darwinia-network/parity-common.git" }
hex-literal = "0.2.1"

[features]
default = ["std"]
std = [
Expand Down
73 changes: 38 additions & 35 deletions srml/eth-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ use merkle_patricia_trie::{trie::Trie, MerklePatriciaTrie, Proof};

type DAG = LightDAG<EthereumPatch>;

mod mock;
hackfisher marked this conversation as resolved.
Show resolved Hide resolved
mod tests;
hackfisher marked this conversation as resolved.
Show resolved Hide resolved

pub trait Trait: system::Trait {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
Expand Down Expand Up @@ -99,6 +102,9 @@ decl_module! {
pub fn test_relay_header(origin, header: EthHeader) {
let _relayer = ensure_signed(origin)?;

// TODO: Just for easy testing.
Self::genesis_header(&header);

<Module<T>>::deposit_event(RawEvent::NewHeader(header));
}

Expand Down Expand Up @@ -136,37 +142,14 @@ decl_module! {
<Module<T>>::deposit_event(RawEvent::NewHeader(header));
}

pub fn test_check_receipt(origin, receipt: Receipt, proof_record: ActionRecord) {
let _relayer = ensure_signed(origin)?;

<Module<T>>::deposit_event(RawEvent::RelayProof(proof_record));
}

pub fn check_receipt(origin, receipt: Receipt, proof_record: ActionRecord) {
pub fn check_receipt(origin, proof_record: ActionRecord) {
let _relayer = ensure_signed(origin)?;

let header_hash = proof_record.header_hash;
if !HeaderOf::exists(header_hash) {
return Err("This block header does not exist.")
}

let header = HeaderOf::get(header_hash).unwrap();

let proof: Proof = rlp::decode(&proof_record.proof).unwrap();
let key = rlp::encode(&proof_record.index);
let verified_receipt = Self::verify_receipt(&proof_record);

let value = MerklePatriciaTrie::verify_proof(header.receipts_root().0.to_vec(), &key, proof)
.unwrap();
assert!(value.is_some());
ensure!(verified_receipt.is_some(), "Receipt proof verification failed.");

let receipt_encoded = rlp::encode(&receipt);

assert_eq!(value.unwrap(), receipt_encoded);
// confirm that the block hash is right
// get the receipt MPT trie root from the block header
// Using receipt MPT trie root to verify the proof and index etc.

<Module<T>>::deposit_event(RawEvent::RelayProof(proof_record));
<Module<T>>::deposit_event(RawEvent::RelayProof(verified_receipt.unwrap(), proof_record));
}

// Assuming that there are at least one honest worker submiting headers
Expand All @@ -184,7 +167,7 @@ decl_event! {
<T as system::Trait>::AccountId
{
NewHeader(EthHeader),
RelayProof(ActionRecord),
RelayProof(Receipt, ActionRecord),
TODO(AccountId),
}
}
Expand All @@ -208,6 +191,30 @@ impl<T: Trait> Module<T> {
BeginHeader::put(header.clone());
}

fn verify_receipt(proof_record: &ActionRecord) -> Option<Receipt> {
let header_hash = proof_record.header_hash;
if !HeaderOf::exists(header_hash) {
return None; //Err("This block header does not exist.");
}

let header = HeaderOf::get(header_hash).unwrap();

let proof: Proof = rlp::decode(&proof_record.proof).unwrap();
let key = rlp::encode(&proof_record.index);

let value = MerklePatriciaTrie::verify_proof(header.receipts_root().0.to_vec(), &key, proof).unwrap();
if !value.is_some() {
return None;
}

let proof_receipt: Receipt = rlp::decode(&value.unwrap()).expect("can't deserialize the receipt");

Some(proof_receipt)
// confirm that the block hash is right
// get the receipt MPT trie root from the block header
// Using receipt MPT trie root to verify the proof and index etc.
}

/// 1. proof of difficulty
/// 2. proof of pow (mixhash)
/// 3. challenge
Expand All @@ -228,13 +235,9 @@ impl<T: Trait> Module<T> {
// check difficulty
let ethash_params = EthashPartial::production();
// ethash_params.set_difficulty_bomb_delays(0xc3500, 5000000);
let result = ethash_params.verify_block_basic(header);
match result {
Ok(_) => (),
Err(e) => {
return Err("Block difficulty verification failed.");
}
};
let result = ethash_params
.verify_block_basic(header)
.expect("Block difficulty verification failed.");

// verify difficulty
let difficulty = ethash_params.calculate_difficulty(header, &prev_header);
Expand Down
155 changes: 155 additions & 0 deletions srml/eth-relay/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//! Test utilities

#![cfg(test)]
hackfisher marked this conversation as resolved.
Show resolved Hide resolved

use crate::{GenesisConfig, Module, Trait};
use primitives::H256;
use runtime_io;
use sr_primitives::{
testing::Header,
traits::{ConvertInto, IdentityLookup},
weights::{DispatchInfo, Weight},
Perbill,
};
use std::cell::RefCell;
use support::traits::Get;
use support::{impl_outer_origin, parameter_types};

impl_outer_origin! {
pub enum Origin for Runtime {}
}

thread_local! {
static EXISTENTIAL_DEPOSIT: RefCell<u64> = RefCell::new(0);
static TRANSFER_FEE: RefCell<u64> = RefCell::new(0);
static CREATION_FEE: RefCell<u64> = RefCell::new(0);
}

pub struct ExistentialDeposit;
impl Get<u64> for ExistentialDeposit {
fn get() -> u64 {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow())
}
}

pub struct TransferFee;
impl Get<u64> for TransferFee {
fn get() -> u64 {
TRANSFER_FEE.with(|v| *v.borrow())
}
}

pub struct CreationFee;
impl Get<u64> for CreationFee {
fn get() -> u64 {
CREATION_FEE.with(|v| *v.borrow())
}
}

// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Runtime;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: u32 = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
}
impl system::Trait for Runtime {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Call = ();
type Hash = H256;
type Hashing = ::sr_primitives::traits::BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
}
parameter_types! {
pub const TransactionBaseFee: u64 = 0;
pub const TransactionByteFee: u64 = 1;
}

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

parameter_types! {
pub const MinimumPeriod: u64 = 5;
}

pub struct ExtBuilder {
existential_deposit: u64,
transfer_fee: u64,
creation_fee: u64,
monied: bool,
vesting: bool,
}
impl Default for ExtBuilder {
fn default() -> Self {
Self {
existential_deposit: 0,
transfer_fee: 0,
creation_fee: 0,
monied: false,
vesting: false,
}
}
}
impl ExtBuilder {
pub fn existential_deposit(mut self, existential_deposit: u64) -> Self {
self.existential_deposit = existential_deposit;
self
}
#[allow(dead_code)]
pub fn transfer_fee(mut self, transfer_fee: u64) -> Self {
self.transfer_fee = transfer_fee;
self
}
pub fn creation_fee(mut self, creation_fee: u64) -> Self {
self.creation_fee = creation_fee;
self
}
pub fn monied(mut self, monied: bool) -> Self {
self.monied = monied;
if self.existential_deposit == 0 {
self.existential_deposit = 1;
}
self
}
pub fn vesting(mut self, vesting: bool) -> Self {
self.vesting = vesting;
self
}
pub fn set_associated_consts(&self) {
EXISTENTIAL_DEPOSIT.with(|v| *v.borrow_mut() = self.existential_deposit);
TRANSFER_FEE.with(|v| *v.borrow_mut() = self.transfer_fee);
CREATION_FEE.with(|v| *v.borrow_mut() = self.creation_fee);
}
pub fn build(self) -> runtime_io::TestExternalities {
self.set_associated_consts();
let mut t = system::GenesisConfig::default().build_storage::<Runtime>().unwrap();

t.into()
}
}

pub type System = system::Module<Runtime>;
pub type EthRelay = Module<Runtime>;

pub const CALL: &<Runtime as system::Trait>::Call = &();

/// create a transaction info struct from weight. Handy to avoid building the whole struct.
pub fn info_from_weight(w: Weight) -> DispatchInfo {
DispatchInfo {
weight: w,
..Default::default()
}
}
Loading