From 1ec0180341a2cf36c94691533f74127eb84bc19f Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Mon, 12 Jun 2023 16:33:20 +0800 Subject: [PATCH 01/12] eth_getLogs implementation --- lib/ain-evm/src/handler.rs | 6 ++ lib/ain-evm/src/lib.rs | 1 + lib/ain-evm/src/log.rs | 95 +++++++++++++++++++++++++ lib/ain-evm/src/receipt.rs | 2 +- lib/ain-evm/src/storage/data_handler.rs | 36 +++++++++- lib/ain-evm/src/storage/mod.rs | 16 ++++- lib/ain-evm/src/storage/traits.rs | 9 ++- lib/ain-grpc/src/lib.rs | 1 + lib/ain-grpc/src/rpc/eth.rs | 24 +++++++ lib/ain-grpc/src/transaction_log.rs | 31 ++++++++ 10 files changed, 216 insertions(+), 5 deletions(-) create mode 100644 lib/ain-evm/src/log.rs create mode 100644 lib/ain-grpc/src/transaction_log.rs diff --git a/lib/ain-evm/src/handler.rs b/lib/ain-evm/src/handler.rs index 0bed2d4c3f..203524dd04 100644 --- a/lib/ain-evm/src/handler.rs +++ b/lib/ain-evm/src/handler.rs @@ -2,6 +2,7 @@ use crate::backend::{EVMBackend, Vicinity}; use crate::block::BlockHandler; use crate::evm::EVMHandler; use crate::executor::{AinExecutor, TxResponse}; +use crate::log::LogHandler; use crate::receipt::ReceiptHandler; use crate::storage::traits::BlockStorage; use crate::storage::Storage; @@ -23,6 +24,7 @@ pub struct Handlers { pub evm: EVMHandler, pub block: BlockHandler, pub receipt: ReceiptHandler, + pub logs: LogHandler, pub storage: Arc, } @@ -54,6 +56,7 @@ impl Handlers { evm: EVMHandler::new_from_json(Arc::clone(&storage), PathBuf::from(path)), block: BlockHandler::new(Arc::clone(&storage)), receipt: ReceiptHandler::new(Arc::clone(&storage)), + logs: LogHandler::new(Arc::clone(&storage)), storage, }) } else { @@ -62,6 +65,7 @@ impl Handlers { evm: EVMHandler::restore(Arc::clone(&storage)), block: BlockHandler::new(Arc::clone(&storage)), receipt: ReceiptHandler::new(Arc::clone(&storage)), + logs: LogHandler::new(Arc::clone(&storage)), storage, }) } @@ -221,6 +225,8 @@ impl Handlers { let base_fee = self.block.calculate_base_fee(parent_hash); self.block.connect_block(block.clone(), base_fee); + self.logs + .generate_logs_from_receipts(&receipts, block.header.number); self.receipt.put_receipts(receipts); } diff --git a/lib/ain-evm/src/lib.rs b/lib/ain-evm/src/lib.rs index 1a59caaa68..f191f9fe07 100644 --- a/lib/ain-evm/src/lib.rs +++ b/lib/ain-evm/src/lib.rs @@ -6,6 +6,7 @@ pub mod executor; mod fee; mod genesis; pub mod handler; +pub mod log; pub mod receipt; pub mod runtime; pub mod storage; diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs new file mode 100644 index 0000000000..553d127720 --- /dev/null +++ b/lib/ain-evm/src/log.rs @@ -0,0 +1,95 @@ +use crate::receipt::Receipt; +use crate::storage::traits::LogStorage; +use crate::storage::Storage; +use ethereum::{Log, ReceiptV3}; +use primitive_types::{H160, H256, U256}; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct LogIndex { + pub block_hash: H256, + pub topics: Vec, + pub data: Vec, + pub log_index: U256, + pub address: H160, + pub removed: bool, + pub transaction_hash: H256, + pub transaction_index: usize, +} + +pub struct LogHandler { + storage: Arc, +} + +fn get_to_address(receipt: &Receipt) -> H160 { + match receipt.to { + Some(to) => to, + None => receipt + .contract_address + .expect("Unable to find a valid destination address"), + } +} + +impl LogHandler { + pub fn new(storage: Arc) -> Self { + Self { storage } + } + + pub fn generate_logs_from_receipts(&self, receipts: &Vec, block_number: U256) { + let mut logs_map: HashMap> = HashMap::new(); + let mut log_index = 0; // log index is a block level index + for receipt in receipts { + let logs = match &receipt.receipt { + ReceiptV3::Legacy(r) => &r.logs, + ReceiptV3::EIP2930(r) => &r.logs, + ReceiptV3::EIP1559(r) => &r.logs, + }; + + for log in logs { + let map = logs_map.entry(log.address).or_insert(Vec::new()); + + map.push(LogIndex { + block_hash: receipt.block_hash, + topics: log.clone().topics, + data: log.clone().data, + log_index: U256::from(log_index), + address: log.clone().address, + removed: false, // hardcoded as no reorgs on DeFiChain + transaction_hash: receipt.tx_hash, + transaction_index: receipt.tx_index, + }); + + log_index += 1; + } + } + + for (address, logs) in logs_map.into_iter() { + self.storage.put_logs(address, logs, block_number) + } + } + + // get logs at a block height and filter for topics + pub fn get_logs(&self, address: &H160, topics: Vec, block_number: U256) -> Vec { + let logs = self + .storage + .get_logs(&address) + .unwrap() + .get(&block_number) + .map(ToOwned::to_owned) + .unwrap(); + + if topics.is_empty() { + logs + } else { + // filter logs with topics + logs.into_iter() + .filter(|log| { + let set: HashSet<_> = log.topics.iter().copied().collect(); + topics.iter().all(|item| set.contains(item)) // TODO: multiple vector topics not working + }) + .collect() + } + } +} diff --git a/lib/ain-evm/src/receipt.rs b/lib/ain-evm/src/receipt.rs index 8b7d64d8e4..4e95d2cef5 100644 --- a/lib/ain-evm/src/receipt.rs +++ b/lib/ain-evm/src/receipt.rs @@ -1,6 +1,6 @@ use crate::storage::{traits::ReceiptStorage, Storage}; use crate::transaction::SignedTx; -use ethereum::{EnvelopedEncodable, ReceiptV3}; +use ethereum::{EnvelopedEncodable, Log, ReceiptV3}; use primitive_types::{H160, H256, U256}; use ethereum::util::ordered_trie_root; diff --git a/lib/ain-evm/src/storage/data_handler.rs b/lib/ain-evm/src/storage/data_handler.rs index 181a40b6f4..f441c6f3e5 100644 --- a/lib/ain-evm/src/storage/data_handler.rs +++ b/lib/ain-evm/src/storage/data_handler.rs @@ -1,10 +1,12 @@ use std::{collections::HashMap, sync::RwLock}; +use crate::log::LogIndex; use ethereum::{BlockAny, TransactionV2}; -use primitive_types::{H256, U256}; +use primitive_types::{H160, H256, U256}; use std::borrow::ToOwned; use crate::receipt::Receipt; +use crate::storage::traits::LogStorage; use super::{ code::CodeHistory, @@ -21,6 +23,8 @@ pub static RECEIPT_MAP_PATH: &str = "receipt_map.bin"; pub static CODE_MAP_PATH: &str = "code_map.bin"; pub static TRANSACTION_DATA_PATH: &str = "transaction_data.bin"; pub static BASE_FEE_MAP_PATH: &str = "base_fee_map.bin"; +pub static LOGS_MAP_PATH: &str = "logs_map.bin"; +pub static ADDRESS_LOGS_MAP_PATH: &str = "address_logs_map.bin"; type BlockHashtoBlock = HashMap; type Blocks = HashMap; @@ -28,12 +32,14 @@ type TxHashToTx = HashMap; type LatestBlockNumber = U256; type TransactionHashToReceipt = HashMap; type BlockHashtoBaseFee = HashMap; +type AddressToLogs = HashMap>>; impl PersistentState for BlockHashtoBlock {} impl PersistentState for Blocks {} impl PersistentState for LatestBlockNumber {} impl PersistentState for TransactionHashToReceipt {} impl PersistentState for TxHashToTx {} +impl PersistentState for AddressToLogs {} #[derive(Debug, Default)] pub struct BlockchainDataHandler { @@ -48,6 +54,8 @@ pub struct BlockchainDataHandler { base_fee_map: RwLock, code_map: RwLock, + + address_logs_map: RwLock, } impl BlockchainDataHandler { @@ -75,6 +83,9 @@ impl BlockchainDataHandler { BlockHashtoBaseFee::load_from_disk(BASE_FEE_MAP_PATH).unwrap_or_default(), ), code_map: RwLock::new(CodeHistory::load_from_disk(CODE_MAP_PATH).unwrap_or_default()), + address_logs_map: RwLock::new( + AddressToLogs::load_from_disk(ADDRESS_LOGS_MAP_PATH).unwrap_or_default(), + ), } } } @@ -203,6 +214,23 @@ impl ReceiptStorage for BlockchainDataHandler { } } +impl LogStorage for BlockchainDataHandler { + fn get_logs(&self, address: &H160) -> Option>> { + self.address_logs_map + .read() + .unwrap() + .get(address) + .map(ToOwned::to_owned) + } + + fn put_logs(&self, address: H160, logs: Vec, block_number: U256) { + let mut address_logs_map = self.address_logs_map.write().unwrap(); + + let address_map = address_logs_map.entry(address).or_insert(HashMap::new()); + address_map.insert(block_number, logs); + } +} + impl FlushableStorage for BlockchainDataHandler { fn flush(&self) -> Result<(), PersistentStateError> { self.block_map @@ -227,7 +255,11 @@ impl FlushableStorage for BlockchainDataHandler { self.base_fee_map .write() .unwrap() - .save_to_disk(BASE_FEE_MAP_PATH) + .save_to_disk(BASE_FEE_MAP_PATH)?; + self.address_logs_map + .write() + .unwrap() + .save_to_disk(ADDRESS_LOGS_MAP_PATH) } } diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index 622527f001..9651d1aa51 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -3,10 +3,13 @@ mod code; mod data_handler; pub mod traits; +use crate::log::LogIndex; use ethereum::{BlockAny, TransactionV2}; -use primitive_types::{H256, U256}; +use primitive_types::{H160, H256, U256}; +use std::collections::HashMap; use crate::receipt::Receipt; +use crate::storage::traits::LogStorage; use self::{ cache::Cache, @@ -174,6 +177,17 @@ impl ReceiptStorage for Storage { } } +impl LogStorage for Storage { + fn get_logs(&self, address: &H160) -> Option>> { + self.blockchain_data_handler.get_logs(address) + } + + fn put_logs(&self, address: H160, logs: Vec, block_number: U256) { + self.blockchain_data_handler + .put_logs(address, logs, block_number) + } +} + impl FlushableStorage for Storage { fn flush(&self) -> Result<(), PersistentStateError> { self.blockchain_data_handler.flush() diff --git a/lib/ain-evm/src/storage/traits.rs b/lib/ain-evm/src/storage/traits.rs index e43d86625b..2d2ff40d22 100644 --- a/lib/ain-evm/src/storage/traits.rs +++ b/lib/ain-evm/src/storage/traits.rs @@ -3,9 +3,11 @@ use ethereum::BlockAny; use ethereum::TransactionV2; use keccak_hash::H256; use log::debug; -use primitive_types::U256; +use primitive_types::{H160, U256}; +use std::collections::HashMap; use std::fs::File; +use crate::log::LogIndex; use std::fmt; use std::io; use std::io::Write; @@ -44,6 +46,11 @@ pub trait ReceiptStorage { fn put_receipts(&self, receipts: Vec); } +pub trait LogStorage { + fn get_logs(&self, address: &H160) -> Option>>; + fn put_logs(&self, address: H160, logs: Vec, block_number: U256); +} + pub trait FlushableStorage { fn flush(&self) -> Result<(), PersistentStateError>; } diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index ed8ef1fc37..0f18a89f01 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -10,6 +10,7 @@ mod impls; mod receipt; pub mod rpc; mod transaction; +mod transaction_log; mod transaction_request; mod utils; diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index da1d608318..53f67a4c9b 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -9,6 +9,7 @@ use ain_cpp_imports::get_eth_priv_key; use ain_evm::executor::TxResponse; use ain_evm::handler::Handlers; +use crate::transaction_log::LogResult; use ain_evm::storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage}; use ain_evm::transaction::{SignedTx, TransactionError}; use ethereum::{EnvelopedEncodable, TransactionV2}; @@ -203,6 +204,14 @@ pub trait MetachainRPC { #[method(name = "maxPriorityFeePerGas")] fn max_priority_fee_per_gas(&self) -> RpcResult; + + #[method(name = "getLogs")] + fn get_logs( + &self, + address: H160, + topics: Vec, + block_number: U256, + ) -> RpcResult>; } pub struct MetachainRPCModule { @@ -703,6 +712,21 @@ impl MetachainRPCServer for MetachainRPCModule { fn max_priority_fee_per_gas(&self) -> RpcResult { Ok(self.handler.block.suggested_priority_fee()) } + + fn get_logs( + &self, + address: H160, + topics: Vec, + block_number: U256, + ) -> RpcResult> { + Ok(self + .handler + .logs + .get_logs(&address, topics, block_number) + .into_iter() + .map(LogResult::from) + .collect()) + } } fn sign( diff --git a/lib/ain-grpc/src/transaction_log.rs b/lib/ain-grpc/src/transaction_log.rs new file mode 100644 index 0000000000..dbd3372c9e --- /dev/null +++ b/lib/ain-grpc/src/transaction_log.rs @@ -0,0 +1,31 @@ +use crate::bytes::Bytes; +use ain_evm::log::LogIndex; +use primitive_types::{H160, H256, U256}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct LogResult { + pub block_hash: H256, + pub log_index: U256, + pub removed: bool, + pub transaction_hash: H256, + pub transaction_index: usize, + pub address: H160, + pub data: Bytes, + pub topics: Vec, +} + +impl From for LogResult { + fn from(log: LogIndex) -> Self { + Self { + block_hash: log.block_hash, + log_index: log.log_index, + removed: log.removed, + transaction_hash: log.transaction_hash, + transaction_index: log.transaction_index, + address: log.address, + data: Bytes::from(log.data), + topics: log.topics, + } + } +} From e61f0fc252671f5979beefd9956081f3d7d900c1 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 12:35:19 +0800 Subject: [PATCH 02/12] Change storage format --- lib/ain-evm/src/log.rs | 15 +++------------ lib/ain-evm/src/receipt.rs | 2 +- lib/ain-evm/src/storage/data_handler.rs | 13 +++++++------ lib/ain-evm/src/storage/mod.rs | 4 ++-- lib/ain-evm/src/storage/traits.rs | 2 +- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 553d127720..4f27a8b7fa 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -1,7 +1,7 @@ use crate::receipt::Receipt; use crate::storage::traits::LogStorage; use crate::storage::Storage; -use ethereum::{Log, ReceiptV3}; +use ethereum::ReceiptV3; use primitive_types::{H160, H256, U256}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; @@ -23,15 +23,6 @@ pub struct LogHandler { storage: Arc, } -fn get_to_address(receipt: &Receipt) -> H160 { - match receipt.to { - Some(to) => to, - None => receipt - .contract_address - .expect("Unable to find a valid destination address"), - } -} - impl LogHandler { pub fn new(storage: Arc) -> Self { Self { storage } @@ -74,9 +65,9 @@ impl LogHandler { pub fn get_logs(&self, address: &H160, topics: Vec, block_number: U256) -> Vec { let logs = self .storage - .get_logs(&address) + .get_logs(&block_number) .unwrap() - .get(&block_number) + .get(&address) .map(ToOwned::to_owned) .unwrap(); diff --git a/lib/ain-evm/src/receipt.rs b/lib/ain-evm/src/receipt.rs index 4e95d2cef5..8b7d64d8e4 100644 --- a/lib/ain-evm/src/receipt.rs +++ b/lib/ain-evm/src/receipt.rs @@ -1,6 +1,6 @@ use crate::storage::{traits::ReceiptStorage, Storage}; use crate::transaction::SignedTx; -use ethereum::{EnvelopedEncodable, Log, ReceiptV3}; +use ethereum::{EnvelopedEncodable, ReceiptV3}; use primitive_types::{H160, H256, U256}; use ethereum::util::ordered_trie_root; diff --git a/lib/ain-evm/src/storage/data_handler.rs b/lib/ain-evm/src/storage/data_handler.rs index f441c6f3e5..0cd767459a 100644 --- a/lib/ain-evm/src/storage/data_handler.rs +++ b/lib/ain-evm/src/storage/data_handler.rs @@ -23,7 +23,6 @@ pub static RECEIPT_MAP_PATH: &str = "receipt_map.bin"; pub static CODE_MAP_PATH: &str = "code_map.bin"; pub static TRANSACTION_DATA_PATH: &str = "transaction_data.bin"; pub static BASE_FEE_MAP_PATH: &str = "base_fee_map.bin"; -pub static LOGS_MAP_PATH: &str = "logs_map.bin"; pub static ADDRESS_LOGS_MAP_PATH: &str = "address_logs_map.bin"; type BlockHashtoBlock = HashMap; @@ -32,7 +31,7 @@ type TxHashToTx = HashMap; type LatestBlockNumber = U256; type TransactionHashToReceipt = HashMap; type BlockHashtoBaseFee = HashMap; -type AddressToLogs = HashMap>>; +type AddressToLogs = HashMap>>; impl PersistentState for BlockHashtoBlock {} impl PersistentState for Blocks {} @@ -215,19 +214,21 @@ impl ReceiptStorage for BlockchainDataHandler { } impl LogStorage for BlockchainDataHandler { - fn get_logs(&self, address: &H160) -> Option>> { + fn get_logs(&self, block_number: &U256) -> Option>> { self.address_logs_map .read() .unwrap() - .get(address) + .get(block_number) .map(ToOwned::to_owned) } fn put_logs(&self, address: H160, logs: Vec, block_number: U256) { let mut address_logs_map = self.address_logs_map.write().unwrap(); - let address_map = address_logs_map.entry(address).or_insert(HashMap::new()); - address_map.insert(block_number, logs); + let address_map = address_logs_map + .entry(block_number) + .or_insert(HashMap::new()); + address_map.insert(address, logs); } } diff --git a/lib/ain-evm/src/storage/mod.rs b/lib/ain-evm/src/storage/mod.rs index 9651d1aa51..83b1b1b14b 100644 --- a/lib/ain-evm/src/storage/mod.rs +++ b/lib/ain-evm/src/storage/mod.rs @@ -178,8 +178,8 @@ impl ReceiptStorage for Storage { } impl LogStorage for Storage { - fn get_logs(&self, address: &H160) -> Option>> { - self.blockchain_data_handler.get_logs(address) + fn get_logs(&self, block_number: &U256) -> Option>> { + self.blockchain_data_handler.get_logs(block_number) } fn put_logs(&self, address: H160, logs: Vec, block_number: U256) { diff --git a/lib/ain-evm/src/storage/traits.rs b/lib/ain-evm/src/storage/traits.rs index 2d2ff40d22..e17bf81696 100644 --- a/lib/ain-evm/src/storage/traits.rs +++ b/lib/ain-evm/src/storage/traits.rs @@ -47,7 +47,7 @@ pub trait ReceiptStorage { } pub trait LogStorage { - fn get_logs(&self, address: &H160) -> Option>>; + fn get_logs(&self, block_number: &U256) -> Option>>; fn put_logs(&self, address: H160, logs: Vec, block_number: U256); } From 6dc8a49269b373fa51538a19d6eb495a130c76a7 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 13:44:40 +0800 Subject: [PATCH 03/12] Make RPC compatible with ETH spec --- lib/ain-evm/src/log.rs | 48 +++++++++++++--------- lib/ain-grpc/src/rpc/eth.rs | 62 ++++++++++++++++++++--------- lib/ain-grpc/src/transaction_log.rs | 13 ++++++ 3 files changed, 87 insertions(+), 36 deletions(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 4f27a8b7fa..7b0042ee69 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -62,25 +62,37 @@ impl LogHandler { } // get logs at a block height and filter for topics - pub fn get_logs(&self, address: &H160, topics: Vec, block_number: U256) -> Vec { - let logs = self - .storage - .get_logs(&block_number) - .unwrap() - .get(&address) - .map(ToOwned::to_owned) - .unwrap(); + pub fn get_logs( + &self, + address: Option>, + topics: Option>, + block_number: U256, + ) -> Vec { + let logs = self.storage.get_logs(&block_number).unwrap(); // TODO: should be handled gracefully - if topics.is_empty() { - logs - } else { - // filter logs with topics - logs.into_iter() - .filter(|log| { - let set: HashSet<_> = log.topics.iter().copied().collect(); - topics.iter().all(|item| set.contains(item)) // TODO: multiple vector topics not working - }) - .collect() + let logs = match address { + None => logs.into_iter().map(|(_, log)| log).flatten().collect(), + Some(addresses) => { + // filter by addresses + logs.into_iter() + .filter(|(address, _)| addresses.contains(address)) + .into_iter() + .map(|(_, log)| log) + .flatten() + .collect() + } + }; + + match topics { + None => logs, + Some(topics) => { + logs.into_iter() + .filter(|log| { + let set: HashSet<_> = log.topics.iter().copied().collect(); + topics.iter().all(|item| set.contains(item)) // TODO: multiple vector topics not working + }) + .collect() + } } } } diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 414c48dfc6..fab69e705c 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -10,7 +10,7 @@ use ain_cpp_imports::get_eth_priv_key; use ain_evm::executor::TxResponse; use ain_evm::handler::Handlers; -use crate::transaction_log::LogResult; +use crate::transaction_log::{GetLogsRequest, LogResult}; use ain_evm::storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage}; use ain_evm::transaction::{SignedTx, TransactionError}; use ethereum::{EnvelopedEncodable, TransactionV2}; @@ -207,12 +207,7 @@ pub trait MetachainRPC { fn max_priority_fee_per_gas(&self) -> RpcResult; #[method(name = "getLogs")] - fn get_logs( - &self, - address: H160, - topics: Vec, - block_number: U256, - ) -> RpcResult>; + fn get_logs(&self, input: GetLogsRequest) -> RpcResult>; } pub struct MetachainRPCModule { @@ -731,18 +726,49 @@ impl MetachainRPCServer for MetachainRPCModule { Ok(self.handler.block.suggested_priority_fee()) } - fn get_logs( - &self, - address: H160, - topics: Vec, - block_number: U256, - ) -> RpcResult> { - Ok(self - .handler - .logs - .get_logs(&address, topics, block_number) + fn get_logs(&self, input: GetLogsRequest) -> RpcResult> { + if input.block_hash.is_some() && (input.to_block.is_some() || input.from_block.is_some()) { + return Err(Error::Custom(String::from( + "cannot specify both blockHash and fromBlock/toBlock, choose one or the other", + ))); + } + + let block_numbers = match input.block_hash { + None => { + // use fromBlock-toBlock + let from_block_number = self.block_number_to_u256(input.from_block).as_u128(); + let to_block_number = self.block_number_to_u256(input.from_block).as_u128(); + let mut block_numbers = Vec::new(); + + for block_number in from_block_number..=to_block_number { + block_numbers.push(U256::from(block_number)) + } + + block_numbers + } + Some(block_hash) => { + vec![ + self.handler + .storage + .get_block_by_hash(&block_hash) + .ok_or_else(|| Error::Custom(String::from("Unable to find block hash"))) + .unwrap() + .header + .number, + ] + } + }; + + Ok(block_numbers .into_iter() - .map(LogResult::from) + .map(|block_number| { + self.handler + .logs + .get_logs(input.clone().address, input.clone().topics, block_number) + .into_iter() + .map(LogResult::from) + }) + .flatten() .collect()) } } diff --git a/lib/ain-grpc/src/transaction_log.rs b/lib/ain-grpc/src/transaction_log.rs index dbd3372c9e..f10392e18e 100644 --- a/lib/ain-grpc/src/transaction_log.rs +++ b/lib/ain-grpc/src/transaction_log.rs @@ -1,3 +1,4 @@ +use crate::block::BlockNumber; use crate::bytes::Bytes; use ain_evm::log::LogIndex; use primitive_types::{H160, H256, U256}; @@ -29,3 +30,15 @@ impl From for LogResult { } } } + +/// Call request +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +#[serde(rename_all = "camelCase")] +pub struct GetLogsRequest { + pub address: Option>, + pub block_hash: Option, + pub from_block: Option, + pub to_block: Option, + pub topics: Option>, +} From 9b0a9afc23609f8f0ce5d146f26b9cbfbf9061c5 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 13:49:32 +0800 Subject: [PATCH 04/12] Do not unwrap after ok_or_else --- lib/ain-grpc/src/rpc/eth.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index fab69e705c..83cf35e6b1 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -751,8 +751,7 @@ impl MetachainRPCServer for MetachainRPCModule { self.handler .storage .get_block_by_hash(&block_hash) - .ok_or_else(|| Error::Custom(String::from("Unable to find block hash"))) - .unwrap() + .ok_or_else(|| Error::Custom(String::from("Unable to find block hash")))? .header .number, ] From faf5b29c72e8bc5dd3f215a8e2cd7463ad591e8f Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 14:03:33 +0800 Subject: [PATCH 05/12] Do not throw when no logs in block --- lib/ain-evm/src/log.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 7b0042ee69..7ed355809f 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -2,6 +2,7 @@ use crate::receipt::Receipt; use crate::storage::traits::LogStorage; use crate::storage::Storage; use ethereum::ReceiptV3; +use log::debug; use primitive_types::{H160, H256, U256}; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; @@ -68,7 +69,8 @@ impl LogHandler { topics: Option>, block_number: U256, ) -> Vec { - let logs = self.storage.get_logs(&block_number).unwrap(); // TODO: should be handled gracefully + debug!("Getting logs for block {:#x?}", block_number); + let logs = self.storage.get_logs(&block_number).unwrap_or_default(); let logs = match address { None => logs.into_iter().map(|(_, log)| log).flatten().collect(), From 21498ed0993d52f79a53890237e65bc3bb6a1b90 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 14:13:42 +0800 Subject: [PATCH 06/12] Fix arg read --- lib/ain-grpc/src/rpc/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 83cf35e6b1..f1de89c559 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -737,7 +737,7 @@ impl MetachainRPCServer for MetachainRPCModule { None => { // use fromBlock-toBlock let from_block_number = self.block_number_to_u256(input.from_block).as_u128(); - let to_block_number = self.block_number_to_u256(input.from_block).as_u128(); + let to_block_number = self.block_number_to_u256(input.to_block).as_u128(); let mut block_numbers = Vec::new(); for block_number in from_block_number..=to_block_number { From 77ad1b9340c1e191fb8ff8d68c927d7a01c35b18 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 14:23:49 +0800 Subject: [PATCH 07/12] Use flat_map --- lib/ain-evm/src/log.rs | 5 ++--- lib/ain-grpc/src/rpc/eth.rs | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 7ed355809f..6208a8dc10 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -73,14 +73,13 @@ impl LogHandler { let logs = self.storage.get_logs(&block_number).unwrap_or_default(); let logs = match address { - None => logs.into_iter().map(|(_, log)| log).flatten().collect(), + None => logs.into_iter().flat_map(|(_, log)| log).collect(), Some(addresses) => { // filter by addresses logs.into_iter() .filter(|(address, _)| addresses.contains(address)) .into_iter() - .map(|(_, log)| log) - .flatten() + .flat_map(|(_, log)| log) .collect() } }; diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index f1de89c559..d521e0dc98 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -760,14 +760,13 @@ impl MetachainRPCServer for MetachainRPCModule { Ok(block_numbers .into_iter() - .map(|block_number| { + .flat_map(|block_number| { self.handler .logs .get_logs(input.clone().address, input.clone().topics, block_number) .into_iter() .map(LogResult::from) }) - .flatten() .collect()) } } From bc94465fffbf453ae918f950e989a44ec5615e9c Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 15:11:00 +0800 Subject: [PATCH 08/12] Avoid downcasting to u128 --- lib/ain-grpc/src/rpc/eth.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index d521e0dc98..d6e67d15fe 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -736,12 +736,18 @@ impl MetachainRPCServer for MetachainRPCModule { let block_numbers = match input.block_hash { None => { // use fromBlock-toBlock - let from_block_number = self.block_number_to_u256(input.from_block).as_u128(); - let to_block_number = self.block_number_to_u256(input.to_block).as_u128(); + let mut block_number = self.block_number_to_u256(input.from_block); + let to_block_number = self.block_number_to_u256(input.to_block); let mut block_numbers = Vec::new(); - for block_number in from_block_number..=to_block_number { - block_numbers.push(U256::from(block_number)) + loop { + block_numbers.push(block_number); + + if block_number == to_block_number { + break; + } else { + block_number += U256::one(); + } } block_numbers From f39573b1cfca165b0fa97fb92676d0c2284cd0d3 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 16:18:32 +0800 Subject: [PATCH 09/12] Check fromBlock <= toBlock --- lib/ain-grpc/src/rpc/eth.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index d6e67d15fe..483f90b83e 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -740,6 +740,14 @@ impl MetachainRPCServer for MetachainRPCModule { let to_block_number = self.block_number_to_u256(input.to_block); let mut block_numbers = Vec::new(); + if block_number > to_block_number { + return Err(Error::Custom(format!( + "fromBlock ({}) > toBlock ({})", + format_u256(block_number), + format_u256(to_block_number) + ))); + } + loop { block_numbers.push(block_number); From 9aa4983c6f0e964534092ba5e0d66e8e16b6146e Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 16:58:30 +0800 Subject: [PATCH 10/12] Fix multiple topic filter --- lib/ain-evm/src/log.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 6208a8dc10..32ce117996 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -86,14 +86,13 @@ impl LogHandler { match topics { None => logs, - Some(topics) => { - logs.into_iter() - .filter(|log| { - let set: HashSet<_> = log.topics.iter().copied().collect(); - topics.iter().all(|item| set.contains(item)) // TODO: multiple vector topics not working - }) - .collect() - } + Some(topics) => logs + .into_iter() + .filter(|log| { + let set: HashSet<_> = log.topics.iter().copied().collect(); + topics.iter().any(|item| set.contains(item)) + }) + .collect(), } } } From 4dcd1f3bbf0f2b7ec2a046123e643d8ecf7bf722 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 17:16:25 +0800 Subject: [PATCH 11/12] Refactor --- lib/ain-evm/src/log.rs | 6 +++--- lib/ain-grpc/src/rpc/eth.rs | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/ain-evm/src/log.rs b/lib/ain-evm/src/log.rs index 32ce117996..2db8484bfa 100644 --- a/lib/ain-evm/src/log.rs +++ b/lib/ain-evm/src/log.rs @@ -57,9 +57,9 @@ impl LogHandler { } } - for (address, logs) in logs_map.into_iter() { - self.storage.put_logs(address, logs, block_number) - } + logs_map + .into_iter() + .for_each(|(address, logs)| self.storage.put_logs(address, logs, block_number)); } // get logs at a block height and filter for topics diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 483f90b83e..affe06fbd1 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -748,14 +748,9 @@ impl MetachainRPCServer for MetachainRPCModule { ))); } - loop { + while block_number <= to_block_number { block_numbers.push(block_number); - - if block_number == to_block_number { - break; - } else { - block_number += U256::one(); - } + block_number += U256::one(); } block_numbers From 210d3285b8450e8c658b41e6d09168f4b64a36c3 Mon Sep 17 00:00:00 2001 From: Shoham Chakraborty Date: Wed, 14 Jun 2023 17:23:26 +0800 Subject: [PATCH 12/12] Refactor --- lib/ain-grpc/src/rpc/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index affe06fbd1..643808feec 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -727,7 +727,7 @@ impl MetachainRPCServer for MetachainRPCModule { } fn get_logs(&self, input: GetLogsRequest) -> RpcResult> { - if input.block_hash.is_some() && (input.to_block.is_some() || input.from_block.is_some()) { + if let (Some(_), Some(_)) = (input.block_hash, input.to_block.or(input.from_block)) { return Err(Error::Custom(String::from( "cannot specify both blockHash and fromBlock/toBlock, choose one or the other", )));