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] 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, }