From 6a2e37708ec5a72cc0dc99b7634f0cc796ea9278 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:55:27 +0700 Subject: [PATCH 1/7] Add eth proof generation utilities --- eth2near/Cargo.lock | 62 ++++-- eth2near/Cargo.toml | 1 + eth2near/utilities/Cargo.toml | 16 ++ eth2near/utilities/src/eth_proof_generator.rs | 178 ++++++++++++++++++ eth2near/utilities/src/eth_rpc_client.rs | 88 +++++++++ eth2near/utilities/src/lib.rs | 5 + eth2near/utilities/src/primitives.rs | 10 + eth2near/utilities/src/serde.rs | 86 +++++++++ eth2near/utilities/src/types.rs | 60 ++++++ 9 files changed, 492 insertions(+), 14 deletions(-) create mode 100644 eth2near/utilities/Cargo.toml create mode 100644 eth2near/utilities/src/eth_proof_generator.rs create mode 100644 eth2near/utilities/src/eth_rpc_client.rs create mode 100644 eth2near/utilities/src/lib.rs create mode 100644 eth2near/utilities/src/primitives.rs create mode 100644 eth2near/utilities/src/serde.rs create mode 100644 eth2near/utilities/src/types.rs diff --git a/eth2near/Cargo.lock b/eth2near/Cargo.lock index 8f571524..18107996 100644 --- a/eth2near/Cargo.lock +++ b/eth2near/Cargo.lock @@ -677,9 +677,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cexpr" @@ -727,6 +727,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cita_trie" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0bc31eabef0259183d03c3846ad6818eaa8e542c31dae751c9d22ea030fb7d" +dependencies = [ + "hasher", + "parking_lot", + "rlp", +] + [[package]] name = "clang-sys" version = "1.7.0" @@ -1129,9 +1140,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "crypto-common", @@ -1932,6 +1943,15 @@ dependencies = [ "ahash", ] +[[package]] +name = "hasher" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbba678b6567f27ce22870d951f4208e1dc2fef64993bd4521b1d497ef8a3aa" +dependencies = [ + "tiny-keccak", +] + [[package]] name = "hashlink" version = "0.8.1" @@ -3371,9 +3391,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -3399,9 +3419,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -4173,7 +4193,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4512,7 +4532,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4536,7 +4556,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4545,7 +4565,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -5478,6 +5498,20 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utilities" +version = "0.1.0" +dependencies = [ + "cita_trie", + "hasher", + "hex 0.4.3", + "num-traits", + "reqwest", + "rlp", + "serde", + "serde_json", +] + [[package]] name = "uuid" version = "1.3.0" @@ -5953,9 +5987,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] diff --git a/eth2near/Cargo.toml b/eth2near/Cargo.toml index c67c93f7..df5b7d76 100644 --- a/eth2near/Cargo.toml +++ b/eth2near/Cargo.toml @@ -7,6 +7,7 @@ members = [ "eth_rpc_client", "finality-update-verify", "logger", + "utilities", ] [workspace.dependencies] diff --git a/eth2near/utilities/Cargo.toml b/eth2near/utilities/Cargo.toml new file mode 100644 index 00000000..5240860c --- /dev/null +++ b/eth2near/utilities/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "utilities" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +reqwest = { version = "0.11", features = ["blocking", "json"] } +serde_json = "1.0.74" +serde = { version = "1.0", features = ["derive"] } +hex = { version="0.4", features = ["serde"] } +num-traits = "0.2" +cita_trie = "5.0.1" +hasher = "0.1.4" +rlp = "0.5.2" diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs new file mode 100644 index 00000000..79a967ac --- /dev/null +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -0,0 +1,178 @@ +use crate::{ + eth_rpc_client::EthRPCClient, + primitives::*, + types::{BlockHeader, Log, TransactionReceipt}, +}; +use cita_trie::{MemoryDB, PatriciaTrie, Trie, TrieError}; +use hasher::HasherKeccak; +use rlp::RlpStream; +use std::error::Error; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Proof { + pub log_index: u64, + pub log_entry_data: Vec, + pub receipt_index: u64, + pub receipt_data: Vec, + pub header_data: Vec, + pub proof: Vec>, +} + +pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Result> { + let client = EthRPCClient::new(node_url); + + let tx_bytes: [u8; 32] = hex::decode(&tx_hash[2..]) + .expect("Invalid hex string") + .try_into() + .expect("Invalid hex string"); + + let receipt = client.get_transaction_receipt_by_hash(&FixedBytes(tx_bytes))?; + let block_header = client.get_block_by_number(receipt.block_number)?; + let block_receipts = client.get_block_receipts(receipt.block_number)?; + + let trie = build_receipt_trie(&block_receipts)?; + + let receipt_key = rlp::encode(&receipt.transaction_index); + let proof = trie.get_proof(&receipt_key)?; + + let mut log_data: Option> = None; + for (_, log) in receipt.logs.iter().enumerate() { + if log.log_index == log_index { + log_data = Some(encode_log(log)); + } + } + + Ok(Proof { + log_index, + log_entry_data: log_data.expect("Log not found"), + receipt_index: receipt.transaction_index, + receipt_data: encode_receipt(&receipt), + header_data: encode_header(&block_header), + proof, + }) +} + +fn build_receipt_trie(receipts: &[TransactionReceipt],) -> Result, TrieError> { + let memdb = Arc::new(MemoryDB::new(true)); + let hasher = Arc::new(HasherKeccak::new()); + let mut trie = PatriciaTrie::new(Arc::clone(&memdb), Arc::clone(&hasher)); + + for (_, receipt) in receipts.iter().enumerate() { + let receipt_key = rlp::encode(&receipt.transaction_index).to_vec(); + let receipt_data = encode_receipt(receipt); + + trie.insert(receipt_key, receipt_data)?; + } + + Ok(trie) +} + +fn encode_receipt(receipt: &TransactionReceipt) -> Vec { + let mut stream = RlpStream::new(); + + if receipt.transaction_type != 0 { + stream.append(&receipt.transaction_type); + } + + stream.begin_list(4); + stream + .append(&receipt.status) + .append(&receipt.cumulative_gas_used.0) + .append(&receipt.logs_bloom.0.to_vec()); + + stream.begin_list(receipt.logs.len()); + for (_, log) in receipt.logs.iter().enumerate() { + stream.begin_list(3); + stream.append(&log.address.0.to_vec()); + + stream.begin_list(log.topics.len()); + for (_, topic) in log.topics.iter().enumerate() { + stream.append(&topic.0.to_vec()); + } + + stream.append(&log.data.0); + } + + stream.out().to_vec() +} + +fn encode_log(log: &Log) -> Vec { + let mut stream = RlpStream::new(); + stream.begin_list(3); + + stream.append(&log.address.0.to_vec()); + + stream.begin_list(log.topics.len()); + for (_, topic) in log.topics.iter().enumerate() { + stream.append(&topic.0.to_vec()); + } + + stream.append(&log.data.0); + + stream.out().to_vec() +} + +fn encode_header(header: &BlockHeader) -> Vec { + let mut stream = RlpStream::new(); + stream.begin_unbounded_list(); + + stream + .append(&header.parent_hash.0.to_vec()) + .append(&header.sha3_uncles.0.to_vec()) + .append(&header.miner.0.to_vec()) + .append(&header.state_root.0.to_vec()) + .append(&header.transactions_root.0.to_vec()) + .append(&header.receipts_root.0.to_vec()) + .append(&header.logs_bloom.0.to_vec()) + .append(&header.difficulty) + .append(&header.number.0) + .append(&header.gas_limit.0) + .append(&header.gas_used.0) + .append(&header.timestamp.0) + .append(&header.extra_data.0.to_vec()) + .append(&header.mix_hash.0.to_vec()) + .append(&header.nonce.0.to_vec()); + + if header.base_fee_per_gas.is_some() { + stream.append(&header.base_fee_per_gas.unwrap()); + } + + if header.withdrawals_root.is_some() { + stream.append(&header.withdrawals_root.clone().unwrap().0.to_vec()); + } + + if header.blob_gas_used.is_some() { + stream.append(&header.blob_gas_used.unwrap()); + } + + if header.excess_blob_gas.is_some() { + stream.append(&header.excess_blob_gas.unwrap()); + } + + if header.parent_beacon_block_root.is_some() { + stream.append(&header.parent_beacon_block_root.clone().unwrap().0.to_vec()); + } + + stream.finalize_unbounded_list(); + + stream.out().to_vec() +} + +#[cfg(test)] +pub mod tests { + use super::*; + use hasher::Hasher; + + #[test] + fn generate_proof() { + const RPC_URL: &'static str = "https://eth.llamarpc.com"; + const TX_HASH: &'static str = "0x9298954a9db8026ca28bce4d71ffb7ba0aac70e91f0667ffb7398c67e60b84fa"; + let proof = get_proof_for_event(TX_HASH, 377, RPC_URL).unwrap(); + + let hasher = HasherKeccak::new(); + + println!("Header {:x?}", hasher.digest(&proof.header_data)); + println!("Proof {:x?}", &proof.proof); + } +} diff --git a/eth2near/utilities/src/eth_rpc_client.rs b/eth2near/utilities/src/eth_rpc_client.rs new file mode 100644 index 00000000..e9de3947 --- /dev/null +++ b/eth2near/utilities/src/eth_rpc_client.rs @@ -0,0 +1,88 @@ +use crate::{ + primitives::U256, + types::{BlockHeader, TransactionReceipt}, +}; +use reqwest::blocking::Client; +use serde::Deserialize; +use serde_json::{json, Value}; +use std::error::Error; + +pub struct EthRPCClient { + endpoint_url: String, + client: Client, +} + +impl EthRPCClient { + pub fn new(endpoint_url: &str) -> Self { + Self { + endpoint_url: endpoint_url.to_string(), + client: reqwest::blocking::Client::new(), + } + } + + pub fn get_transaction_receipt_by_hash(&self, tx_hash: &U256,) -> Result> { + let json_value = json!({ + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [tx_hash.0] + }); + + let res = self + .client + .post(&self.endpoint_url) + .json(&json_value) + .send()? + .text()?; + + let val: Value = serde_json::from_str(&res)?; + let receipt = TransactionReceipt::deserialize(&val["result"])?; + + Ok(receipt) + } + + pub fn get_block_by_number(&self, block_number: u64) -> Result> { + let json_value = json!({ + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [format!("0x{:x}", block_number), false] + }); + + let res = self + .client + .post(&self.endpoint_url) + .json(&json_value) + .send()? + .text()?; + + let val: Value = serde_json::from_str(&res)?; + let header = BlockHeader::deserialize(&val["result"])?; + + Ok(header) + } + + pub fn get_block_receipts( + &self, + block_number: u64, + ) -> Result, Box> { + let json_value = json!({ + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockReceipts", + "params": [format!("0x{:x}", block_number)] + }); + + let res = self + .client + .post(&self.endpoint_url) + .json(&json_value) + .send()? + .text()?; + + let val: Value = serde_json::from_str(&res)?; + let receipts = Vec::::deserialize(&val["result"])?; + + Ok(receipts) + } +} diff --git a/eth2near/utilities/src/lib.rs b/eth2near/utilities/src/lib.rs new file mode 100644 index 00000000..fd714c2f --- /dev/null +++ b/eth2near/utilities/src/lib.rs @@ -0,0 +1,5 @@ +pub mod eth_rpc_client; +pub mod eth_proof_generator; +mod primitives; +mod types; +mod serde; \ No newline at end of file diff --git a/eth2near/utilities/src/primitives.rs b/eth2near/utilities/src/primitives.rs new file mode 100644 index 00000000..15d56efa --- /dev/null +++ b/eth2near/utilities/src/primitives.rs @@ -0,0 +1,10 @@ +#[derive(Debug, Clone)] +pub struct FixedBytes(pub [u8; N]); +#[derive(Debug, Clone)] +pub struct Bytes(pub Vec); +#[derive(Debug, Clone)] +pub struct Byte(pub u8); + +pub type U256 = FixedBytes<32>; +pub type Address = FixedBytes<20>; +pub type Bloom = FixedBytes<256>; diff --git a/eth2near/utilities/src/serde.rs b/eth2near/utilities/src/serde.rs new file mode 100644 index 00000000..d27632bd --- /dev/null +++ b/eth2near/utilities/src/serde.rs @@ -0,0 +1,86 @@ +use num_traits::Num; +use serde::{de, Deserialize, Deserializer}; +use crate::primitives::{Byte, Bytes, FixedBytes}; + +pub fn hex_to_int_opt<'de, D, N>(deserializer: D) -> Result, D::Error> + where D: Deserializer<'de>, + N: Num, +{ + Ok(Some(hex_to_int(deserializer)?)) +} + +pub fn hex_to_int<'de, D, N>(deserializer: D) -> Result + where D: Deserializer<'de>, + N: Num, +{ + match String::deserialize(deserializer)? { + s if s.starts_with("0x") => { + N::from_str_radix(&s[2..], 16) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s))) + } + s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), + } +} + +impl<'de, const N: usize> Deserialize<'de> for FixedBytes { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de>, + { + match String::deserialize(deserializer)? { + s if s.starts_with("0x") => { + let s_normalized = normalize_hex_string(&s); + + let bytes: [u8; N] = hex::decode(&s_normalized) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))? + .try_into() + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + + Ok(FixedBytes::(bytes)) + } + s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), + } + } +} + +impl<'de> Deserialize<'de> for Bytes { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de>, + { + match String::deserialize(deserializer)? { + s if s.starts_with("0x") => { + let s_normalized = normalize_hex_string(&s); + + let vec: Vec = hex::decode(&s_normalized) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + + Ok(Bytes(vec)) + } + s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), + } + } +} + +impl<'de> Deserialize<'de> for Byte { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de>, + { + match String::deserialize(deserializer)? { + s if s.starts_with("0x") => { + let s_normalized = normalize_hex_string(&s); + + let bytes: Vec = hex::decode(&s_normalized) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + + Ok(Byte(bytes[0])) + } + s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), + } + } +} + +fn normalize_hex_string(s: &str) -> String { + match s.len() % 2 { + 0 => s[2..].to_owned(), + _ => "0".to_owned() + &s[2..], + } +} diff --git a/eth2near/utilities/src/types.rs b/eth2near/utilities/src/types.rs new file mode 100644 index 00000000..a40b4b67 --- /dev/null +++ b/eth2near/utilities/src/types.rs @@ -0,0 +1,60 @@ +use crate::{ + primitives::*, + serde::{hex_to_int, hex_to_int_opt}, +}; +use serde::Deserialize; + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BlockHeader { + pub parent_hash: U256, + pub sha3_uncles: U256, + pub miner: Address, + pub state_root: U256, + pub transactions_root: U256, + pub receipts_root: U256, + pub logs_bloom: Bloom, + #[serde(deserialize_with = "hex_to_int")] + pub difficulty: u128, + pub number: Bytes, + pub gas_limit: Bytes, + pub gas_used: Bytes, + pub timestamp: Bytes, + pub extra_data: Bytes, + pub mix_hash: U256, + pub nonce: Bytes, + #[serde(default, deserialize_with = "hex_to_int_opt")] + pub base_fee_per_gas: Option, + pub withdrawals_root: Option, + #[serde(default, deserialize_with = "hex_to_int_opt")] + pub blob_gas_used: Option, + #[serde(default, deserialize_with = "hex_to_int_opt")] + pub excess_blob_gas: Option, + pub parent_beacon_block_root: Option, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Log { + pub address: Address, + pub topics: Vec, + pub data: Bytes, + #[serde(deserialize_with = "hex_to_int")] + pub log_index: u64, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionReceipt { + #[serde(deserialize_with = "hex_to_int")] + pub block_number: u64, + #[serde(deserialize_with = "hex_to_int")] + pub transaction_index: u64, + #[serde(rename = "type", deserialize_with = "hex_to_int")] + pub transaction_type: u8, + pub cumulative_gas_used: Bytes, + pub logs_bloom: Bloom, + pub logs: Vec, + #[serde(deserialize_with = "hex_to_int")] + pub status: u8, +} From c70cc73eb4cd78f8dfdfb2f1be34a6807cc5c921 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Tue, 19 Mar 2024 19:45:04 +0700 Subject: [PATCH 2/7] Code review fixes --- eth2near/utilities/src/eth_proof_generator.rs | 80 ++++++++----------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs index 79a967ac..7df40ce4 100644 --- a/eth2near/utilities/src/eth_proof_generator.rs +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -22,10 +22,9 @@ pub struct Proof { pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Result> { let client = EthRPCClient::new(node_url); - let tx_bytes: [u8; 32] = hex::decode(&tx_hash[2..]) - .expect("Invalid hex string") + let tx_bytes: [u8; 32] = hex::decode(&tx_hash[2..])? .try_into() - .expect("Invalid hex string"); + .map_err(|_| Box::::from("Invalid hex string length"))?; let receipt = client.get_transaction_receipt_by_hash(&FixedBytes(tx_bytes))?; let block_header = client.get_block_by_number(receipt.block_number)?; @@ -37,7 +36,7 @@ pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Re let proof = trie.get_proof(&receipt_key)?; let mut log_data: Option> = None; - for (_, log) in receipt.logs.iter().enumerate() { + for log in &receipt.logs { if log.log_index == log_index { log_data = Some(encode_log(log)); } @@ -45,7 +44,7 @@ pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Re Ok(Proof { log_index, - log_entry_data: log_data.expect("Log not found"), + log_entry_data: log_data.ok_or("Log not found")?, receipt_index: receipt.transaction_index, receipt_data: encode_receipt(&receipt), header_data: encode_header(&block_header), @@ -56,9 +55,9 @@ pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Re fn build_receipt_trie(receipts: &[TransactionReceipt],) -> Result, TrieError> { let memdb = Arc::new(MemoryDB::new(true)); let hasher = Arc::new(HasherKeccak::new()); - let mut trie = PatriciaTrie::new(Arc::clone(&memdb), Arc::clone(&hasher)); + let mut trie = PatriciaTrie::new(memdb, hasher); - for (_, receipt) in receipts.iter().enumerate() { + for receipt in receipts { let receipt_key = rlp::encode(&receipt.transaction_index).to_vec(); let receipt_data = encode_receipt(receipt); @@ -79,16 +78,16 @@ fn encode_receipt(receipt: &TransactionReceipt) -> Vec { stream .append(&receipt.status) .append(&receipt.cumulative_gas_used.0) - .append(&receipt.logs_bloom.0.to_vec()); + .append(&receipt.logs_bloom.0.as_slice()); stream.begin_list(receipt.logs.len()); - for (_, log) in receipt.logs.iter().enumerate() { + for log in &receipt.logs { stream.begin_list(3); - stream.append(&log.address.0.to_vec()); + stream.append(&log.address.0.as_slice()); stream.begin_list(log.topics.len()); - for (_, topic) in log.topics.iter().enumerate() { - stream.append(&topic.0.to_vec()); + for topic in &log.topics { + stream.append(&topic.0.as_slice()); } stream.append(&log.data.0); @@ -101,11 +100,11 @@ fn encode_log(log: &Log) -> Vec { let mut stream = RlpStream::new(); stream.begin_list(3); - stream.append(&log.address.0.to_vec()); + stream.append(&log.address.0.as_slice()); stream.begin_list(log.topics.len()); - for (_, topic) in log.topics.iter().enumerate() { - stream.append(&topic.0.to_vec()); + for topic in &log.topics { + stream.append(&topic.0.as_slice()); } stream.append(&log.data.0); @@ -118,44 +117,33 @@ fn encode_header(header: &BlockHeader) -> Vec { stream.begin_unbounded_list(); stream - .append(&header.parent_hash.0.to_vec()) - .append(&header.sha3_uncles.0.to_vec()) - .append(&header.miner.0.to_vec()) - .append(&header.state_root.0.to_vec()) - .append(&header.transactions_root.0.to_vec()) - .append(&header.receipts_root.0.to_vec()) - .append(&header.logs_bloom.0.to_vec()) + .append(&header.parent_hash.0.as_slice()) + .append(&header.sha3_uncles.0.as_slice()) + .append(&header.miner.0.as_slice()) + .append(&header.state_root.0.as_slice()) + .append(&header.transactions_root.0.as_slice()) + .append(&header.receipts_root.0.as_slice()) + .append(&header.logs_bloom.0.as_slice()) .append(&header.difficulty) .append(&header.number.0) .append(&header.gas_limit.0) .append(&header.gas_used.0) .append(&header.timestamp.0) - .append(&header.extra_data.0.to_vec()) - .append(&header.mix_hash.0.to_vec()) - .append(&header.nonce.0.to_vec()); - - if header.base_fee_per_gas.is_some() { - stream.append(&header.base_fee_per_gas.unwrap()); - } - - if header.withdrawals_root.is_some() { - stream.append(&header.withdrawals_root.clone().unwrap().0.to_vec()); - } - - if header.blob_gas_used.is_some() { - stream.append(&header.blob_gas_used.unwrap()); - } - - if header.excess_blob_gas.is_some() { - stream.append(&header.excess_blob_gas.unwrap()); - } - - if header.parent_beacon_block_root.is_some() { - stream.append(&header.parent_beacon_block_root.clone().unwrap().0.to_vec()); - } + .append(&header.extra_data.0.as_slice()) + .append(&header.mix_hash.0.as_slice()) + .append(&header.nonce.0.as_slice()); + + header.base_fee_per_gas.map(|v| stream.append(&v)); + header.withdrawals_root + .as_ref() + .map(|v| stream.append(&v.0.as_slice())); + header.blob_gas_used.map(|v| stream.append(&v)); + header.excess_blob_gas.map(|v| stream.append(&v)); + header.parent_beacon_block_root + .as_ref() + .map(|v| stream.append(&v.0.as_slice())); stream.finalize_unbounded_list(); - stream.out().to_vec() } From 97bc7648291bc25f4e88625f4e589b51c3344209 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:00:00 +0700 Subject: [PATCH 3/7] Added tests and code improvements for custom deserializers --- eth2near/utilities/src/eth_proof_generator.rs | 10 +- eth2near/utilities/src/serde.rs | 140 ++++++++++++------ eth2near/utilities/src/types.rs | 7 +- 3 files changed, 107 insertions(+), 50 deletions(-) diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs index 7df40ce4..dec07e30 100644 --- a/eth2near/utilities/src/eth_proof_generator.rs +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -70,13 +70,13 @@ fn build_receipt_trie(receipts: &[TransactionReceipt],) -> Result Vec { let mut stream = RlpStream::new(); - if receipt.transaction_type != 0 { - stream.append(&receipt.transaction_type); + if receipt.transaction_type.0 != 0 { + stream.append(&receipt.transaction_type.0); } stream.begin_list(4); stream - .append(&receipt.status) + .append(&receipt.status.0) .append(&receipt.cumulative_gas_used.0) .append(&receipt.logs_bloom.0.as_slice()); @@ -158,9 +158,13 @@ pub mod tests { const TX_HASH: &'static str = "0x9298954a9db8026ca28bce4d71ffb7ba0aac70e91f0667ffb7398c67e60b84fa"; let proof = get_proof_for_event(TX_HASH, 377, RPC_URL).unwrap(); + const EXPECTED_HEADER: &'static str = "14ffc7718ede2f244f3abcdf513cade51d60a50bfd503a10079b5b540af5dee0"; + let hasher = HasherKeccak::new(); println!("Header {:x?}", hasher.digest(&proof.header_data)); println!("Proof {:x?}", &proof.proof); + + assert_eq!(hasher.digest(&proof.header_data), hex::decode(EXPECTED_HEADER).unwrap()); } } diff --git a/eth2near/utilities/src/serde.rs b/eth2near/utilities/src/serde.rs index d27632bd..4783d448 100644 --- a/eth2near/utilities/src/serde.rs +++ b/eth2near/utilities/src/serde.rs @@ -13,32 +13,25 @@ pub fn hex_to_int<'de, D, N>(deserializer: D) -> Result where D: Deserializer<'de>, N: Num, { - match String::deserialize(deserializer)? { - s if s.starts_with("0x") => { - N::from_str_radix(&s[2..], 16) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s))) - } - s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), - } + let s = extract_hex_string(deserializer)?; + + N::from_str_radix(&s, 16) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s))) } impl<'de, const N: usize> Deserialize<'de> for FixedBytes { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - match String::deserialize(deserializer)? { - s if s.starts_with("0x") => { - let s_normalized = normalize_hex_string(&s); - - let bytes: [u8; N] = hex::decode(&s_normalized) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))? - .try_into() - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; - - Ok(FixedBytes::(bytes)) - } - s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), - } + let s = extract_hex_string(deserializer)?; + let padded = format!("{:0>size$}", s, size = N * 2); + + let bytes: [u8; N] = hex::decode(&padded) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", padded)))? + .try_into() + .map_err(|_| de::Error::custom(format!("Hex string of invalid length: {}", padded)))?; + + Ok(FixedBytes::(bytes)) } } @@ -46,17 +39,12 @@ impl<'de> Deserialize<'de> for Bytes { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - match String::deserialize(deserializer)? { - s if s.starts_with("0x") => { - let s_normalized = normalize_hex_string(&s); + let s = extract_hex_string(deserializer)?; - let vec: Vec = hex::decode(&s_normalized) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + let vec: Vec = hex::decode(&s) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; - Ok(Bytes(vec)) - } - s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), - } + Ok(Bytes(vec)) } } @@ -64,23 +52,89 @@ impl<'de> Deserialize<'de> for Byte { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - match String::deserialize(deserializer)? { - s if s.starts_with("0x") => { - let s_normalized = normalize_hex_string(&s); - - let bytes: Vec = hex::decode(&s_normalized) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + Ok(Byte(hex_to_int(deserializer)?)) + } +} - Ok(Byte(bytes[0])) - } - s => Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))), - } +fn extract_hex_string<'de, D>(deserializer: D) -> Result + where D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + if let Some(stripped) = s.strip_prefix("0x") { + Ok(match stripped.len() % 2 { + 0 => stripped.to_owned(), + _ => "0".to_owned() + &stripped, + }) + } else { + Err(de::Error::custom(format!("Hex string must start with 0x: {}", s))) } } -fn normalize_hex_string(s: &str) -> String { - match s.len() % 2 { - 0 => s[2..].to_owned(), - _ => "0".to_owned() + &s[2..], +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn deserialize_fixed() { + let s = r#""0x1234""#; + let bytes: FixedBytes<2> = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, [0x12, 0x34]); + + let s = r#""0x23456""#; + let bytes: FixedBytes<3> = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, [0x02, 0x34, 0x56]); + + let s = r#""0x23456""#; + let bytes: FixedBytes<8> = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x56]); + } + + #[test] + fn deserialize_bytes() { + let s = r#""0x1234""#; + let bytes: Bytes = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, vec![0x12, 0x34]); + + let s = r#""0x21234""#; + let bytes: Bytes = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, vec![0x02, 0x12, 0x34]); + + let s = r#""0x0""#; + let bytes: Bytes = serde_json::from_str(s).unwrap(); + assert_eq!(bytes.0, vec![0x00]); + } + + #[test] + fn deserialize_byte() { + let s = r#""0x11""#; + let byte: Byte = serde_json::from_str(s).unwrap(); + assert_eq!(byte.0, 0x11); + + let s = r#""0x1""#; + let byte: Byte = serde_json::from_str(s).unwrap(); + assert_eq!(byte.0, 0x01); + + let s = r#""0x0""#; + let byte: Byte = serde_json::from_str(s).unwrap(); + assert_eq!(byte.0, 0x00); + } + + #[test] + fn deserialize_num() { + let s = r#""0x1234""#; + let deserializer = &mut serde_json::Deserializer::from_str(s); + let num: u16 = hex_to_int(deserializer).unwrap(); + assert_eq!(num, 0x1234); + + let s = r#""0x234""#; + let deserializer = &mut serde_json::Deserializer::from_str(s); + let num: u16 = hex_to_int(deserializer).unwrap(); + assert_eq!(num, 0x0234); + + let s = r#""0x234""#; + let deserializer = &mut serde_json::Deserializer::from_str(s); + let num: u32 = hex_to_int(deserializer).unwrap(); + assert_eq!(num, 0x00000234); } } + diff --git a/eth2near/utilities/src/types.rs b/eth2near/utilities/src/types.rs index a40b4b67..990d8aec 100644 --- a/eth2near/utilities/src/types.rs +++ b/eth2near/utilities/src/types.rs @@ -50,11 +50,10 @@ pub struct TransactionReceipt { pub block_number: u64, #[serde(deserialize_with = "hex_to_int")] pub transaction_index: u64, - #[serde(rename = "type", deserialize_with = "hex_to_int")] - pub transaction_type: u8, + #[serde(rename = "type")] + pub transaction_type: Byte, pub cumulative_gas_used: Bytes, pub logs_bloom: Bloom, pub logs: Vec, - #[serde(deserialize_with = "hex_to_int")] - pub status: u8, + pub status: Byte, } From da40e8ef5a43a364b3e189e9e094293b17da35a4 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Wed, 20 Mar 2024 20:23:27 +0700 Subject: [PATCH 4/7] Add more tests for proof generator --- eth2near/utilities/src/eth_proof_generator.rs | 97 ++++++++++++++++--- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs index dec07e30..fb2f2521 100644 --- a/eth2near/utilities/src/eth_proof_generator.rs +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -30,20 +30,23 @@ pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Re let block_header = client.get_block_by_number(receipt.block_number)?; let block_receipts = client.get_block_receipts(receipt.block_number)?; - let trie = build_receipt_trie(&block_receipts)?; + let mut trie = build_receipt_trie(&block_receipts)?; + trie.root()?; let receipt_key = rlp::encode(&receipt.transaction_index); let proof = trie.get_proof(&receipt_key)?; let mut log_data: Option> = None; - for log in &receipt.logs { + let mut log_index_in_receipt = 0; + for (i, log) in receipt.logs.iter().enumerate() { if log.log_index == log_index { log_data = Some(encode_log(log)); + log_index_in_receipt = i as u64; } } Ok(Proof { - log_index, + log_index: log_index_in_receipt, log_entry_data: log_data.ok_or("Log not found")?, receipt_index: receipt.transaction_index, receipt_data: encode_receipt(&receipt), @@ -151,20 +154,90 @@ fn encode_header(header: &BlockHeader) -> Vec { pub mod tests { use super::*; use hasher::Hasher; + const RPC_URL: &'static str = "https://eth.llamarpc.com"; #[test] - fn generate_proof() { - const RPC_URL: &'static str = "https://eth.llamarpc.com"; - const TX_HASH: &'static str = "0x9298954a9db8026ca28bce4d71ffb7ba0aac70e91f0667ffb7398c67e60b84fa"; - let proof = get_proof_for_event(TX_HASH, 377, RPC_URL).unwrap(); + fn generate_proof_pre_shapella() { + let tx_hash = "0xc4a6c5cde1d243b26b013f805f71f6de91536f66c993abfee746f373203b68cc"; + let proof = get_proof_for_event(tx_hash, 251, RPC_URL).unwrap(); + + let expected_log_index = 0; + let expected_receipt_index = 167; + let expected_header = "f61633d948772c98982af9df989c5cb9b9a8f5ed1a8411d57feb794013941de5"; + let expected_receipt = "02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000"; + let expected_log = "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800"; + let expected_proof = [ + "f90131a0967c44262dfeff60c2af9aba0bece5cb031e5072f2978bcf7fb18360abad1d3ca0ebdf9d8b1746ad2d585fa5c657348250fa92fa0586d6c89ab40c186115bebc17a0feffed8388da8e4f4936717c660a42f34b93cce4583d0944198c27e043779f56a06f970da48b1447fb56f88d27d9b0d4ea8cf30a6e83b507734fd96e3a42c17f24a0748ff314a3f88b77e11ef6c7f716f58ac498ae3b3264d6b2e0bdb6c91030df1fa05f6b3f1d31dc2f30322199b97af434c1c40891648515c0c483c2518f981a10b1a06dfe85601a2d49321453acf4edeab412bdb950fc65b2337b042aa7972d4925eea01eb88ec9349d5f61858f5a14b90456b78fb3bb0121d90df936d9765a05e78031a047c4fa8e5283c0dbeae2e4b9e6250008551b02d2edce1dd87bf9ace4d687604b8080808080808080", + "f851a08aa8e40f2823eb01a484cf576f2582137280289ca54eb3da743a36203ba963d0a023bad42a2491d2b478b82ff7e2d1b2beb569981a23c4376be21d1436c12d920a808080808080808080808080808080", + "f8918080808080808080a0918f290dbb902b8bf23c852bd82c945a37d4d5d015e9e9485616f3fa6e12aabca092b063303221d5c76f441ae788fa44597bd71cf03d0c944993ce8428c5a661fda0a7fc9b765f5a541c286acb44fe3ccffd32c1585da784b88d9bd800d933e69826a0ea9675894b751d28c53159f2582481df16925392fef0a81e1a2baa2d9e08190b8080808080", + "f90211a0abc02bfbddd2313e525124b626275a08e4d5437c837a114b11bd56a9421d04aaa0e71d7c39496e26fa67b5cc364a49e2e5701c8b5edbd5c58afc716e92ca9cc8f9a0cdec4707b811edbf0c81db09631c5a18dbfbda66d4793358257e5ec5c8993234a01356b944c23504dc1aa148f1a46d5e3c3f1b990a88b8ade4767d84aa7d4ca79fa06f883de36996ebd0b395f114e96a468c1aeaa287ca4f10e01648b0d60515a111a02ccaea122ce8542fd7ff9e02cec311f8d1b8ab7a0d949074e8f621765c58588ba01aeeca3be1c4e8e2581ed016d74442677645c0b423bb34e919ccf14009cbc92ba03bc2b368375a4de99317a01c548c6e564966cb317c3b4ba20c5cb0b181ac7c6ca04350da6c4a50dbb535c72bcd4632a5b94c15c709e2df6cd91269ce0faacd46c4a0743908223350d40bdb093c331dc0fbabe066f46440fdcf474f28acc48162c67da052aeea371b09dfe541719470a63a1fb12708c72eaa575bf723fea692a48b9d77a0aefd559fe69cb9163a4c3aa562e80beb3199afa446c449f048a38be05bc5fa00a05a373afc917a53eea199c158f7daea520dcc4d5b76c6cf87bb823b962f6cb506a0eb119ea50817395bd79be6e6fa748d64dc9ded81c63c6d61474210ab0003be7da0e4c36dd93a40a90993f083829469e0718aaf510e8eedf9ed5a7d8fdd4af92643a0aa1c5c12d65fdf25f74354991185dccecefb1e5813531ce8c9fdd2b2c7494a3c80", + "f902cf20b902cb02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000" + ]; + + let hasher = HasherKeccak::new(); + assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); + + assert_eq!(proof.log_index, expected_log_index); + assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); + assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); + assert_eq!(proof.proof.len(), expected_proof.len()); + assert!(proof.proof.into_iter().eq(expected_proof.iter().map(|x| hex::decode(x).unwrap()))); + } - const EXPECTED_HEADER: &'static str = "14ffc7718ede2f244f3abcdf513cade51d60a50bfd503a10079b5b540af5dee0"; + #[test] + fn generate_proof_post_shapella() { + let tx_hash = "0xd6ae351d6946f98c4b63589e2154db668e703e8c09fbd4e5c6807b5d356453c3"; + let proof = get_proof_for_event(tx_hash, 172, RPC_URL).unwrap(); + + let expected_log_index = 0; + let expected_receipt_index = 54; + let expected_header = "d02357b89842839d7c736f5b9899a6a2f469c7c1c35ec574c76b087006653456"; + let expected_receipt = "02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000"; + let expected_log = "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380"; + let expected_proof = [ + "f90111a09e0259b98fa182a95c48a8dacc2692badd7c29f71bc3e0d9d73dbf9d07e9611ba0ba6c9f95a62c8f2b828d4160e01162934297442c7cefea304908609de9fbd075a0993a2a24f0772d90700a7ad8f133ab1b7963defa359ad9826eb963f6168cfb60a0c31053f554e06e64bdddc105051dd2210d396514cd6edcc9aa55767e7652825ba05e2a24f235c03c6b6320a1d62e0e6d646349da863767ecf10126e6b4aacf274fa0e0c4a45d2ecd16a37af707062a5bec9f6657fcfe14ddb692215bdd6a26600617a0e53fe123d45561809c69c532b39d90e7eb0b6d7a74d09a259cbb41a29b12081480a044cf8e4f60cf97fb129824b1b37c04e82251da90b5e8fb9b3998cc3519e159798080808080808080", + "f90211a0d4de7e86f5e6eba4a08c89925937986e201e6f286b7123fb5700354df9167b7ba07b3389484104ebb32e6959db5ed3cddcdb2d1ce0c2b41ce5dc4ce2553e808f84a0e7344755384ea053c57c5546c1516a356c8cab5fe926a5a3eb3fe6721671001da0b9312cb00a3723a9a80598ab13d730430c686e9f2b14e669f41d87f36ede87b2a06069a92ac34df54f389475c9b92fea2b92bc73e92bffa14cb5c085469e884398a03f6262719ad775eef95b991f24aa63370892d4d0ef8dbaeba19f681e2cba2b5aa0071ab0cc93209db0be2343111f91ba35a180e0a453f23660aed462fce5daf551a0bfd7126fa52bb94255b9b7613a5a0b8bdb1f01443de5da83ce1839a0fe9d6e3ba02384631620ba5abce1a52e7347bff8c3727a56390bd7bc57c7d1386508cb1672a06ed35b57e37f3a08788866524b8a2d0089ec3fb308f34dea583324afd57e476aa05af302b741e36f6c630f423ff8d40be2fdeb4fb517eb62782ae6955c986ce21fa0b16f820757bb0bd971bdba9371540c09528d2818a6ab196ca6cbb3919d5097bda027b6b7c488fd95227a11f4c62d1d138341fd242f558de9bba659f99f543edd18a06f83a49cb804e10ee72d2cbd844b0fb6145eb5ca2f3bcd0c4d37fd357f2404d8a0b9f13ed67f0b534b781693633d36bde8f6127aa4cae31659475910a08a2956f4a0dcc805b1d26db82e140bf5de19cb39b95e7590a52e13cd83a65471cb95f456fd80", + "f902cf20b902cb02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000", + ]; let hasher = HasherKeccak::new(); + assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); + + assert_eq!(proof.log_index, expected_log_index); + assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); + assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); + assert_eq!(proof.proof.len(), expected_proof.len()); + assert!(proof.proof.into_iter().eq(expected_proof.iter().map(|x| hex::decode(x).unwrap()))); + } + + #[test] + fn generate_proof_post_dencun() { + let tx_hash = "0x42639810a1238a76ca947b848f5b88a854ac36471d1c4f6a15631393790f89af"; + let proof = get_proof_for_event(tx_hash, 360, RPC_URL).unwrap(); + + let expected_log_index = 0; + let expected_receipt_index = 212; + let expected_header = "0a02eb4a373b45367457c1e162c728cae7e68beaf0914b259b10ed033e95bdcc"; + let expected_receipt = "02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000"; + let expected_log = "f89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130"; + let expected_proof = [ + "f90131a0ea31efc223a1f91c0211cc8216c96d841a4c6aa9e706b1c80f4556473766c835a0a0d053a80857fe23752abc931238dfb519c600ec2c89740a8c0027f2452691dba07211c9aec8f2476236ff4ae404ea0a4d86a3b69aef1d7d68b4525b695d6937c3a066ff6c2bdfbec1a598afe01a4c8cb5342f09dc23e126af6161fc8b66a29258b4a02b1c9c12e45087ab52a964dac390a2b297b279839a14d73e6039ff4136efe176a0c5d3039faed9aefe6b036979ee41e741a6d1a1ffb280d245eefac5646ff0e5b4a0de9817fcc57347a50f1c3bf6bc0af45514a1e17b349d6b3a893acdfc45ad0a70a0bd3ac3599d9a58447c23c89c2ba279fa00a11c13c5e181012d50e012ef845f77a026ce9a58a9d343be345947cd441816397a516ad88e7211170a856d8ce164a14b8080808080808080", + "f851a0776031d2861aa23cb9bd323e49ac2b831658c311c35413899369ea8d558af735a08b9654ecaae433ee01704bb66b4877076a1f8e40b92ba31cadfb9dc06f858c15808080808080808080808080808080", + "f8f18080808080808080a07a49b3a8c05d073eb6d6d11c5c4fdc4505acb5a36c9cbc590929aad029ffc719a099264b31f39abaef84c246bbac4a72dc8bcf5d935c775a8d6c356234d0226061a042f9385fe9d42d8764f8e69b30cae57bcff98c77dc5431d7cc21d10905abcd1ca08a3023498e1067ee67f3caa5a290502efcb05549dd9b0814023e6e1448288467a06e40e4f27b3a0ed5de67c684369aa12610652e6399d002edb5443394f64db861a069631286f3eddfa8ef89eec490348240bc8690b874db62dde1690206dff758b2a0cebfcf4bb26fdcd28a9a42ec0da1e287a0cb41d9bb40ca4879d1cccaf23309998080", + "f90211a0c36f6abaee0178f644673e7d81132cdb139a9bd0bacf0d9719803242b54ef4d3a001a13437394f2ec24ec6a62baf5ef685dc617948314cf6cb7cb237dd759ba7afa0723df3efb2a08ca7156749e43c789cc92001953180a0e51935b3db6eb9c189b2a0d9929bc3195b7cb531249cfcccb0d7d56243a3af67be40d8a89a1ee287a2deeaa0641a7b318fd965ea4d1eb0686909dcd7898b491bb632eeb1ebad2bcc828f4017a0908899d902b0d7d459bba5e19767fc3373764fc6290de12d6588b4e90694aadfa0c6bdef3e0259812cbb979859c0e6a5e2bf980be306d5ed709ae373f0953449cca00993685867da25fb8ac53d636b9630a20297cdabf6e45bc003770dc335742d99a0c8b548c83f65e60afe207d499697f7b377be59c73183f0507862bc739be2348ba0cb4bc9bafef0aec55cd9ff83bc459d162e9f3701b784e2af2a768bc8b3dceeb9a066f522fef288d829e8e49738af851f7aef120dda1f6a1b934c24f96f52684ff2a0117847f1836bf5f354706fce391a183f4b69a55c6e64e820d69c4f5ee35e703da0548eb3f38b406cd35381c28b8a78028d48fe63db72f4a595893adc579b566295a0228c5276786aad75391a7b42d96df14b4494723fc1b096e07bc73e6bfaebc00ea01ae3c79fc12a94557c83e2668c89ec273b0fec08ad6b66e758cde410f121d340a06009085a2fc2a80ee20e8846c9320e28fd7ecf2c519fb8b5559fa30c750ebe8b80", + "f902ae20b902aa02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000" + ]; - println!("Header {:x?}", hasher.digest(&proof.header_data)); - println!("Proof {:x?}", &proof.proof); - - assert_eq!(hasher.digest(&proof.header_data), hex::decode(EXPECTED_HEADER).unwrap()); + let hasher = HasherKeccak::new(); + assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); + + assert_eq!(proof.log_index, expected_log_index); + assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); + assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); + assert_eq!(proof.proof.len(), expected_proof.len()); + assert!(proof.proof.into_iter().eq(expected_proof.iter().map(|x| hex::decode(x).unwrap()))); } } From bec1784bd37aef6abfc007519b37af37d3131d5e Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Thu, 21 Mar 2024 22:08:28 +0700 Subject: [PATCH 5/7] Use ethereum_types instead of custom types where possible --- eth2near/Cargo.lock | 2 +- eth2near/utilities/Cargo.toml | 2 +- eth2near/utilities/src/eth_proof_generator.rs | 95 +++++++++---------- eth2near/utilities/src/eth_rpc_client.rs | 12 +-- eth2near/utilities/src/primitives.rs | 23 +++-- eth2near/utilities/src/serde.rs | 86 +++-------------- eth2near/utilities/src/types.rs | 49 ++++------ 7 files changed, 102 insertions(+), 167 deletions(-) diff --git a/eth2near/Cargo.lock b/eth2near/Cargo.lock index 18107996..45322365 100644 --- a/eth2near/Cargo.lock +++ b/eth2near/Cargo.lock @@ -5503,9 +5503,9 @@ name = "utilities" version = "0.1.0" dependencies = [ "cita_trie", + "ethereum-types", "hasher", "hex 0.4.3", - "num-traits", "reqwest", "rlp", "serde", diff --git a/eth2near/utilities/Cargo.toml b/eth2near/utilities/Cargo.toml index 5240860c..c1a2c27a 100644 --- a/eth2near/utilities/Cargo.toml +++ b/eth2near/utilities/Cargo.toml @@ -10,7 +10,7 @@ reqwest = { version = "0.11", features = ["blocking", "json"] } serde_json = "1.0.74" serde = { version = "1.0", features = ["derive"] } hex = { version="0.4", features = ["serde"] } -num-traits = "0.2" cita_trie = "5.0.1" hasher = "0.1.4" rlp = "0.5.2" +ethereum-types = "0.14" diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs index fb2f2521..c51b85f3 100644 --- a/eth2near/utilities/src/eth_proof_generator.rs +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -1,32 +1,29 @@ use crate::{ eth_rpc_client::EthRPCClient, - primitives::*, types::{BlockHeader, Log, TransactionReceipt}, + primitives::U8 }; use cita_trie::{MemoryDB, PatriciaTrie, Trie, TrieError}; use hasher::HasherKeccak; use rlp::RlpStream; use std::error::Error; use std::sync::Arc; +use ethereum_types::{H256, U64}; #[derive(Debug)] pub struct Proof { - pub log_index: u64, + pub log_index: U64, pub log_entry_data: Vec, - pub receipt_index: u64, + pub receipt_index: U64, pub receipt_data: Vec, pub header_data: Vec, pub proof: Vec>, } -pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Result> { +pub fn get_proof_for_event(tx_hash: H256, log_index: u64, node_url: &str) -> Result> { let client = EthRPCClient::new(node_url); - let tx_bytes: [u8; 32] = hex::decode(&tx_hash[2..])? - .try_into() - .map_err(|_| Box::::from("Invalid hex string length"))?; - - let receipt = client.get_transaction_receipt_by_hash(&FixedBytes(tx_bytes))?; + let receipt = client.get_transaction_receipt_by_hash(&tx_hash)?; let block_header = client.get_block_by_number(receipt.block_number)?; let block_receipts = client.get_block_receipts(receipt.block_number)?; @@ -39,14 +36,14 @@ pub fn get_proof_for_event(tx_hash: &str, log_index: u64, node_url: &str,) -> Re let mut log_data: Option> = None; let mut log_index_in_receipt = 0; for (i, log) in receipt.logs.iter().enumerate() { - if log.log_index == log_index { + if log.log_index == log_index.into() { log_data = Some(encode_log(log)); - log_index_in_receipt = i as u64; + log_index_in_receipt = i; } } Ok(Proof { - log_index: log_index_in_receipt, + log_index: log_index_in_receipt.into(), log_entry_data: log_data.ok_or("Log not found")?, receipt_index: receipt.transaction_index, receipt_data: encode_receipt(&receipt), @@ -73,27 +70,27 @@ fn build_receipt_trie(receipts: &[TransactionReceipt],) -> Result Vec { let mut stream = RlpStream::new(); - if receipt.transaction_type.0 != 0 { - stream.append(&receipt.transaction_type.0); + if receipt.transaction_type != U8(0) { + stream.append(&receipt.transaction_type); } stream.begin_list(4); stream - .append(&receipt.status.0) - .append(&receipt.cumulative_gas_used.0) - .append(&receipt.logs_bloom.0.as_slice()); + .append(&receipt.status) + .append(&receipt.cumulative_gas_used) + .append(&receipt.logs_bloom); stream.begin_list(receipt.logs.len()); for log in &receipt.logs { stream.begin_list(3); - stream.append(&log.address.0.as_slice()); + stream.append(&log.address); stream.begin_list(log.topics.len()); for topic in &log.topics { - stream.append(&topic.0.as_slice()); + stream.append(topic); } - stream.append(&log.data.0); + stream.append(&log.data); } stream.out().to_vec() @@ -103,14 +100,14 @@ fn encode_log(log: &Log) -> Vec { let mut stream = RlpStream::new(); stream.begin_list(3); - stream.append(&log.address.0.as_slice()); + stream.append(&log.address); stream.begin_list(log.topics.len()); for topic in &log.topics { - stream.append(&topic.0.as_slice()); + stream.append(topic); } - stream.append(&log.data.0); + stream.append(&log.data); stream.out().to_vec() } @@ -120,31 +117,31 @@ fn encode_header(header: &BlockHeader) -> Vec { stream.begin_unbounded_list(); stream - .append(&header.parent_hash.0.as_slice()) - .append(&header.sha3_uncles.0.as_slice()) - .append(&header.miner.0.as_slice()) - .append(&header.state_root.0.as_slice()) - .append(&header.transactions_root.0.as_slice()) - .append(&header.receipts_root.0.as_slice()) - .append(&header.logs_bloom.0.as_slice()) + .append(&header.parent_hash) + .append(&header.sha3_uncles) + .append(&header.miner) + .append(&header.state_root) + .append(&header.transactions_root) + .append(&header.receipts_root) + .append(&header.logs_bloom) .append(&header.difficulty) - .append(&header.number.0) - .append(&header.gas_limit.0) - .append(&header.gas_used.0) - .append(&header.timestamp.0) - .append(&header.extra_data.0.as_slice()) - .append(&header.mix_hash.0.as_slice()) - .append(&header.nonce.0.as_slice()); + .append(&header.number) + .append(&header.gas_limit) + .append(&header.gas_used) + .append(&header.timestamp) + .append(&header.extra_data) + .append(&header.mix_hash) + .append(&header.nonce); header.base_fee_per_gas.map(|v| stream.append(&v)); header.withdrawals_root .as_ref() - .map(|v| stream.append(&v.0.as_slice())); + .map(|v| stream.append(v)); header.blob_gas_used.map(|v| stream.append(&v)); header.excess_blob_gas.map(|v| stream.append(&v)); header.parent_beacon_block_root .as_ref() - .map(|v| stream.append(&v.0.as_slice())); + .map(|v| stream.append(v)); stream.finalize_unbounded_list(); stream.out().to_vec() @@ -152,13 +149,15 @@ fn encode_header(header: &BlockHeader) -> Vec { #[cfg(test)] pub mod tests { + use std::str::FromStr; + use super::*; use hasher::Hasher; const RPC_URL: &'static str = "https://eth.llamarpc.com"; #[test] fn generate_proof_pre_shapella() { - let tx_hash = "0xc4a6c5cde1d243b26b013f805f71f6de91536f66c993abfee746f373203b68cc"; + let tx_hash = H256::from_str("0xc4a6c5cde1d243b26b013f805f71f6de91536f66c993abfee746f373203b68cc").unwrap(); let proof = get_proof_for_event(tx_hash, 251, RPC_URL).unwrap(); let expected_log_index = 0; @@ -177,8 +176,8 @@ pub mod tests { let hasher = HasherKeccak::new(); assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); - assert_eq!(proof.log_index, expected_log_index); - assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.log_index, expected_log_index.into()); + assert_eq!(proof.receipt_index, expected_receipt_index.into()); assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); assert_eq!(proof.proof.len(), expected_proof.len()); @@ -187,7 +186,7 @@ pub mod tests { #[test] fn generate_proof_post_shapella() { - let tx_hash = "0xd6ae351d6946f98c4b63589e2154db668e703e8c09fbd4e5c6807b5d356453c3"; + let tx_hash = H256::from_str("0xd6ae351d6946f98c4b63589e2154db668e703e8c09fbd4e5c6807b5d356453c3").unwrap(); let proof = get_proof_for_event(tx_hash, 172, RPC_URL).unwrap(); let expected_log_index = 0; @@ -204,8 +203,8 @@ pub mod tests { let hasher = HasherKeccak::new(); assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); - assert_eq!(proof.log_index, expected_log_index); - assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.log_index, expected_log_index.into()); + assert_eq!(proof.receipt_index, expected_receipt_index.into()); assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); assert_eq!(proof.proof.len(), expected_proof.len()); @@ -214,7 +213,7 @@ pub mod tests { #[test] fn generate_proof_post_dencun() { - let tx_hash = "0x42639810a1238a76ca947b848f5b88a854ac36471d1c4f6a15631393790f89af"; + let tx_hash = H256::from_str("0x42639810a1238a76ca947b848f5b88a854ac36471d1c4f6a15631393790f89af").unwrap(); let proof = get_proof_for_event(tx_hash, 360, RPC_URL).unwrap(); let expected_log_index = 0; @@ -233,8 +232,8 @@ pub mod tests { let hasher = HasherKeccak::new(); assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); - assert_eq!(proof.log_index, expected_log_index); - assert_eq!(proof.receipt_index, expected_receipt_index); + assert_eq!(proof.log_index, expected_log_index.into()); + assert_eq!(proof.receipt_index, expected_receipt_index.into()); assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); assert_eq!(proof.proof.len(), expected_proof.len()); diff --git a/eth2near/utilities/src/eth_rpc_client.rs b/eth2near/utilities/src/eth_rpc_client.rs index e9de3947..5a291822 100644 --- a/eth2near/utilities/src/eth_rpc_client.rs +++ b/eth2near/utilities/src/eth_rpc_client.rs @@ -1,11 +1,9 @@ -use crate::{ - primitives::U256, - types::{BlockHeader, TransactionReceipt}, -}; +use crate::types::{BlockHeader, TransactionReceipt}; use reqwest::blocking::Client; use serde::Deserialize; use serde_json::{json, Value}; use std::error::Error; +use ethereum_types::{H256, U64}; pub struct EthRPCClient { endpoint_url: String, @@ -20,7 +18,7 @@ impl EthRPCClient { } } - pub fn get_transaction_receipt_by_hash(&self, tx_hash: &U256,) -> Result> { + pub fn get_transaction_receipt_by_hash(&self, tx_hash: &H256) -> Result> { let json_value = json!({ "id": 1, "jsonrpc": "2.0", @@ -41,7 +39,7 @@ impl EthRPCClient { Ok(receipt) } - pub fn get_block_by_number(&self, block_number: u64) -> Result> { + pub fn get_block_by_number(&self, block_number: U64) -> Result> { let json_value = json!({ "id": 1, "jsonrpc": "2.0", @@ -64,7 +62,7 @@ impl EthRPCClient { pub fn get_block_receipts( &self, - block_number: u64, + block_number: U64, ) -> Result, Box> { let json_value = json!({ "id": 1, diff --git a/eth2near/utilities/src/primitives.rs b/eth2near/utilities/src/primitives.rs index 15d56efa..2955088b 100644 --- a/eth2near/utilities/src/primitives.rs +++ b/eth2near/utilities/src/primitives.rs @@ -1,10 +1,19 @@ -#[derive(Debug, Clone)] -pub struct FixedBytes(pub [u8; N]); +use rlp::{Encodable, RlpStream}; + #[derive(Debug, Clone)] pub struct Bytes(pub Vec); -#[derive(Debug, Clone)] -pub struct Byte(pub u8); -pub type U256 = FixedBytes<32>; -pub type Address = FixedBytes<20>; -pub type Bloom = FixedBytes<256>; +#[derive(Debug, Clone, PartialEq)] +pub struct U8(pub u8); + +impl Encodable for U8 { + fn rlp_append(&self, s: &mut RlpStream) { + self.0.rlp_append(s); + } +} + +impl Encodable for Bytes { + fn rlp_append(&self, s: &mut RlpStream) { + self.0.rlp_append(s); + } +} diff --git a/eth2near/utilities/src/serde.rs b/eth2near/utilities/src/serde.rs index 4783d448..391e0aac 100644 --- a/eth2near/utilities/src/serde.rs +++ b/eth2near/utilities/src/serde.rs @@ -1,39 +1,5 @@ -use num_traits::Num; use serde::{de, Deserialize, Deserializer}; -use crate::primitives::{Byte, Bytes, FixedBytes}; - -pub fn hex_to_int_opt<'de, D, N>(deserializer: D) -> Result, D::Error> - where D: Deserializer<'de>, - N: Num, -{ - Ok(Some(hex_to_int(deserializer)?)) -} - -pub fn hex_to_int<'de, D, N>(deserializer: D) -> Result - where D: Deserializer<'de>, - N: Num, -{ - let s = extract_hex_string(deserializer)?; - - N::from_str_radix(&s, 16) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s))) -} - -impl<'de, const N: usize> Deserialize<'de> for FixedBytes { - fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de>, - { - let s = extract_hex_string(deserializer)?; - let padded = format!("{:0>size$}", s, size = N * 2); - - let bytes: [u8; N] = hex::decode(&padded) - .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", padded)))? - .try_into() - .map_err(|_| de::Error::custom(format!("Hex string of invalid length: {}", padded)))?; - - Ok(FixedBytes::(bytes)) - } -} +use crate::primitives::{Bytes, U8}; impl<'de> Deserialize<'de> for Bytes { fn deserialize(deserializer: D) -> Result @@ -48,11 +14,16 @@ impl<'de> Deserialize<'de> for Bytes { } } -impl<'de> Deserialize<'de> for Byte { +impl<'de> Deserialize<'de> for U8 { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - Ok(Byte(hex_to_int(deserializer)?)) + let s = extract_hex_string(deserializer)?; + + let byte = u8::from_str_radix(&s, 16) + .map_err(|_| de::Error::custom(format!("Invalid hex string: {}", s)))?; + + Ok(Self(byte)) } } @@ -74,21 +45,6 @@ fn extract_hex_string<'de, D>(deserializer: D) -> Result mod test { use super::*; - #[test] - fn deserialize_fixed() { - let s = r#""0x1234""#; - let bytes: FixedBytes<2> = serde_json::from_str(s).unwrap(); - assert_eq!(bytes.0, [0x12, 0x34]); - - let s = r#""0x23456""#; - let bytes: FixedBytes<3> = serde_json::from_str(s).unwrap(); - assert_eq!(bytes.0, [0x02, 0x34, 0x56]); - - let s = r#""0x23456""#; - let bytes: FixedBytes<8> = serde_json::from_str(s).unwrap(); - assert_eq!(bytes.0, [0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x34, 0x56]); - } - #[test] fn deserialize_bytes() { let s = r#""0x1234""#; @@ -105,36 +61,18 @@ mod test { } #[test] - fn deserialize_byte() { + fn deserialize_u8() { let s = r#""0x11""#; - let byte: Byte = serde_json::from_str(s).unwrap(); + let byte: U8 = serde_json::from_str(s).unwrap(); assert_eq!(byte.0, 0x11); let s = r#""0x1""#; - let byte: Byte = serde_json::from_str(s).unwrap(); + let byte: U8 = serde_json::from_str(s).unwrap(); assert_eq!(byte.0, 0x01); let s = r#""0x0""#; - let byte: Byte = serde_json::from_str(s).unwrap(); + let byte: U8 = serde_json::from_str(s).unwrap(); assert_eq!(byte.0, 0x00); } - - #[test] - fn deserialize_num() { - let s = r#""0x1234""#; - let deserializer = &mut serde_json::Deserializer::from_str(s); - let num: u16 = hex_to_int(deserializer).unwrap(); - assert_eq!(num, 0x1234); - - let s = r#""0x234""#; - let deserializer = &mut serde_json::Deserializer::from_str(s); - let num: u16 = hex_to_int(deserializer).unwrap(); - assert_eq!(num, 0x0234); - - let s = r#""0x234""#; - let deserializer = &mut serde_json::Deserializer::from_str(s); - let num: u32 = hex_to_int(deserializer).unwrap(); - assert_eq!(num, 0x00000234); - } } diff --git a/eth2near/utilities/src/types.rs b/eth2near/utilities/src/types.rs index 990d8aec..8dd52bf8 100644 --- a/eth2near/utilities/src/types.rs +++ b/eth2near/utilities/src/types.rs @@ -1,59 +1,50 @@ -use crate::{ - primitives::*, - serde::{hex_to_int, hex_to_int_opt}, -}; +use crate::primitives::{Bytes, U8}; +use ethereum_types::{H256, Address, Bloom, U64, U128}; use serde::Deserialize; #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockHeader { - pub parent_hash: U256, - pub sha3_uncles: U256, + pub parent_hash: H256, + pub sha3_uncles: H256, pub miner: Address, - pub state_root: U256, - pub transactions_root: U256, - pub receipts_root: U256, + pub state_root: H256, + pub transactions_root: H256, + pub receipts_root: H256, pub logs_bloom: Bloom, - #[serde(deserialize_with = "hex_to_int")] - pub difficulty: u128, + pub difficulty: U128, pub number: Bytes, pub gas_limit: Bytes, pub gas_used: Bytes, pub timestamp: Bytes, pub extra_data: Bytes, - pub mix_hash: U256, + pub mix_hash: H256, pub nonce: Bytes, - #[serde(default, deserialize_with = "hex_to_int_opt")] - pub base_fee_per_gas: Option, - pub withdrawals_root: Option, - #[serde(default, deserialize_with = "hex_to_int_opt")] - pub blob_gas_used: Option, - #[serde(default, deserialize_with = "hex_to_int_opt")] - pub excess_blob_gas: Option, - pub parent_beacon_block_root: Option, + pub base_fee_per_gas: Option, + pub withdrawals_root: Option, + pub blob_gas_used: Option, + pub excess_blob_gas: Option, + pub parent_beacon_block_root: Option, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Log { pub address: Address, - pub topics: Vec, + pub topics: Vec, pub data: Bytes, - #[serde(deserialize_with = "hex_to_int")] - pub log_index: u64, + pub log_index: U64, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionReceipt { - #[serde(deserialize_with = "hex_to_int")] - pub block_number: u64, - #[serde(deserialize_with = "hex_to_int")] - pub transaction_index: u64, + pub block_number: U64, + pub transaction_index: U64, #[serde(rename = "type")] - pub transaction_type: Byte, + pub transaction_type: U8, pub cumulative_gas_used: Bytes, pub logs_bloom: Bloom, pub logs: Vec, - pub status: Byte, + pub status: U8, } From 04ef873a7697a0c961e698fad51bc6fa3d484354 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Thu, 21 Mar 2024 22:13:32 +0700 Subject: [PATCH 6/7] Remove unused feature --- eth2near/utilities/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth2near/utilities/Cargo.toml b/eth2near/utilities/Cargo.toml index c1a2c27a..287baf69 100644 --- a/eth2near/utilities/Cargo.toml +++ b/eth2near/utilities/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" reqwest = { version = "0.11", features = ["blocking", "json"] } serde_json = "1.0.74" serde = { version = "1.0", features = ["derive"] } -hex = { version="0.4", features = ["serde"] } +hex = { version="0.4" } cita_trie = "5.0.1" hasher = "0.1.4" rlp = "0.5.2" From 9faa39c5f446230ca4792d21cd659989d43466c8 Mon Sep 17 00:00:00 2001 From: kiseln <3428059+kiseln@users.noreply.github.com> Date: Wed, 27 Mar 2024 19:06:22 +0700 Subject: [PATCH 7/7] Split test data into json files --- eth2near/utilities/src/eth_proof_generator.rs | 102 ++++++++---------- .../src/test_data/post_dencun_proof.json | 14 +++ .../src/test_data/post_shapella_proof.json | 12 +++ .../src/test_data/pre_shapella_proof.json | 14 +++ 4 files changed, 83 insertions(+), 59 deletions(-) create mode 100644 eth2near/utilities/src/test_data/post_dencun_proof.json create mode 100644 eth2near/utilities/src/test_data/post_shapella_proof.json create mode 100644 eth2near/utilities/src/test_data/pre_shapella_proof.json diff --git a/eth2near/utilities/src/eth_proof_generator.rs b/eth2near/utilities/src/eth_proof_generator.rs index c51b85f3..ba998bc4 100644 --- a/eth2near/utilities/src/eth_proof_generator.rs +++ b/eth2near/utilities/src/eth_proof_generator.rs @@ -149,85 +149,69 @@ fn encode_header(header: &BlockHeader) -> Vec { #[cfg(test)] pub mod tests { - use std::str::FromStr; - use super::*; + use std::{fs, str::FromStr}; use hasher::Hasher; - const RPC_URL: &'static str = "https://eth.llamarpc.com"; + use serde_json::Value; + use std::path::PathBuf; + + const RPC_URL: &str = "https://eth.llamarpc.com"; + + /* + * Test data format: + * log_index - index of the log within transaction receipt (can be obtained from ETH RPC) + * receipt_index - index of the transaction receipt within the block (can be obtained from ETH RPC) + * block_hash - hash of the block containing the transaction + * receipt - RLP encoded transaction receipt (can be generated using other libraries, like eth-object.js) + * log - RLP encoded log entry (can be generated using other libraries, like eth-object.js) + * proof - merkle proof that receipt is part of the block receipt trie. To get the proof, first create a Merkle-Patricia tree including + * all RLP encoded transaction receipts of the block. The root of the tree must be the same as the receiptsRoot field of the block header. + * Then calculate merkle proof. One can use merkle-patricia-tree.js to build and generate the proof for the tree. + */ #[test] fn generate_proof_pre_shapella() { let tx_hash = H256::from_str("0xc4a6c5cde1d243b26b013f805f71f6de91536f66c993abfee746f373203b68cc").unwrap(); let proof = get_proof_for_event(tx_hash, 251, RPC_URL).unwrap(); - - let expected_log_index = 0; - let expected_receipt_index = 167; - let expected_header = "f61633d948772c98982af9df989c5cb9b9a8f5ed1a8411d57feb794013941de5"; - let expected_receipt = "02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000"; - let expected_log = "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800"; - let expected_proof = [ - "f90131a0967c44262dfeff60c2af9aba0bece5cb031e5072f2978bcf7fb18360abad1d3ca0ebdf9d8b1746ad2d585fa5c657348250fa92fa0586d6c89ab40c186115bebc17a0feffed8388da8e4f4936717c660a42f34b93cce4583d0944198c27e043779f56a06f970da48b1447fb56f88d27d9b0d4ea8cf30a6e83b507734fd96e3a42c17f24a0748ff314a3f88b77e11ef6c7f716f58ac498ae3b3264d6b2e0bdb6c91030df1fa05f6b3f1d31dc2f30322199b97af434c1c40891648515c0c483c2518f981a10b1a06dfe85601a2d49321453acf4edeab412bdb950fc65b2337b042aa7972d4925eea01eb88ec9349d5f61858f5a14b90456b78fb3bb0121d90df936d9765a05e78031a047c4fa8e5283c0dbeae2e4b9e6250008551b02d2edce1dd87bf9ace4d687604b8080808080808080", - "f851a08aa8e40f2823eb01a484cf576f2582137280289ca54eb3da743a36203ba963d0a023bad42a2491d2b478b82ff7e2d1b2beb569981a23c4376be21d1436c12d920a808080808080808080808080808080", - "f8918080808080808080a0918f290dbb902b8bf23c852bd82c945a37d4d5d015e9e9485616f3fa6e12aabca092b063303221d5c76f441ae788fa44597bd71cf03d0c944993ce8428c5a661fda0a7fc9b765f5a541c286acb44fe3ccffd32c1585da784b88d9bd800d933e69826a0ea9675894b751d28c53159f2582481df16925392fef0a81e1a2baa2d9e08190b8080808080", - "f90211a0abc02bfbddd2313e525124b626275a08e4d5437c837a114b11bd56a9421d04aaa0e71d7c39496e26fa67b5cc364a49e2e5701c8b5edbd5c58afc716e92ca9cc8f9a0cdec4707b811edbf0c81db09631c5a18dbfbda66d4793358257e5ec5c8993234a01356b944c23504dc1aa148f1a46d5e3c3f1b990a88b8ade4767d84aa7d4ca79fa06f883de36996ebd0b395f114e96a468c1aeaa287ca4f10e01648b0d60515a111a02ccaea122ce8542fd7ff9e02cec311f8d1b8ab7a0d949074e8f621765c58588ba01aeeca3be1c4e8e2581ed016d74442677645c0b423bb34e919ccf14009cbc92ba03bc2b368375a4de99317a01c548c6e564966cb317c3b4ba20c5cb0b181ac7c6ca04350da6c4a50dbb535c72bcd4632a5b94c15c709e2df6cd91269ce0faacd46c4a0743908223350d40bdb093c331dc0fbabe066f46440fdcf474f28acc48162c67da052aeea371b09dfe541719470a63a1fb12708c72eaa575bf723fea692a48b9d77a0aefd559fe69cb9163a4c3aa562e80beb3199afa446c449f048a38be05bc5fa00a05a373afc917a53eea199c158f7daea520dcc4d5b76c6cf87bb823b962f6cb506a0eb119ea50817395bd79be6e6fa748d64dc9ded81c63c6d61474210ab0003be7da0e4c36dd93a40a90993f083829469e0718aaf510e8eedf9ed5a7d8fdd4af92643a0aa1c5c12d65fdf25f74354991185dccecefb1e5813531ce8c9fdd2b2c7494a3c80", - "f902cf20b902cb02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000" - ]; - - let hasher = HasherKeccak::new(); - assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); - - assert_eq!(proof.log_index, expected_log_index.into()); - assert_eq!(proof.receipt_index, expected_receipt_index.into()); - assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); - assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); - assert_eq!(proof.proof.len(), expected_proof.len()); - assert!(proof.proof.into_iter().eq(expected_proof.iter().map(|x| hex::decode(x).unwrap()))); + verify_proof(proof, "pre_shapella_proof.json"); } #[test] fn generate_proof_post_shapella() { let tx_hash = H256::from_str("0xd6ae351d6946f98c4b63589e2154db668e703e8c09fbd4e5c6807b5d356453c3").unwrap(); let proof = get_proof_for_event(tx_hash, 172, RPC_URL).unwrap(); - - let expected_log_index = 0; - let expected_receipt_index = 54; - let expected_header = "d02357b89842839d7c736f5b9899a6a2f469c7c1c35ec574c76b087006653456"; - let expected_receipt = "02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000"; - let expected_log = "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380"; - let expected_proof = [ - "f90111a09e0259b98fa182a95c48a8dacc2692badd7c29f71bc3e0d9d73dbf9d07e9611ba0ba6c9f95a62c8f2b828d4160e01162934297442c7cefea304908609de9fbd075a0993a2a24f0772d90700a7ad8f133ab1b7963defa359ad9826eb963f6168cfb60a0c31053f554e06e64bdddc105051dd2210d396514cd6edcc9aa55767e7652825ba05e2a24f235c03c6b6320a1d62e0e6d646349da863767ecf10126e6b4aacf274fa0e0c4a45d2ecd16a37af707062a5bec9f6657fcfe14ddb692215bdd6a26600617a0e53fe123d45561809c69c532b39d90e7eb0b6d7a74d09a259cbb41a29b12081480a044cf8e4f60cf97fb129824b1b37c04e82251da90b5e8fb9b3998cc3519e159798080808080808080", - "f90211a0d4de7e86f5e6eba4a08c89925937986e201e6f286b7123fb5700354df9167b7ba07b3389484104ebb32e6959db5ed3cddcdb2d1ce0c2b41ce5dc4ce2553e808f84a0e7344755384ea053c57c5546c1516a356c8cab5fe926a5a3eb3fe6721671001da0b9312cb00a3723a9a80598ab13d730430c686e9f2b14e669f41d87f36ede87b2a06069a92ac34df54f389475c9b92fea2b92bc73e92bffa14cb5c085469e884398a03f6262719ad775eef95b991f24aa63370892d4d0ef8dbaeba19f681e2cba2b5aa0071ab0cc93209db0be2343111f91ba35a180e0a453f23660aed462fce5daf551a0bfd7126fa52bb94255b9b7613a5a0b8bdb1f01443de5da83ce1839a0fe9d6e3ba02384631620ba5abce1a52e7347bff8c3727a56390bd7bc57c7d1386508cb1672a06ed35b57e37f3a08788866524b8a2d0089ec3fb308f34dea583324afd57e476aa05af302b741e36f6c630f423ff8d40be2fdeb4fb517eb62782ae6955c986ce21fa0b16f820757bb0bd971bdba9371540c09528d2818a6ab196ca6cbb3919d5097bda027b6b7c488fd95227a11f4c62d1d138341fd242f558de9bba659f99f543edd18a06f83a49cb804e10ee72d2cbd844b0fb6145eb5ca2f3bcd0c4d37fd357f2404d8a0b9f13ed67f0b534b781693633d36bde8f6127aa4cae31659475910a08a2956f4a0dcc805b1d26db82e140bf5de19cb39b95e7590a52e13cd83a65471cb95f456fd80", - "f902cf20b902cb02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000", - ]; - - let hasher = HasherKeccak::new(); - assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); - - assert_eq!(proof.log_index, expected_log_index.into()); - assert_eq!(proof.receipt_index, expected_receipt_index.into()); - assert_eq!(proof.receipt_data, hex::decode(expected_receipt).unwrap()); - assert_eq!(proof.log_entry_data, hex::decode(expected_log).unwrap()); - assert_eq!(proof.proof.len(), expected_proof.len()); - assert!(proof.proof.into_iter().eq(expected_proof.iter().map(|x| hex::decode(x).unwrap()))); + verify_proof(proof, "post_shapella_proof.json"); } #[test] fn generate_proof_post_dencun() { let tx_hash = H256::from_str("0x42639810a1238a76ca947b848f5b88a854ac36471d1c4f6a15631393790f89af").unwrap(); let proof = get_proof_for_event(tx_hash, 360, RPC_URL).unwrap(); + verify_proof(proof, "post_dencun_proof.json"); + } + + fn read_proof_data(file_name: &str) -> (u64, u64, String, String, String, Vec) { + let mut data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + data_dir.push("src/test_data"); + data_dir.push(file_name); + + let data = fs::read_to_string(data_dir).unwrap(); + let obj: Value = serde_json::from_str(&data).unwrap(); + + let expected_log_index = obj["log_index"].as_u64().unwrap(); + let expected_receipt_index = obj["receipt_index"].as_u64().unwrap(); + let expected_header = obj["block_hash"].as_str().unwrap().into(); + let expected_receipt = obj["receipt"].as_str().unwrap().into(); + let expected_log = obj["log"].as_str().unwrap().into(); + let expected_proof = obj["proof"].as_array().unwrap() + .iter().map(|x| x.as_str().unwrap().into()).collect::>(); + + (expected_log_index, expected_receipt_index, expected_header, expected_receipt, expected_log, expected_proof) + } - let expected_log_index = 0; - let expected_receipt_index = 212; - let expected_header = "0a02eb4a373b45367457c1e162c728cae7e68beaf0914b259b10ed033e95bdcc"; - let expected_receipt = "02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000"; - let expected_log = "f89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130"; - let expected_proof = [ - "f90131a0ea31efc223a1f91c0211cc8216c96d841a4c6aa9e706b1c80f4556473766c835a0a0d053a80857fe23752abc931238dfb519c600ec2c89740a8c0027f2452691dba07211c9aec8f2476236ff4ae404ea0a4d86a3b69aef1d7d68b4525b695d6937c3a066ff6c2bdfbec1a598afe01a4c8cb5342f09dc23e126af6161fc8b66a29258b4a02b1c9c12e45087ab52a964dac390a2b297b279839a14d73e6039ff4136efe176a0c5d3039faed9aefe6b036979ee41e741a6d1a1ffb280d245eefac5646ff0e5b4a0de9817fcc57347a50f1c3bf6bc0af45514a1e17b349d6b3a893acdfc45ad0a70a0bd3ac3599d9a58447c23c89c2ba279fa00a11c13c5e181012d50e012ef845f77a026ce9a58a9d343be345947cd441816397a516ad88e7211170a856d8ce164a14b8080808080808080", - "f851a0776031d2861aa23cb9bd323e49ac2b831658c311c35413899369ea8d558af735a08b9654ecaae433ee01704bb66b4877076a1f8e40b92ba31cadfb9dc06f858c15808080808080808080808080808080", - "f8f18080808080808080a07a49b3a8c05d073eb6d6d11c5c4fdc4505acb5a36c9cbc590929aad029ffc719a099264b31f39abaef84c246bbac4a72dc8bcf5d935c775a8d6c356234d0226061a042f9385fe9d42d8764f8e69b30cae57bcff98c77dc5431d7cc21d10905abcd1ca08a3023498e1067ee67f3caa5a290502efcb05549dd9b0814023e6e1448288467a06e40e4f27b3a0ed5de67c684369aa12610652e6399d002edb5443394f64db861a069631286f3eddfa8ef89eec490348240bc8690b874db62dde1690206dff758b2a0cebfcf4bb26fdcd28a9a42ec0da1e287a0cb41d9bb40ca4879d1cccaf23309998080", - "f90211a0c36f6abaee0178f644673e7d81132cdb139a9bd0bacf0d9719803242b54ef4d3a001a13437394f2ec24ec6a62baf5ef685dc617948314cf6cb7cb237dd759ba7afa0723df3efb2a08ca7156749e43c789cc92001953180a0e51935b3db6eb9c189b2a0d9929bc3195b7cb531249cfcccb0d7d56243a3af67be40d8a89a1ee287a2deeaa0641a7b318fd965ea4d1eb0686909dcd7898b491bb632eeb1ebad2bcc828f4017a0908899d902b0d7d459bba5e19767fc3373764fc6290de12d6588b4e90694aadfa0c6bdef3e0259812cbb979859c0e6a5e2bf980be306d5ed709ae373f0953449cca00993685867da25fb8ac53d636b9630a20297cdabf6e45bc003770dc335742d99a0c8b548c83f65e60afe207d499697f7b377be59c73183f0507862bc739be2348ba0cb4bc9bafef0aec55cd9ff83bc459d162e9f3701b784e2af2a768bc8b3dceeb9a066f522fef288d829e8e49738af851f7aef120dda1f6a1b934c24f96f52684ff2a0117847f1836bf5f354706fce391a183f4b69a55c6e64e820d69c4f5ee35e703da0548eb3f38b406cd35381c28b8a78028d48fe63db72f4a595893adc579b566295a0228c5276786aad75391a7b42d96df14b4494723fc1b096e07bc73e6bfaebc00ea01ae3c79fc12a94557c83e2668c89ec273b0fec08ad6b66e758cde410f121d340a06009085a2fc2a80ee20e8846c9320e28fd7ecf2c519fb8b5559fa30c750ebe8b80", - "f902ae20b902aa02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000" - ]; + fn verify_proof(proof: Proof, test_file: &str) { + let (expected_log_index, expected_receipt_index, expected_header, expected_receipt, expected_log, expected_proof) + = read_proof_data(test_file); let hasher = HasherKeccak::new(); assert_eq!(hasher.digest(&proof.header_data), hex::decode(expected_header).unwrap()); diff --git a/eth2near/utilities/src/test_data/post_dencun_proof.json b/eth2near/utilities/src/test_data/post_dencun_proof.json new file mode 100644 index 00000000..a74690c0 --- /dev/null +++ b/eth2near/utilities/src/test_data/post_dencun_proof.json @@ -0,0 +1,14 @@ +{ + "log_index": 0, + "receipt_index": 212, + "block_hash": "0a02eb4a373b45367457c1e162c728cae7e68beaf0914b259b10ed033e95bdcc", + "receipt": "02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000", + "log": "f89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130", + "proof": [ + "f90131a0ea31efc223a1f91c0211cc8216c96d841a4c6aa9e706b1c80f4556473766c835a0a0d053a80857fe23752abc931238dfb519c600ec2c89740a8c0027f2452691dba07211c9aec8f2476236ff4ae404ea0a4d86a3b69aef1d7d68b4525b695d6937c3a066ff6c2bdfbec1a598afe01a4c8cb5342f09dc23e126af6161fc8b66a29258b4a02b1c9c12e45087ab52a964dac390a2b297b279839a14d73e6039ff4136efe176a0c5d3039faed9aefe6b036979ee41e741a6d1a1ffb280d245eefac5646ff0e5b4a0de9817fcc57347a50f1c3bf6bc0af45514a1e17b349d6b3a893acdfc45ad0a70a0bd3ac3599d9a58447c23c89c2ba279fa00a11c13c5e181012d50e012ef845f77a026ce9a58a9d343be345947cd441816397a516ad88e7211170a856d8ce164a14b8080808080808080", + "f851a0776031d2861aa23cb9bd323e49ac2b831658c311c35413899369ea8d558af735a08b9654ecaae433ee01704bb66b4877076a1f8e40b92ba31cadfb9dc06f858c15808080808080808080808080808080", + "f8f18080808080808080a07a49b3a8c05d073eb6d6d11c5c4fdc4505acb5a36c9cbc590929aad029ffc719a099264b31f39abaef84c246bbac4a72dc8bcf5d935c775a8d6c356234d0226061a042f9385fe9d42d8764f8e69b30cae57bcff98c77dc5431d7cc21d10905abcd1ca08a3023498e1067ee67f3caa5a290502efcb05549dd9b0814023e6e1448288467a06e40e4f27b3a0ed5de67c684369aa12610652e6399d002edb5443394f64db861a069631286f3eddfa8ef89eec490348240bc8690b874db62dde1690206dff758b2a0cebfcf4bb26fdcd28a9a42ec0da1e287a0cb41d9bb40ca4879d1cccaf23309998080", + "f90211a0c36f6abaee0178f644673e7d81132cdb139a9bd0bacf0d9719803242b54ef4d3a001a13437394f2ec24ec6a62baf5ef685dc617948314cf6cb7cb237dd759ba7afa0723df3efb2a08ca7156749e43c789cc92001953180a0e51935b3db6eb9c189b2a0d9929bc3195b7cb531249cfcccb0d7d56243a3af67be40d8a89a1ee287a2deeaa0641a7b318fd965ea4d1eb0686909dcd7898b491bb632eeb1ebad2bcc828f4017a0908899d902b0d7d459bba5e19767fc3373764fc6290de12d6588b4e90694aadfa0c6bdef3e0259812cbb979859c0e6a5e2bf980be306d5ed709ae373f0953449cca00993685867da25fb8ac53d636b9630a20297cdabf6e45bc003770dc335742d99a0c8b548c83f65e60afe207d499697f7b377be59c73183f0507862bc739be2348ba0cb4bc9bafef0aec55cd9ff83bc459d162e9f3701b784e2af2a768bc8b3dceeb9a066f522fef288d829e8e49738af851f7aef120dda1f6a1b934c24f96f52684ff2a0117847f1836bf5f354706fce391a183f4b69a55c6e64e820d69c4f5ee35e703da0548eb3f38b406cd35381c28b8a78028d48fe63db72f4a595893adc579b566295a0228c5276786aad75391a7b42d96df14b4494723fc1b096e07bc73e6bfaebc00ea01ae3c79fc12a94557c83e2668c89ec273b0fec08ad6b66e758cde410f121d340a06009085a2fc2a80ee20e8846c9320e28fd7ecf2c519fb8b5559fa30c750ebe8b80", + "f902ae20b902aa02f902a60183cee136b9010000000000000020000000000000000000000000000000000000000000000000000800010000000000000008000100000040000000000000000000000000000000000000000000000000000008004000000000000000000000000000000000000000000000000000000000000000000200000000000000010000000010000000000000010000000000000000000000000000000000000004000000000000000000000000000000000080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000210000000000000000000000000000000000000200000000000000000000000000000000000000f9019bf89b94438e48ed4ce6beecf503d43b9dbd3c30d516e7fdf863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa00000000000000000000000006889de313803839ce3e15996a86167f639b4a634a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa000000000000000000000000000000000000000000000001a2738b6f81a2e0130f8fc9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000438e48ed4ce6beecf503d43b9dbd3c30d516e7fda00000000000000000000000006889de313803839ce3e15996a86167f639b4a634b88000000000000000000000000000000000000000000000001a2738b6f81a2e01300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b74696d626c652e6e656172000000000000000000000000000000000000000000" + ] +} \ No newline at end of file diff --git a/eth2near/utilities/src/test_data/post_shapella_proof.json b/eth2near/utilities/src/test_data/post_shapella_proof.json new file mode 100644 index 00000000..0279fa2c --- /dev/null +++ b/eth2near/utilities/src/test_data/post_shapella_proof.json @@ -0,0 +1,12 @@ +{ + "log_index": 0, + "receipt_index": 54, + "block_hash": "d02357b89842839d7c736f5b9899a6a2f469c7c1c35ec574c76b087006653456", + "receipt": "02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000", + "log": "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380", + "proof": [ + "f90111a09e0259b98fa182a95c48a8dacc2692badd7c29f71bc3e0d9d73dbf9d07e9611ba0ba6c9f95a62c8f2b828d4160e01162934297442c7cefea304908609de9fbd075a0993a2a24f0772d90700a7ad8f133ab1b7963defa359ad9826eb963f6168cfb60a0c31053f554e06e64bdddc105051dd2210d396514cd6edcc9aa55767e7652825ba05e2a24f235c03c6b6320a1d62e0e6d646349da863767ecf10126e6b4aacf274fa0e0c4a45d2ecd16a37af707062a5bec9f6657fcfe14ddb692215bdd6a26600617a0e53fe123d45561809c69c532b39d90e7eb0b6d7a74d09a259cbb41a29b12081480a044cf8e4f60cf97fb129824b1b37c04e82251da90b5e8fb9b3998cc3519e159798080808080808080", + "f90211a0d4de7e86f5e6eba4a08c89925937986e201e6f286b7123fb5700354df9167b7ba07b3389484104ebb32e6959db5ed3cddcdb2d1ce0c2b41ce5dc4ce2553e808f84a0e7344755384ea053c57c5546c1516a356c8cab5fe926a5a3eb3fe6721671001da0b9312cb00a3723a9a80598ab13d730430c686e9f2b14e669f41d87f36ede87b2a06069a92ac34df54f389475c9b92fea2b92bc73e92bffa14cb5c085469e884398a03f6262719ad775eef95b991f24aa63370892d4d0ef8dbaeba19f681e2cba2b5aa0071ab0cc93209db0be2343111f91ba35a180e0a453f23660aed462fce5daf551a0bfd7126fa52bb94255b9b7613a5a0b8bdb1f01443de5da83ce1839a0fe9d6e3ba02384631620ba5abce1a52e7347bff8c3727a56390bd7bc57c7d1386508cb1672a06ed35b57e37f3a08788866524b8a2d0089ec3fb308f34dea583324afd57e476aa05af302b741e36f6c630f423ff8d40be2fdeb4fb517eb62782ae6955c986ce21fa0b16f820757bb0bd971bdba9371540c09528d2818a6ab196ca6cbb3919d5097bda027b6b7c488fd95227a11f4c62d1d138341fd242f558de9bba659f99f543edd18a06f83a49cb804e10ee72d2cbd844b0fb6145eb5ca2f3bcd0c4d37fd357f2404d8a0b9f13ed67f0b534b781693633d36bde8f6127aa4cae31659475910a08a2956f4a0dcc805b1d26db82e140bf5de19cb39b95e7590a52e13cd83a65471cb95f456fd80", + "f902cf20b902cb02f902c701837036edb9010000000000000000000000000000000000000000000000000000200000000000000800010000000000000002000100000000000000000000000000000000000000000000000000000008000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000002000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2a000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa00000000000000000000000000000000000000000000000000000000014dc9380f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a000000000000000000000000090b0a46b1c02bd137ca1410772eff1c231f07fe2b8a00000000000000000000000000000000000000000000000000000000014dc93800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a316339396663333736353537366635613641353544353341653431423936434239373141393432350000000000000000000000000000000000" + ] +} \ No newline at end of file diff --git a/eth2near/utilities/src/test_data/pre_shapella_proof.json b/eth2near/utilities/src/test_data/pre_shapella_proof.json new file mode 100644 index 00000000..ad2e4850 --- /dev/null +++ b/eth2near/utilities/src/test_data/pre_shapella_proof.json @@ -0,0 +1,14 @@ +{ + "log_index": 0, + "receipt_index": 167, + "block_hash": "f61633d948772c98982af9df989c5cb9b9a8f5ed1a8411d57feb794013941de5", + "receipt": "02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000", + "log": "f89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800", + "proof": [ + "f90131a0967c44262dfeff60c2af9aba0bece5cb031e5072f2978bcf7fb18360abad1d3ca0ebdf9d8b1746ad2d585fa5c657348250fa92fa0586d6c89ab40c186115bebc17a0feffed8388da8e4f4936717c660a42f34b93cce4583d0944198c27e043779f56a06f970da48b1447fb56f88d27d9b0d4ea8cf30a6e83b507734fd96e3a42c17f24a0748ff314a3f88b77e11ef6c7f716f58ac498ae3b3264d6b2e0bdb6c91030df1fa05f6b3f1d31dc2f30322199b97af434c1c40891648515c0c483c2518f981a10b1a06dfe85601a2d49321453acf4edeab412bdb950fc65b2337b042aa7972d4925eea01eb88ec9349d5f61858f5a14b90456b78fb3bb0121d90df936d9765a05e78031a047c4fa8e5283c0dbeae2e4b9e6250008551b02d2edce1dd87bf9ace4d687604b8080808080808080", + "f851a08aa8e40f2823eb01a484cf576f2582137280289ca54eb3da743a36203ba963d0a023bad42a2491d2b478b82ff7e2d1b2beb569981a23c4376be21d1436c12d920a808080808080808080808080808080", + "f8918080808080808080a0918f290dbb902b8bf23c852bd82c945a37d4d5d015e9e9485616f3fa6e12aabca092b063303221d5c76f441ae788fa44597bd71cf03d0c944993ce8428c5a661fda0a7fc9b765f5a541c286acb44fe3ccffd32c1585da784b88d9bd800d933e69826a0ea9675894b751d28c53159f2582481df16925392fef0a81e1a2baa2d9e08190b8080808080", + "f90211a0abc02bfbddd2313e525124b626275a08e4d5437c837a114b11bd56a9421d04aaa0e71d7c39496e26fa67b5cc364a49e2e5701c8b5edbd5c58afc716e92ca9cc8f9a0cdec4707b811edbf0c81db09631c5a18dbfbda66d4793358257e5ec5c8993234a01356b944c23504dc1aa148f1a46d5e3c3f1b990a88b8ade4767d84aa7d4ca79fa06f883de36996ebd0b395f114e96a468c1aeaa287ca4f10e01648b0d60515a111a02ccaea122ce8542fd7ff9e02cec311f8d1b8ab7a0d949074e8f621765c58588ba01aeeca3be1c4e8e2581ed016d74442677645c0b423bb34e919ccf14009cbc92ba03bc2b368375a4de99317a01c548c6e564966cb317c3b4ba20c5cb0b181ac7c6ca04350da6c4a50dbb535c72bcd4632a5b94c15c709e2df6cd91269ce0faacd46c4a0743908223350d40bdb093c331dc0fbabe066f46440fdcf474f28acc48162c67da052aeea371b09dfe541719470a63a1fb12708c72eaa575bf723fea692a48b9d77a0aefd559fe69cb9163a4c3aa562e80beb3199afa446c449f048a38be05bc5fa00a05a373afc917a53eea199c158f7daea520dcc4d5b76c6cf87bb823b962f6cb506a0eb119ea50817395bd79be6e6fa748d64dc9ded81c63c6d61474210ab0003be7da0e4c36dd93a40a90993f083829469e0718aaf510e8eedf9ed5a7d8fdd4af92643a0aa1c5c12d65fdf25f74354991185dccecefb1e5813531ce8c9fdd2b2c7494a3c80", + "f902cf20b902cb02f902c70183f2d2d4b9010000000000000000000000000000000000000000000000000000000000000000000800010000000000000002000100000000000000000000000000000000000000000200000000000008000008000000000000000000000000000000004000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000200000000010000000000000000000000000000000000200080000000200000000000000000000000000000004000000000000002000000000000000000000000000000000000080000000000000000000000000000000000000000000200000004000000000000000000000000000000f901bcf89b94a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afa000000000000000000000000023ddd3e3692d1861ed57ede224608875809e127fa0000000000000000000000000000000000000000000000000000000174876e800f9011c9423ddd3e3692d1861ed57ede224608875809e127ff863a0dd85dc56b5b4da387bf69c28ec19b1d66e793e0d51b567882fa31dc50bbd32c5a0000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a0000000000000000000000000ef013a60f765f34b0fd7c5aaf83b9c65bb10a9afb8a0000000000000000000000000000000000000000000000000000000174876e8000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002f6175726f72613a343332456231663237333036363241443141393739314564333443423244424466373030313535350000000000000000000000000000000000" + ] +} \ No newline at end of file