Skip to content

Commit

Permalink
Merge 5f7d572 into 6d3a5ee
Browse files Browse the repository at this point in the history
  • Loading branch information
k06a committed Apr 30, 2020
2 parents 6d3a5ee + 5f7d572 commit 57b6c92
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 24 deletions.
7 changes: 7 additions & 0 deletions ethprover/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 ethprover/Cargo.toml
Expand Up @@ -19,6 +19,7 @@ rlp = "0.4.2"
[dev-dependencies]
web3 = "0.8.0"
lazy_static = "1.4.0"
hex = "0.4.2"

[profile.release]
codegen-units = 1
Expand Down
40 changes: 36 additions & 4 deletions ethprover/index.js
Expand Up @@ -310,19 +310,38 @@ class EthProverContract extends Contract {
}
}

function receiptFromWeb3(result) {
function receiptFromWeb3(result, state_root) {
return new Receipt([
toBuffer((result.status ? 0x1 : 0x0) || result.root),
toBuffer(result.status ? 0x1 : 0x0),
toBuffer(result.cumulativeGasUsed),
toBuffer(result.logsBloom),
result.logs.map(Log.fromRpc)
result.logs.map(logFromRpc)
]);
}

function logFromRpc(result) {
return new Log([
toBuffer(result.address),
result.topics.map(toBuffer),
toBuffer(result.data)
]);
}

function logFromWeb3(result) {
return new Log([
toBuffer(result.address),
result.raw.topics.map(toBuffer),
toBuffer(result.raw.data)
]);
}

(async function () {
const web3 = new Web3(process.env.ETH_NODE_URL);
await web3.eth.getBlock('latest');

const emitter = new web3.eth.Contract(require('./build/contracts/Emitter.json').abi, process.env.ETH_CONTRACT_ADDRESS);
const events = await emitter.getPastEvents('allEvents');
console.log('events', events);

// Get proof
// https://github.com/zmitton/eth-proof/blob/master/getProof.js#L39
Expand All @@ -346,8 +365,21 @@ function receiptFromWeb3(result) {
txIndex: targetReceipt.transactionIndex,
};

console.log('proof:', proof);
console.log('event: ', event);
console.log('receipt: ', blockReceipts[proof.txIndex]);

console.log('let header_data = Vec::from_hex("' + proof.header.serialize().toString('hex') + '").unwrap();');
console.log('let receipt_data = Vec::from_hex("' + receiptFromWeb3(blockReceipts[proof.txIndex]).serialize().toString('hex') + '").unwrap();');
console.log('let log_entry = Vec::from_hex("' + logFromWeb3(event).serialize().toString('hex') + '").unwrap();');
console.log('let proof = vec![');
for (let rec of proof.receiptProof) {
for (let r of rec) {
console.log(' Vec::from_hex("' + r.toString('hex') + '").unwrap(),');
}
}
console.log('];');
console.log(proof.receiptProof);

const near = await nearlib.connect({
nodeUrl: process.env.NEAR_NODE_URL, // 'https://rpc.nearprotocol.com',
networkId: process.env.NEAR_NODE_NETWORK_ID,
Expand Down
Binary file modified ethprover/res/eth_prover.wasm
Binary file not shown.
19 changes: 17 additions & 2 deletions ethprover/scripts/run_localnet.sh
Expand Up @@ -9,11 +9,26 @@ source $DIR/../../scripts/start_nearcore.sh
set -o errexit

start_ganache_if_needed
start_nearcore_if_needed
#start_nearcore_if_needed
$DIR/../../ethrelay/scripts/run_ganache_to_localnet.sh &
ethrelay_pid=$!
sleep 10

# Executes cleanup function at script exit.
trap_add cleanup_ethrelay EXIT

cleanup_ethrelay() {
# Kill the ganache instance that we started (if we started one and if it's still running).
if [ -n "$ethrelay_pid" ] && ps -p $ethrelay_pid > /dev/null; then
kill $ethrelay_pid
fi
}

oz compile
ETH_CONTRACT_ADDRESS=$(oz deploy Emitter --kind regular --network development --silent --no-interactive)
EXH_TX=$(oz send-tx --to $ETH_CONTRACT_ADDRESS --method "emitEvent(uint256,uint256,uint256)" --args 1,2,3 --network development)
echo "ETH_CONTRACT_ADDRESS: $ETH_CONTRACT_ADDRESS"
ETH_TX=$(oz send-tx --to $ETH_CONTRACT_ADDRESS --method "emitEvent(uint256,uint256,uint256)" --args 1,2,3 --network development)
echo "ETH_TX: $ETH_TX"

$DIR/../build.sh

Expand Down
38 changes: 21 additions & 17 deletions ethprover/src/lib.rs
Expand Up @@ -7,6 +7,10 @@ use near_bindgen::{env, ext_contract, near_bindgen, PromiseOrValue};
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests;

type AccountId = String;
const GAS: u64 = 100_000_000_000_000;

Expand Down Expand Up @@ -94,23 +98,24 @@ impl EthProver {
#[serializer(borsh)]
expected_block_hash: H256,
) -> PromiseOrValue<bool> {
eth_bridge::block_hash_safe(
block_number,
&self.bridge_smart_contract,
0,
GAS,
).then(
self.bridge_smart_contract.setup(0, GAS).block_hash_safe(block_number).then(
env::current_account_id().setup(0, GAS).on_block_hash(expected_block_hash)
);

eth_bridge::block_hash_safe(block_number, &self.bridge_smart_contract, 0, GAS).then(
remote_self::on_block_hash(expected_block_hash, &env::current_account_id(), 0, GAS)
).into()
}

pub fn verify_log_entry(
&self,
log_index: usize,
log_index: u64,
log_entry_data: Vec<u8>,
receipt_index: u64,
receipt_data: Vec<u8>,
header_data: Vec<u8>,
proof: Vec<Vec<u8>>,
skip_bridge_call: bool
) -> bool {
let log_entry: LogEntry = rlp::decode(log_entry_data.as_slice()).unwrap();
let receipt: Receipt = rlp::decode(receipt_data.as_slice()).unwrap();
Expand All @@ -119,22 +124,19 @@ impl EthProver {
// Verify block header was in the bridge
// TODO: inter-contract call:
//self.bridge_smart_contract.block_hashes(header.number) == header.hash;
eth_bridge::block_hash_safe(
header.number,
&self.bridge_smart_contract,
0,
GAS,
).then(
remote_self::on_block_hash(header.hash.unwrap(), &env::current_account_id(), 0, GAS)
);
if !skip_bridge_call {
eth_bridge::block_hash_safe(header.number, &self.bridge_smart_contract, 0, GAS).then(
remote_self::on_block_hash(header.hash.unwrap(), &env::current_account_id(), 0, GAS)
);
}

// Verify log_entry included in receipt
assert_eq!(receipt.logs[log_index], log_entry);
assert_eq!(receipt.logs[log_index as usize], log_entry);

// Verify receipt included into header
Self::verify_trie_proof(
header.receipts_root,
rlp::encode(&log_index),
rlp::encode(&receipt_index),
proof,
0,
0,
Expand All @@ -158,6 +160,7 @@ impl EthProver {
/// Verification: https://github.com/slockit/in3/wiki/Ethereum-Verification-and-MerkleProof#receipt-proof
/// Article: https://medium.com/@ouvrard.pierre.alain/merkle-proof-verification-for-ethereum-patricia-tree-48f29658eec
/// Python impl: https://gist.github.com/paouvrard/7bb947bf5de0fa0dc69d0d254d82252a
/// JS impl: https://github.com/slockit/in3/blob/master/src/util/merkleProof.ts
///
fn verify_trie_proof(
expected_root: H256,
Expand All @@ -169,6 +172,7 @@ impl EthProver {
) -> bool {
let node = &proof[proof_index];
let dec = Rlp::new(&node.as_slice());
println!("{:}", dec);

if key_index == 0 { // trie root is always a hash
assert_eq!(near_keccak256(node), (expected_root.0).0);
Expand Down
106 changes: 106 additions & 0 deletions ethprover/src/tests.rs
@@ -0,0 +1,106 @@
use hex::FromHex;
use rlp::RlpStream;
use serde::{Deserialize, Deserializer};
use crate::{EthProver};

//#[macro_use]
//extern crate lazy_static;
use lazy_static::lazy_static;

#[derive(Debug)]
struct Hex(pub Vec<u8>);

impl<'de> Deserialize<'de> for Hex {
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
let mut s = <String as Deserialize>::deserialize(deserializer)?;
if s.starts_with("0x") {
s = s[2..].to_string();
}
if s.len() % 2 == 1 {
s.insert_str(0, "0");
}
Ok(Hex(Vec::from_hex(&s).map_err(|err| {
serde::de::Error::custom(err.to_string())
})?))
}
}

// TESTS

use near_bindgen::MockedBlockchain;
use near_bindgen::{testing_env, VMContext};

lazy_static! {
static ref WEB3RS: web3::Web3<web3::transports::Http> = {
let (eloop, transport) = web3::transports::Http::new(
"https://mainnet.infura.io/v3/b5f870422ee5454fb11937e947154cd2",
)
.unwrap();
eloop.into_remote();
web3::Web3::new(transport)
};
}

fn get_context(input: Vec<u8>, is_view: bool) -> VMContext {
VMContext {
current_account_id: "alice.near".to_string(),
signer_account_id: "bob.near".to_string(),
signer_account_pk: vec![0, 1, 2],
predecessor_account_id: "carol.near".to_string(),
input,
block_index: 0,
block_timestamp: 0,
account_balance: 0,
account_locked_balance: 0,
storage_usage: 0,
attached_deposit: 0,
prepaid_gas: 10u64.pow(18),
random_seed: vec![0, 1, 2],
is_view,
output_data_receivers: vec![],
}
}

#[test]
fn add_dags_merkle_roots() {
testing_env!(get_context(vec![], false));

let contract = EthProver::init("ethbridge".to_string());

let log_index = 0;
let receipt_index = 0;
let header_data = Vec::from_hex("f901f6a0008e55e1282b0c21411cb354e46704b87c34774bb8545ad7f08c15d23c8ad0aba01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0f174e800bac63e98447a7aa0d68dd983837ccf38d124450c8060e1d90da15066a088ce77ae7b5397b5d679148424f8d6c6e715feb4f5b206132f6092ad896bf23da0f11406c226b6d85d0d437a2c85592b59cb1841d17f0c2cdd6d70e413b549c2e2b9010000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000200000000000000000000000000000000000000000004000000000000000000000000020000000000000000040000000000000000000000000000000000000000000000000000000000000000000300483989680825bb0845e9edd2880a00000000000000000000000000000000000000000000000000000000000000000880000000000000000");
let receipt_data = Vec::from_hex("f901a601825bb0b9010000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000200000000000000000000000000000000000000000004000000000000000000000000020000000000000000040000000000000000000000000000000000000000000000000000000000000000000f89df89b940f5ea0a652e851678ebf77b69484bfcd31f9459bf842a000032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0a00000000000000000000000000000000000000000000000000000000000000001b84000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003");
let log_entry = Vec::from_hex("f89b940f5ea0a652e851678ebf77b69484bfcd31f9459bf842a000032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0a00000000000000000000000000000000000000000000000000000000000000001b84000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003");
let proof = vec![
Vec::from_hex("2080").unwrap(),
Vec::from_hex("f901a601825bb0b9010000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000200000000000000000000000000000000000000000004000000000000000000000000020000000000000000040000000000000000000000000000000000000000000000000000000000000000000f89df89b940f5ea0a652e851678ebf77b69484bfcd31f9459bf842a000032a912636b05d31af43f00b91359ddcfddebcffa7c15470a13ba1992e10f0a00000000000000000000000000000000000000000000000000000000000000001b84000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003").unwrap(),
];

let result = contract.verify_log_entry(
log_index,
log_entry.unwrap(),
receipt_index,
receipt_data.unwrap(),
header_data.unwrap(),
proof,
true
);

// log_index: u64,
// log_entry_data: Vec<u8>,
// receipt_index: u64,
// receipt_data: Vec<u8>,
// header_data: Vec<u8>,
// proof: Vec<Vec<u8>>,

// assert_eq!(dmr.dag_merkle_roots[0], contract.dag_merkle_root(0));
// assert_eq!(dmr.dag_merkle_roots[10], contract.dag_merkle_root(10));
// assert_eq!(dmr.dag_merkle_roots[511], contract.dag_merkle_root(511));

// let result = catch_unwind_silent(|| contract.dag_merkle_root(512));
// assert!(result.is_err());
}
3 changes: 3 additions & 0 deletions ethprover/test.sh
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

RUST_BACKTRACE=1 cargo test --jobs 8 --package eth-prover -- --nocapture
2 changes: 1 addition & 1 deletion ethtypes/src/lib.rs
Expand Up @@ -243,7 +243,7 @@ pub struct LogEntry {

#[derive(Debug, Clone, PartialEq, Eq, RlpEncodableDerive, RlpDecodableDerive)]
pub struct Receipt {
pub state_root: H256,
pub status: bool,
pub gas_used: U256,
pub log_bloom: Bloom,
pub logs: Vec<LogEntry>,
Expand Down

0 comments on commit 57b6c92

Please sign in to comment.