From 819b3f83a2d8ea211d2b297e192663ef389132d5 Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Wed, 22 Feb 2023 17:21:49 +0500 Subject: [PATCH 01/10] ethereum contract send call implementation --- chains/ethereum/server/src/lib.rs | 33 +++++++++-------- chains/ethereum/server/src/utils.rs | 21 ++++++++++- chains/ethereum/tx/Cargo.toml | 2 + chains/ethereum/tx/src/lib.rs | 57 ++++++++++++++++++++++++++++- chains/polkadot/tx/src/lib.rs | 10 ++++- rosetta-client/src/wallet.rs | 29 +++++++++++++++ rosetta-core/src/lib.rs | 2 + rosetta-wallet/src/main.rs | 28 ++++++++++++++ 8 files changed, 163 insertions(+), 19 deletions(-) diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 55b1f435..4619750b 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -1,8 +1,6 @@ use crate::eth_types::GENESIS_BLOCK_INDEX; use crate::utils::{get_block, get_transaction, populate_transactions, EthDetokenizer}; use anyhow::{anyhow, bail, Context, Result}; -use ethers::abi::Abi; -use ethers::contract as ethers_contract; use ethers::prelude::*; use rosetta_config_ethereum::{EthereumMetadata, EthereumMetadataParams}; use rosetta_server::crypto::address::Address; @@ -14,6 +12,7 @@ use rosetta_server::types::{ use rosetta_server::{BlockchainClient, BlockchainConfig}; use serde_json::Value; use std::str::FromStr; +use utils::parse_method; mod eth_types; mod utils; @@ -201,10 +200,6 @@ impl BlockchainClient for EthereumClient { match call_type.to_lowercase().as_str() { "call" => { //process constant call - let abi_str = params["abi"].as_str().context("ABI not found")?; - - let abi: Abi = serde_json::from_str(abi_str).map_err(|err| anyhow!(err))?; - let contract_address = H160::from_str( params["contract_address"] .as_str() @@ -212,23 +207,29 @@ impl BlockchainClient for EthereumClient { ) .map_err(|err| anyhow!(err))?; - let contract = - ethers_contract::Contract::new(contract_address, abi, self.client.clone()); + let function = parse_method(&method)?; + + let bytes: Vec<u8> = function.encode_input(&[])?; + + let tx = Eip1559TransactionRequest { + to: Some(contract_address.into()), + data: Some(bytes.into()), + ..Default::default() + }; - let value: EthDetokenizer = contract - .method(&method, ()) - .map_err(|err| anyhow!(err))? - .call() - .await - .map_err(|err| anyhow!(err))?; + let tx = &tx.into(); + let received_data = self.client.call(tx, None).await?; + + let data: EthDetokenizer = decode_function_data(&function, received_data, false)?; + + let result: Value = serde_json::from_str(&data.json)?; - let result: Value = serde_json::from_str(&value.json)?; return Ok(result); } "storage" => { //process storage call let from = H160::from_str( - params["address"] + params["contract_address"] .as_str() .context("address field not found")?, ) diff --git a/chains/ethereum/server/src/utils.rs b/chains/ethereum/server/src/utils.rs index 834f32b0..706c243c 100644 --- a/chains/ethereum/server/src/utils.rs +++ b/chains/ethereum/server/src/utils.rs @@ -7,7 +7,7 @@ use crate::eth_types::{ }; use anyhow::{anyhow, bail, Context, Result}; use ethers::{ - abi::{Detokenize, InvalidOutputType, Token}, + abi::{Abi, Detokenize, Function, HumanReadableParser, InvalidOutputType, Token}, prelude::*, }; use ethers::{ @@ -729,6 +729,25 @@ fn effective_gas_price(tx: &Transaction, base_fee: Option<U256>) -> Result<U256> Ok(base_fee + tx_max_priority_fee_per_gas) } +pub fn parse_method(method: &str) -> Result<Function> { + let parse_result = HumanReadableParser::parse_function(method); + if parse_result.is_ok() { + parse_result.map_err(|e| anyhow!(e)) + } else { + let json_parse: Result<Abi, serde_json::Error> = + if !(method.starts_with('[') && method.ends_with(']')) { + let abi_str = format!("[{method}]"); + serde_json::from_str(&abi_str) + } else { + serde_json::from_str(method) + }; + let abi: Abi = json_parse.unwrap(); + let (_, functions): (&String, &Vec<Function>) = abi.functions.iter().next().unwrap(); + let function: Function = functions.get(0).unwrap().clone(); + Ok(function) + } +} + #[derive(Serialize)] #[doc(hidden)] pub(crate) struct GethLoggerConfig { diff --git a/chains/ethereum/tx/Cargo.toml b/chains/ethereum/tx/Cargo.toml index a3e2b1f7..463211c9 100644 --- a/chains/ethereum/tx/Cargo.toml +++ b/chains/ethereum/tx/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] anyhow = "1.0.69" ethers-core = "1.0.2" +ethers = "1.0.2" rosetta-config-ethereum = { version = "0.1.0", path = "../config" } rosetta-core = { version = "0.1.0", path = "../../../rosetta-core" } +serde_json = "1.0.70" sha3 = "0.10.6" diff --git a/chains/ethereum/tx/src/lib.rs b/chains/ethereum/tx/src/lib.rs index d43842d9..e731e615 100644 --- a/chains/ethereum/tx/src/lib.rs +++ b/chains/ethereum/tx/src/lib.rs @@ -1,9 +1,12 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; +use ethers::abi::token::{LenientTokenizer, Tokenizer}; +use ethers::abi::{Abi, Function, HumanReadableParser, Param, Token}; use ethers_core::types::{Eip1559TransactionRequest, Signature, H160, U256}; use rosetta_config_ethereum::{EthereumMetadata, EthereumMetadataParams}; use rosetta_core::crypto::address::Address; use rosetta_core::crypto::SecretKey; use rosetta_core::{BlockchainConfig, TransactionBuilder}; +use serde_json::Value; use sha3::{Digest, Keccak256}; #[derive(Default)] @@ -23,6 +26,29 @@ impl TransactionBuilder for EthereumTransactionBuilder { }) } + fn method_call(&self, address: &Address, params: &Value) -> Result<Self::MetadataParams> { + let destination: H160 = address.address().parse()?; + + let method_str = params["method_signature"] + .as_str() + .ok_or(anyhow!("Method signature not found"))?; + let function_params = params["params"] + .as_array() + .ok_or(anyhow!("Params not found"))?; + + let function = parse_method(method_str)?; + + let tokens = tokenize_params(function_params, &function.inputs); + + let bytes: Vec<u8> = function.encode_input(&tokens).map(Into::into)?; + + Ok(EthereumMetadataParams { + destination: destination.0.to_vec(), + amount: [0, 0, 0, 0], + data: bytes, + }) + } + fn create_and_sign( &self, config: &BlockchainConfig, @@ -65,3 +91,32 @@ impl TransactionBuilder for EthereumTransactionBuilder { tx } } + +fn parse_method(method: &str) -> Result<Function> { + let parse_result = HumanReadableParser::parse_function(method); + if parse_result.is_ok() { + parse_result.map_err(|e| anyhow!(e)) + } else { + let json_parse: Result<Abi, serde_json::Error> = + if !(method.starts_with('[') && method.ends_with(']')) { + let abi_str = format!("[{method}]"); + serde_json::from_str(&abi_str) + } else { + serde_json::from_str(method) + }; + let abi: Abi = json_parse.unwrap(); + let (_, functions): (&String, &Vec<Function>) = abi.functions.iter().next().unwrap(); + let function: Function = functions.get(0).unwrap().clone(); + Ok(function) + } +} + +fn tokenize_params(values: &[Value], inputs: &[Param]) -> Vec<Token> { + let value_strings: Vec<String> = values.iter().map(|v| v.as_str().unwrap().into()).collect(); + + inputs + .iter() + .zip(value_strings.iter()) + .map(|(param, arg)| LenientTokenizer::tokenize(¶m.kind, arg).unwrap()) + .collect() +} diff --git a/chains/polkadot/tx/src/lib.rs b/chains/polkadot/tx/src/lib.rs index cea1562b..67559ece 100644 --- a/chains/polkadot/tx/src/lib.rs +++ b/chains/polkadot/tx/src/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use parity_scale_codec::{Compact, Decode, Encode}; use rosetta_config_polkadot::{PolkadotMetadata, PolkadotMetadataParams}; use rosetta_core::crypto::address::Address; @@ -98,6 +98,14 @@ impl TransactionBuilder for PolkadotTransactionBuilder { }) } + fn method_call( + &self, + _address: &Address, + _params: &serde_json::Value, + ) -> Result<Self::MetadataParams> { + bail!("Not Implemented") + } + fn create_and_sign( &self, _config: &BlockchainConfig, diff --git a/rosetta-client/src/wallet.rs b/rosetta-client/src/wallet.rs index 0473d735..908dc8dd 100644 --- a/rosetta-client/src/wallet.rs +++ b/rosetta-client/src/wallet.rs @@ -14,6 +14,7 @@ use anyhow::Result; use futures::{Future, Stream}; use std::pin::Pin; use std::task::{Context, Poll}; +use serde_json::Value; pub enum GenericTransactionBuilder { Ethereum(rosetta_tx_ethereum::EthereumTransactionBuilder), @@ -36,6 +37,17 @@ impl GenericTransactionBuilder { }) } + pub fn method_call( + &self, + method: &Address, + params: &serde_json::Value, + ) -> Result<serde_json::Value> { + Ok(match self { + Self::Ethereum(tx) => serde_json::to_value(tx.method_call(method, params)?)?, + Self::Polkadot(tx) => serde_json::to_value(tx.method_call(method, params)?)?, + }) + } + pub fn create_and_sign( &self, config: &BlockchainConfig, @@ -173,6 +185,23 @@ impl Wallet { self.submit(&transaction).await } + pub async fn method_call( + &self, + account: &AccountIdentifier, + params: Value, + ) -> Result<TransactionIdentifier> { + let address = Address::new(self.config.address_format, account.address.clone()); + let metadata_params = self.tx.method_call(&address, ¶ms)?; + let metadata = self.metadata(metadata_params.clone()).await?; + let transaction = self.tx.create_and_sign( + &self.config, + metadata_params, + metadata, + self.secret_key.secret_key(), + ); + self.submit(&transaction).await + } + pub async fn faucet(&self, faucet_parameter: u128) -> Result<TransactionIdentifier> { let req = AccountFaucetRequest { network_identifier: self.config.network(), diff --git a/rosetta-core/src/lib.rs b/rosetta-core/src/lib.rs index 3cbeffd7..73eb99f1 100644 --- a/rosetta-core/src/lib.rs +++ b/rosetta-core/src/lib.rs @@ -122,6 +122,8 @@ pub trait TransactionBuilder: Default + Sized { fn transfer(&self, address: &Address, amount: u128) -> Result<Self::MetadataParams>; + fn method_call(&self, address: &Address, values: &Value) -> Result<Self::MetadataParams>; + fn create_and_sign( &self, config: &BlockchainConfig, diff --git a/rosetta-wallet/src/main.rs b/rosetta-wallet/src/main.rs index becded74..2e47b9a8 100644 --- a/rosetta-wallet/src/main.rs +++ b/rosetta-wallet/src/main.rs @@ -3,6 +3,7 @@ use clap::Parser; use futures::stream::StreamExt; use rosetta_client::types::AccountIdentifier; use std::path::PathBuf; +use surf::http::convert::json; #[derive(Parser)] pub struct Opts { @@ -26,6 +27,7 @@ pub enum Command { Faucet(FaucetOpts), Transfer(TransferOpts), Transactions, + MethodCall(MethodCallOpts), } #[derive(Parser)] @@ -39,6 +41,14 @@ pub struct FaucetOpts { pub amount: u128, } +#[derive(Parser)] +pub struct MethodCallOpts { + pub address: String, + pub method_signature: String, + #[clap(value_delimiter = ' ')] + pub params: Vec<String>, +} + #[async_std::main] async fn main() -> Result<()> { tracing_subscriber::fmt::init(); @@ -148,6 +158,24 @@ async fn main() -> Result<()> { println!("No transactions found"); } } + Command::MethodCall(MethodCallOpts { + address, + method_signature, + params, + }) => { + let acc_identifier = AccountIdentifier { + address, + sub_account: None, + metadata: None, + }; + let params = json!({ + "method_signature": method_signature, + "params": params + }); + + let tx = wallet.method_call(&acc_identifier, params).await?; + println!("Transaction hash: {:?}", tx.hash); + } } Ok(()) } From 3ee011244ce28f424b4914059fe9a247fb65a148 Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Wed, 22 Feb 2023 19:06:29 +0500 Subject: [PATCH 02/10] rebasinc to account --- rosetta-client/src/wallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rosetta-client/src/wallet.rs b/rosetta-client/src/wallet.rs index 908dc8dd..5f51d37e 100644 --- a/rosetta-client/src/wallet.rs +++ b/rosetta-client/src/wallet.rs @@ -12,9 +12,9 @@ use crate::types::{ use crate::{BlockchainConfig, Client, TransactionBuilder}; use anyhow::Result; use futures::{Future, Stream}; +use serde_json::Value; use std::pin::Pin; use std::task::{Context, Poll}; -use serde_json::Value; pub enum GenericTransactionBuilder { Ethereum(rosetta_tx_ethereum::EthereumTransactionBuilder), From 0eab3d840d3cfd1ae4d57c4b8cb5b85e9916e844 Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Wed, 22 Feb 2023 19:09:26 +0500 Subject: [PATCH 03/10] clippy fixed --- chains/polkadot/server/src/block.rs | 4 ++-- rosetta-server/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chains/polkadot/server/src/block.rs b/chains/polkadot/server/src/block.rs index e2c69fca..a38299c9 100644 --- a/chains/polkadot/server/src/block.rs +++ b/chains/polkadot/server/src/block.rs @@ -38,7 +38,7 @@ pub async fn get_transaction<T: Config<Hash = H256>>( let op_neg_amount: Option<Amount> = event_parsed_data.amount.as_ref().map(|amount| Amount { - value: format!("-{}", amount), + value: format!("-{amount}"), currency: config.currency(), metadata: None, }); @@ -99,7 +99,7 @@ fn get_operation_data( let pallet_name = event.pallet_name(); let event_name = event.variant_name(); - let call_type = format!("{}.{}", pallet_name, event_name); + let call_type = format!("{pallet_name}.{event_name}"); let event_fields = event.field_values()?; let parsed_data = match event_fields { diff --git a/rosetta-server/src/lib.rs b/rosetta-server/src/lib.rs index 49900efb..ae9168be 100644 --- a/rosetta-server/src/lib.rs +++ b/rosetta-server/src/lib.rs @@ -113,7 +113,7 @@ fn ok<T: serde::Serialize>(t: &T) -> tide::Result { fn err(err: &anyhow::Error) -> tide::Result { let error = crate::types::Error { code: 500, - message: format!("{}", err), + message: format!("{err}"), description: None, retriable: false, details: None, From 1360a372c452e1c9c2c3e7bcfc666206b88b011a Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Wed, 1 Mar 2023 02:19:11 +0500 Subject: [PATCH 04/10] Features: Storage proof implementation Testcase fixed for ethereum Code improvement --- chains/ethereum/server/src/lib.rs | 83 ++++++++++-- chains/ethereum/server/src/proof.rs | 194 ++++++++++++++++++++++++++++ chains/ethereum/server/src/utils.rs | 122 ++++++----------- rosetta-server/src/indexer.rs | 25 ++-- rosetta-server/src/lib.rs | 1 + 5 files changed, 319 insertions(+), 106 deletions(-) create mode 100644 chains/ethereum/server/src/proof.rs diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 4619750b..36936159 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -1,7 +1,10 @@ use crate::eth_types::GENESIS_BLOCK_INDEX; use crate::utils::{get_block, get_transaction, populate_transactions, EthDetokenizer}; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; use ethers::prelude::*; +use ethers::utils::keccak256; +use ethers::utils::rlp::Encodable; +use proof::verify_proof; use rosetta_config_ethereum::{EthereumMetadata, EthereumMetadataParams}; use rosetta_server::crypto::address::Address; use rosetta_server::crypto::PublicKey; @@ -10,11 +13,12 @@ use rosetta_server::types::{ TransactionIdentifier, }; use rosetta_server::{BlockchainClient, BlockchainConfig}; -use serde_json::Value; +use serde_json::{json, Value}; use std::str::FromStr; -use utils::parse_method; +use utils::{hex_str_to_bytes, parse_method}; mod eth_types; +mod proof; mod utils; pub struct EthereumClient { @@ -31,7 +35,10 @@ impl BlockchainClient for EthereumClient { async fn new(network: &str, addr: &str) -> Result<Self> { let config = rosetta_config_ethereum::config(network)?; let client = Provider::<Http>::try_from(format!("http://{addr}"))?; - let genesis = client.get_block(0).await?.unwrap(); + let genesis = client + .get_block(0) + .await? + .context("Failed to get genesis block")?; let genesis_block = BlockIdentifier { index: 0, hash: hex::encode(genesis.hash.as_ref().unwrap()), @@ -111,8 +118,7 @@ impl BlockchainClient for EthereumClient { let from: H160 = public_key .to_address(self.config().address_format) .address() - .parse() - .unwrap(); + .parse()?; let to = H160::from_slice(&options.destination); let chain_id = self.client.get_chainid().await?; let nonce = self.client.get_transaction_count(from, None).await?; @@ -135,12 +141,13 @@ impl BlockchainClient for EthereumClient { async fn submit(&self, transaction: &[u8]) -> Result<Vec<u8>> { let tx = transaction.to_vec().into(); + Ok(self .client .send_raw_transaction(Bytes(tx)) .await? .await? - .unwrap() + .context("Failed to get transaction receipt")? .transaction_hash .0 .to_vec()) @@ -204,8 +211,7 @@ impl BlockchainClient for EthereumClient { params["contract_address"] .as_str() .context("contact address not found")?, - ) - .map_err(|err| anyhow!(err))?; + )?; let function = parse_method(&method)?; @@ -232,12 +238,10 @@ impl BlockchainClient for EthereumClient { params["contract_address"] .as_str() .context("address field not found")?, - ) - .map_err(|err| anyhow!(err))?; + )?; let location = - H256::from_str(params["position"].as_str().context("position not found")?) - .map_err(|err| anyhow!(err))?; + H256::from_str(params["position"].as_str().context("position not found")?)?; let block_num = params["block_number"] .as_u64() @@ -249,6 +253,47 @@ impl BlockchainClient for EthereumClient { .await?; return Ok(Value::String(format!("{storage_check:#?}",))); } + "storage_proof" => { + let from = H160::from_str( + params["contract_address"] + .as_str() + .context("address field not found")?, + )?; + + let location = + H256::from_str(params["position"].as_str().context("position not found")?)?; + + let block_num = params["block_number"] + .as_u64() + .map(|block_num| BlockId::Number(block_num.into())); + + let proof_data = self + .client + .get_proof(from, vec![location], block_num) + .await?; + + //process verfiicatin of proof + let storage_hash = proof_data.storage_hash; + let storage_proof = proof_data.storage_proof.first().context("No proof found")?; + + let key = hex_str_to_bytes(&hex::encode(storage_proof.key))?; + let key_hash = keccak256(key); + let encoded_val = storage_proof.value.rlp_bytes().to_vec(); + + let is_valid = verify_proof( + &storage_proof.proof, + storage_hash.as_bytes(), + &key_hash.to_vec(), + &encoded_val, + ); + + let result = serde_json::to_value(&proof_data)?; + + return Ok(json!({ + "proof": result, + "isValid": is_valid + })); + } _ => { bail!("request type not supported") } @@ -289,4 +334,16 @@ mod tests { let config = rosetta_config_ethereum::config("dev")?; rosetta_server::tests::construction(config).await } + + #[tokio::test] + async fn test_find_transaction() -> Result<()> { + let config = rosetta_config_ethereum::config("dev")?; + rosetta_server::tests::find_transaction(config).await + } + + #[tokio::test] + async fn test_list_transactions() -> Result<()> { + let config = rosetta_config_ethereum::config("dev")?; + rosetta_server::tests::list_transactions(config).await + } } diff --git a/chains/ethereum/server/src/proof.rs b/chains/ethereum/server/src/proof.rs new file mode 100644 index 00000000..d111a540 --- /dev/null +++ b/chains/ethereum/server/src/proof.rs @@ -0,0 +1,194 @@ +use ethers::types::{Bytes, EIP1186ProofResponse}; +use ethers::utils::keccak256; +use ethers::utils::rlp::{decode_list, RlpStream}; + +pub fn verify_proof(proof: &Vec<Bytes>, root: &[u8], path: &Vec<u8>, value: &Vec<u8>) -> bool { + let mut expected_hash = root.to_vec(); + let mut path_offset = 0; + + for (i, node) in proof.iter().enumerate() { + if expected_hash != keccak256(node).to_vec() { + return false; + } + + let node_list: Vec<Vec<u8>> = decode_list(node); + + if node_list.len() == 17 { + if i == proof.len() - 1 { + // exclusion proof + let nibble = get_nibble(path, path_offset); + let node = &node_list[nibble as usize]; + + if node.is_empty() && is_empty_value(value) { + return true; + } + } else { + let nibble = get_nibble(path, path_offset); + expected_hash = node_list[nibble as usize].clone(); + + path_offset += 1; + } + } else if node_list.len() == 2 { + if i == proof.len() - 1 { + // exclusion proof + if !paths_match(&node_list[0], skip_length(&node_list[0]), path, path_offset) + && is_empty_value(value) + { + return true; + } + + // inclusion proof + if &node_list[1] == value { + return paths_match( + &node_list[0], + skip_length(&node_list[0]), + path, + path_offset, + ); + } + } else { + let node_path = &node_list[0]; + let prefix_length = shared_prefix_length(path, path_offset, node_path); + if prefix_length < node_path.len() * 2 - skip_length(node_path) { + // The proof shows a divergent path, but we're not + // at the end of the proof, so something's wrong. + return false; + } + path_offset += prefix_length; + expected_hash = node_list[1].clone(); + } + } else { + return false; + } + } + + false +} + +fn paths_match(p1: &Vec<u8>, s1: usize, p2: &Vec<u8>, s2: usize) -> bool { + let len1 = p1.len() * 2 - s1; + let len2 = p2.len() * 2 - s2; + + if len1 != len2 { + return false; + } + + for offset in 0..len1 { + let n1 = get_nibble(p1, s1 + offset); + let n2 = get_nibble(p2, s2 + offset); + + if n1 != n2 { + return false; + } + } + + true +} + +#[allow(dead_code)] +fn get_rest_path(p: &Vec<u8>, s: usize) -> String { + let mut ret = String::new(); + for i in s..p.len() * 2 { + let n = get_nibble(p, i); + ret += &format!("{n:01x}"); + } + ret +} + +fn is_empty_value(value: &Vec<u8>) -> bool { + let mut stream = RlpStream::new(); + stream.begin_list(4); + stream.append_empty_data(); + stream.append_empty_data(); + let empty_storage_hash = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"; + stream.append(&hex::decode(empty_storage_hash).unwrap()); + let empty_code_hash = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; + stream.append(&hex::decode(empty_code_hash).unwrap()); + let empty_account = stream.out(); + + let is_empty_slot = value.len() == 1 && value[0] == 0x80; + let is_empty_account = value == &empty_account; + is_empty_slot || is_empty_account +} + +fn shared_prefix_length(path: &Vec<u8>, path_offset: usize, node_path: &Vec<u8>) -> usize { + let skip_length = skip_length(node_path); + + let len = std::cmp::min( + node_path.len() * 2 - skip_length, + path.len() * 2 - path_offset, + ); + let mut prefix_len = 0; + + for i in 0..len { + let path_nibble = get_nibble(path, i + path_offset); + let node_path_nibble = get_nibble(node_path, i + skip_length); + + if path_nibble == node_path_nibble { + prefix_len += 1; + } else { + break; + } + } + + prefix_len +} + +fn skip_length(node: &Vec<u8>) -> usize { + if node.is_empty() { + return 0; + } + + let nibble = get_nibble(node, 0); + match nibble { + 0 => 2, + 1 => 1, + 2 => 2, + 3 => 1, + _ => 0, + } +} + +fn get_nibble(path: &[u8], offset: usize) -> u8 { + let byte = path[offset / 2]; + if offset % 2 == 0 { + byte >> 4 + } else { + byte & 0xF + } +} + +pub fn _encode_account(proof: &EIP1186ProofResponse) -> Vec<u8> { + let mut stream = RlpStream::new_list(4); + stream.append(&proof.nonce); + stream.append(&proof.balance); + stream.append(&proof.storage_hash); + stream.append(&proof.code_hash); + let encoded = stream.out(); + encoded.to_vec() +} + +#[cfg(test)] +mod tests { + use crate::proof::shared_prefix_length; + + #[tokio::test] + async fn test_shared_prefix_length() { + // We compare the path starting from the 6th nibble i.e. the 6 in 0x6f + let path: Vec<u8> = vec![0x12, 0x13, 0x14, 0x6f, 0x6c, 0x64, 0x21]; + let path_offset = 6; + // Our node path matches only the first 5 nibbles of the path + let node_path: Vec<u8> = vec![0x6f, 0x6c, 0x63, 0x21]; + let shared_len = shared_prefix_length(&path, path_offset, &node_path); + assert_eq!(shared_len, 5); + + // Now we compare the path starting from the 5th nibble i.e. the 4 in 0x14 + let path: Vec<u8> = vec![0x12, 0x13, 0x14, 0x6f, 0x6c, 0x64, 0x21]; + let path_offset = 5; + // Our node path matches only the first 7 nibbles of the path + // Note the first nibble is 1, so we skip 1 nibble + let node_path: Vec<u8> = vec![0x14, 0x6f, 0x6c, 0x64, 0x11]; + let shared_len = shared_prefix_length(&path, path_offset, &node_path); + assert_eq!(shared_len, 7); + } +} diff --git a/chains/ethereum/server/src/utils.rs b/chains/ethereum/server/src/utils.rs index 706c243c..1827ecbe 100644 --- a/chains/ethereum/server/src/utils.rs +++ b/chains/ethereum/server/src/utils.rs @@ -19,8 +19,7 @@ use rosetta_server::types::{ AccountIdentifier, Amount, BlockIdentifier, Currency, Operation, OperationIdentifier, PartialBlockIdentifier, TransactionIdentifier, }; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::json; use std::collections::HashMap; use std::str::FromStr; @@ -33,7 +32,7 @@ pub async fn get_block( client: &Provider<Http>, ) -> Result<(Block<Transaction>, Vec<LoadedTransaction>, Vec<Block<H256>>)> { let bl_id = if let Some(hash) = block.hash.as_ref() { - let h256 = H256::from_str(hash).map_err(|err| anyhow!(err))?; + let h256 = H256::from_str(hash)?; BlockId::Hash(h256) } else if let Some(index) = block.index { let ehters_u64 = U64::from(index); @@ -45,8 +44,7 @@ pub async fn get_block( let block_eth = client .get_block_with_txs(bl_id) - .await - .map_err(|err| anyhow!(err))? + .await? .context("Block not found")?; let block_number = block_eth @@ -76,7 +74,7 @@ pub async fn get_block( traces.extend(block_traces.0); } - let mut loaded_transaction_vec = vec![]; + let mut loaded_transactions = vec![]; for (idx, transaction) in block_transactions.iter().enumerate() { let tx_receipt = &receipts[idx]; @@ -96,15 +94,15 @@ pub async fn get_block( }; if !add_traces { - loaded_transaction_vec.push(loaded_tx); + loaded_transactions.push(loaded_tx); continue; } loaded_tx.trace = Some(traces[idx].result.clone()); - loaded_transaction_vec.push(loaded_tx); + loaded_transactions.push(loaded_tx); } - Ok((block_eth, loaded_transaction_vec, uncles)) + Ok((block_eth, loaded_transactions, uncles)) } pub async fn get_transaction( @@ -113,11 +111,10 @@ pub async fn get_transaction( client: &Provider<Http>, currency: &Currency, ) -> Result<rosetta_types::Transaction> { - let tx_hash = H256::from_str(hash).map_err(|err| anyhow!(err))?; + let tx_hash = H256::from_str(hash)?; let transaction = client .get_transaction(tx_hash) - .await - .map_err(|err| anyhow!(err))? + .await? .context("Unable to get transaction")?; let ehters_u64 = U64::from(block_identifier.index); @@ -126,8 +123,7 @@ pub async fn get_transaction( let block = client .get_block(block_num) - .await - .map_err(|err| anyhow!(err))? + .await? .context("Block not found")?; let block_hash = block.hash.context("Block hash not found")?; @@ -135,8 +131,7 @@ pub async fn get_transaction( let tx_receipt = client .get_transaction_receipt(tx_hash) - .await - .map_err(|err| anyhow!(err))? + .await? .context("Transaction receipt not found")?; if tx_receipt @@ -216,7 +211,7 @@ pub async fn populate_transaction( let transaction = rosetta_types::Transaction { transaction_identifier: TransactionIdentifier { - hash: format!("{:?}", tx.transaction.hash), + hash: hex::encode(tx.transaction.hash), }, operations, related_transactions: None, @@ -235,17 +230,16 @@ pub async fn get_uncles( uncles: &[H256], client: &Provider<Http>, ) -> Result<Vec<Block<H256>>> { - let mut uncles_vec = vec![]; + let mut uncles_data = vec![]; for (idx, _) in uncles.iter().enumerate() { let index = U64::from(idx); let uncle_response = client .get_uncle(block_index, index) - .await - .map_err(|err| anyhow!("{err}"))? + .await? .context("Uncle block now found")?; - uncles_vec.push(uncle_response); + uncles_data.push(uncle_response); } - Ok(uncles_vec) + Ok(uncles_data) } pub async fn get_block_receipts( @@ -258,8 +252,7 @@ pub async fn get_block_receipts( let tx_hash = tx.hash; let receipt = client .get_transaction_receipt(tx_hash) - .await - .map_err(|err| anyhow!("{err}"))? + .await? .context("Transaction receipt not found")?; if receipt @@ -288,8 +281,7 @@ pub async fn get_block_traces( let traces: ResultGethExecTraces = client .request("debug_traceBlockByHash", [hash_serialize, cfg]) - .await - .map_err(|err| anyhow!(err))?; + .await?; Ok(traces) } @@ -304,8 +296,7 @@ async fn get_transaction_trace(hash: &H256, client: &Provider<Http>) -> Result<T let traces: Trace = client .request("debug_traceTransaction", [hash_serialize, cfg]) - .await - .map_err(|err| anyhow!(err))?; + .await?; Ok(traces) } @@ -317,7 +308,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result tx.fee_amount }; - let mut operations_vec = vec![]; + let mut operations = vec![]; let first_op = Operation { operation_identifier: OperationIdentifier { @@ -366,8 +357,8 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result metadata: None, }; - operations_vec.push(first_op); - operations_vec.push(second_op); + operations.push(first_op); + operations.push(second_op); if let Some(fee_burned) = tx.fee_burned { let burned_operation = Operation { @@ -392,11 +383,9 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result metadata: None, }; - operations_vec.push(burned_operation); - Ok(operations_vec) - } else { - Ok(operations_vec) + operations.push(burned_operation); } + Ok(operations) } pub fn get_traces_operations( @@ -718,9 +707,7 @@ fn effective_gas_price(tx: &Transaction, base_fee: Option<U256>) -> Result<U256> .transaction_type .context("transaction type is not available")?; let tx_gas_price = tx.gas_price.context("gas price is not available")?; - let tx_max_priority_fee_per_gas = tx - .max_priority_fee_per_gas - .context("max priority fee per gas is not available")?; + let tx_max_priority_fee_per_gas = tx.max_priority_fee_per_gas.unwrap_or(U256::from(0)); if tx_transaction_type.as_u64() != 2 { return Ok(tx_gas_price); @@ -741,58 +728,25 @@ pub fn parse_method(method: &str) -> Result<Function> { } else { serde_json::from_str(method) }; - let abi: Abi = json_parse.unwrap(); - let (_, functions): (&String, &Vec<Function>) = abi.functions.iter().next().unwrap(); - let function: Function = functions.get(0).unwrap().clone(); + let abi: Abi = json_parse?; + let (_, functions): (&String, &Vec<Function>) = abi + .functions + .iter() + .next() + .context("No functions found in abi")?; + let function: Function = functions + .get(0) + .context("Abi function list is empty")? + .clone(); Ok(function) } } -#[derive(Serialize)] -#[doc(hidden)] -pub(crate) struct GethLoggerConfig { - /// enable memory capture - #[serde(rename = "EnableMemory")] - enable_memory: bool, - /// disable stack capture - #[serde(rename = "DisableStack")] - disable_stack: bool, - /// disable storage capture - #[serde(rename = "DisableStorage")] - disable_storage: bool, - /// enable return data capture - #[serde(rename = "EnableReturnData")] - enable_return_data: bool, -} - -impl Default for GethLoggerConfig { - fn default() -> Self { - Self { - enable_memory: false, - disable_stack: false, - disable_storage: false, - enable_return_data: true, - } - } -} - -#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] -pub struct GethExecTrace { - /// Used gas - pub gas: Gas, - /// True when the transaction has failed. - pub failed: bool, - /// Return value of execution which is a hex encoded byte array - #[serde(rename = "returnValue")] - pub return_value: String, - /// Vector of geth execution steps of the trace. - #[serde(rename = "structLogs")] - pub struct_logs: Vec<Value>, +pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> { + let stripped = s.strip_prefix("0x").unwrap_or(s); + Ok(hex::decode(stripped)?) } -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Gas(pub u64); - pub struct LoadedTransaction { pub transaction: Transaction, pub from: H160, diff --git a/rosetta-server/src/indexer.rs b/rosetta-server/src/indexer.rs index 21c02b4a..3ebf50a4 100644 --- a/rosetta-server/src/indexer.rs +++ b/rosetta-server/src/indexer.rs @@ -105,9 +105,10 @@ impl AccountTable { } pub fn get(&self, account: &AccountIdentifier) -> impl Iterator<Item = Result<TransactionRef>> { - let address_len = account.address.as_bytes().len(); + let address = preprocess_acc_address(&account.address); + let address_len = address.as_bytes().len(); self.tree - .scan_prefix(account.address.as_bytes()) + .scan_prefix(address.to_lowercase().as_bytes()) .keys() .map(move |key| Ok(TransactionRef::from_bytes(&key?[address_len..]))) } @@ -118,10 +119,8 @@ impl AccountTable { } pub fn len(&self, account: &AccountIdentifier) -> usize { - self.tree - .scan_prefix(account.address.as_bytes()) - .keys() - .count() + let address = preprocess_acc_address(&account.address); + self.tree.scan_prefix(address.as_bytes()).keys().count() } #[allow(unused)] @@ -132,13 +131,21 @@ impl AccountTable { } fn account_table_key(account: &AccountIdentifier, tx: &TransactionRef) -> Vec<u8> { - let address_len = account.address.as_bytes().len(); + let address = preprocess_acc_address(&account.address); + let address_len = address.as_bytes().len(); let mut key = Vec::with_capacity(address_len + 12); - key.extend(account.address.as_bytes()); + key.extend(address.as_bytes()); key.extend(tx.to_bytes()); key } +fn preprocess_acc_address(address: &str) -> String { + address + .strip_prefix("0x") + .unwrap_or(&address) + .to_lowercase() +} + #[derive(Clone)] pub struct Indexer<C: BlockchainClient> { transaction_table: TransactionTable, @@ -204,7 +211,7 @@ impl<C: BlockchainClient> Indexer<C> { pub async fn sync(&self) -> Result<()> { let synced_height = self.transaction_table.height()?; let current_height = self.client.current_block().await?.index; - for block_index in (synced_height + 1)..current_height { + for block_index in (synced_height + 1)..current_height + 1 { let block = self.block_by_index(block_index).await?; for (transaction_index, transaction) in block.transactions.iter().enumerate() { let tx = TransactionRef::new(block_index, transaction_index as _); diff --git a/rosetta-server/src/lib.rs b/rosetta-server/src/lib.rs index ae9168be..6662efc1 100644 --- a/rosetta-server/src/lib.rs +++ b/rosetta-server/src/lib.rs @@ -537,6 +537,7 @@ pub mod tests { alice.transfer(bob.account(), value).await?; alice.transfer(bob.account(), value).await?; + tokio::time::sleep(Duration::from_secs(11)).await; let mut stream = bob.transactions(1); let mut count = 0; while let Some(res) = stream.next().await { From 9f44eee8f14256c63fe147751e47f1a3a183781b Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Wed, 1 Mar 2023 02:23:31 +0500 Subject: [PATCH 05/10] clippy fix --- rosetta-server/src/indexer.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rosetta-server/src/indexer.rs b/rosetta-server/src/indexer.rs index 3ebf50a4..e89c40b8 100644 --- a/rosetta-server/src/indexer.rs +++ b/rosetta-server/src/indexer.rs @@ -140,10 +140,7 @@ fn account_table_key(account: &AccountIdentifier, tx: &TransactionRef) -> Vec<u8 } fn preprocess_acc_address(address: &str) -> String { - address - .strip_prefix("0x") - .unwrap_or(&address) - .to_lowercase() + address.strip_prefix("0x").unwrap_or(address).to_lowercase() } #[derive(Clone)] From 79a44ede2fb6dd677235e1ca8a3e91995614186e Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Thu, 2 Mar 2023 01:27:13 +0500 Subject: [PATCH 06/10] reviews fixes --- chains/ethereum/server/src/utils.rs | 22 ++++++++++++++-------- rosetta-server/src/indexer.rs | 20 ++++++++------------ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/chains/ethereum/server/src/utils.rs b/chains/ethereum/server/src/utils.rs index 1827ecbe..76aa33c9 100644 --- a/chains/ethereum/server/src/utils.rs +++ b/chains/ethereum/server/src/utils.rs @@ -9,6 +9,7 @@ use anyhow::{anyhow, bail, Context, Result}; use ethers::{ abi::{Abi, Detokenize, Function, HumanReadableParser, InvalidOutputType, Token}, prelude::*, + utils::to_checksum, }; use ethers::{ providers::{Http, Middleware, Provider}, @@ -319,7 +320,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: format!("{:?}", tx.from), + address: parse_address(format!("{:?}", tx.from))?, sub_account: None, metadata: None, }), @@ -344,7 +345,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: format!("{:?}", tx.miner), + address: parse_address(format!("{:?}", tx.miner))?, sub_account: None, metadata: None, }), @@ -370,7 +371,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: format!("{:?}", tx.from), + address: parse_address(format!("{:?}", tx.from))?, sub_account: None, metadata: None, }), @@ -431,7 +432,7 @@ pub fn get_traces_operations( r#type: trace.trace_type.clone(), status: Some(operation_status.into()), account: Some(AccountIdentifier { - address: from.clone(), + address: parse_address(from.clone())?, sub_account: None, metadata: None, }), @@ -487,7 +488,7 @@ pub fn get_traces_operations( r#type: trace.trace_type, status: Some(operation_status.into()), account: Some(AccountIdentifier { - address: to.clone(), + address: parse_address(to.clone())?, sub_account: None, metadata: None, }), @@ -530,7 +531,7 @@ pub fn get_traces_operations( r#type: DESTRUCT_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: k.clone(), + address: parse_address(k.clone())?, sub_account: None, metadata: None, }), @@ -597,7 +598,7 @@ pub fn get_mining_rewards( r#type: MINING_REWARD_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: format!("{miner:?}"), + address: parse_address(format!("{miner:?}"))?, sub_account: None, metadata: None, }), @@ -627,7 +628,7 @@ pub fn get_mining_rewards( r#type: UNCLE_REWARD_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: format!("{uncle_miner:?}"), + address: parse_address(format!("{uncle_miner:?}"))?, sub_account: None, metadata: None, }), @@ -747,6 +748,11 @@ pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> { Ok(hex::decode(stripped)?) } +pub fn parse_address(address: String) -> Result<String> { + let ethereum_address = H160::from_str(&address)?; + Ok(to_checksum(ðereum_address, None)) +} + pub struct LoadedTransaction { pub transaction: Transaction, pub from: H160, diff --git a/rosetta-server/src/indexer.rs b/rosetta-server/src/indexer.rs index e89c40b8..c9ee783a 100644 --- a/rosetta-server/src/indexer.rs +++ b/rosetta-server/src/indexer.rs @@ -105,10 +105,9 @@ impl AccountTable { } pub fn get(&self, account: &AccountIdentifier) -> impl Iterator<Item = Result<TransactionRef>> { - let address = preprocess_acc_address(&account.address); - let address_len = address.as_bytes().len(); + let address_len = account.address.as_bytes().len(); self.tree - .scan_prefix(address.to_lowercase().as_bytes()) + .scan_prefix(account.address.as_bytes()) .keys() .map(move |key| Ok(TransactionRef::from_bytes(&key?[address_len..]))) } @@ -119,8 +118,10 @@ impl AccountTable { } pub fn len(&self, account: &AccountIdentifier) -> usize { - let address = preprocess_acc_address(&account.address); - self.tree.scan_prefix(address.as_bytes()).keys().count() + self.tree + .scan_prefix(account.address.as_bytes()) + .keys() + .count() } #[allow(unused)] @@ -131,18 +132,13 @@ impl AccountTable { } fn account_table_key(account: &AccountIdentifier, tx: &TransactionRef) -> Vec<u8> { - let address = preprocess_acc_address(&account.address); - let address_len = address.as_bytes().len(); + let address_len = account.address.as_bytes().len(); let mut key = Vec::with_capacity(address_len + 12); - key.extend(address.as_bytes()); + key.extend(account.address.as_bytes()); key.extend(tx.to_bytes()); key } -fn preprocess_acc_address(address: &str) -> String { - address.strip_prefix("0x").unwrap_or(address).to_lowercase() -} - #[derive(Clone)] pub struct Indexer<C: BlockchainClient> { transaction_table: TransactionTable, From 56de95be744e4f799d1113b84b146cae5549af4c Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Thu, 2 Mar 2023 16:41:43 +0500 Subject: [PATCH 07/10] fixing checksum junk code --- chains/ethereum/server/src/lib.rs | 6 ++++-- chains/ethereum/server/src/utils.rs | 30 ++++++++++------------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 36936159..5f531f11 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -15,7 +15,7 @@ use rosetta_server::types::{ use rosetta_server::{BlockchainClient, BlockchainConfig}; use serde_json::{json, Value}; use std::str::FromStr; -use utils::{hex_str_to_bytes, parse_method}; +use utils::parse_method; mod eth_types; mod proof; @@ -276,7 +276,9 @@ impl BlockchainClient for EthereumClient { let storage_hash = proof_data.storage_hash; let storage_proof = proof_data.storage_proof.first().context("No proof found")?; - let key = hex_str_to_bytes(&hex::encode(storage_proof.key))?; + let encoded_key = hex::encode(storage_proof.key); + let stripped_key = encoded_key.strip_prefix("0x").unwrap_or(&encoded_key); + let key = hex::decode(stripped_key)?; let key_hash = keccak256(key); let encoded_val = storage_proof.value.rlp_bytes().to_vec(); diff --git a/chains/ethereum/server/src/utils.rs b/chains/ethereum/server/src/utils.rs index 76aa33c9..a6e50235 100644 --- a/chains/ethereum/server/src/utils.rs +++ b/chains/ethereum/server/src/utils.rs @@ -320,7 +320,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(format!("{:?}", tx.from))?, + address: to_checksum(&tx.from, None), sub_account: None, metadata: None, }), @@ -345,7 +345,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(format!("{:?}", tx.miner))?, + address: to_checksum(&tx.miner, None), sub_account: None, metadata: None, }), @@ -371,7 +371,7 @@ pub fn get_fee_operations(tx: &LoadedTransaction, currency: &Currency) -> Result r#type: FEE_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(format!("{:?}", tx.from))?, + address: to_checksum(&tx.from, None), sub_account: None, metadata: None, }), @@ -419,8 +419,8 @@ pub fn get_traces_operations( should_add = false; } - let from = format!("{:?}", trace.from); - let to = format!("{:?}", trace.to); + let from = to_checksum(&trace.from, None); + let to = to_checksum(&trace.to, None); if should_add { let mut from_operation = Operation { @@ -432,7 +432,7 @@ pub fn get_traces_operations( r#type: trace.trace_type.clone(), status: Some(operation_status.into()), account: Some(AccountIdentifier { - address: parse_address(from.clone())?, + address: from.clone(), sub_account: None, metadata: None, }), @@ -488,7 +488,7 @@ pub fn get_traces_operations( r#type: trace.trace_type, status: Some(operation_status.into()), account: Some(AccountIdentifier { - address: parse_address(to.clone())?, + address: to.clone(), sub_account: None, metadata: None, }), @@ -531,7 +531,7 @@ pub fn get_traces_operations( r#type: DESTRUCT_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(k.clone())?, + address: to_checksum(&H160::from_str(k)?, None), sub_account: None, metadata: None, }), @@ -598,7 +598,7 @@ pub fn get_mining_rewards( r#type: MINING_REWARD_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(format!("{miner:?}"))?, + address: to_checksum(miner, None), sub_account: None, metadata: None, }), @@ -628,7 +628,7 @@ pub fn get_mining_rewards( r#type: UNCLE_REWARD_OP_TYPE.into(), status: Some(SUCCESS_STATUS.into()), account: Some(AccountIdentifier { - address: parse_address(format!("{uncle_miner:?}"))?, + address: to_checksum(&uncle_miner, None), sub_account: None, metadata: None, }), @@ -743,16 +743,6 @@ pub fn parse_method(method: &str) -> Result<Function> { } } -pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> { - let stripped = s.strip_prefix("0x").unwrap_or(s); - Ok(hex::decode(stripped)?) -} - -pub fn parse_address(address: String) -> Result<String> { - let ethereum_address = H160::from_str(&address)?; - Ok(to_checksum(ðereum_address, None)) -} - pub struct LoadedTransaction { pub transaction: Transaction, pub from: H160, From 948f82d97bdf276043edab13d8ece3644eea1b94 Mon Sep 17 00:00:00 2001 From: David Craven <david@craven.ch> Date: Thu, 2 Mar 2023 14:53:29 +0100 Subject: [PATCH 08/10] Update chains/ethereum/server/src/lib.rs --- chains/ethereum/server/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 5f531f11..e439d41c 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -276,9 +276,7 @@ impl BlockchainClient for EthereumClient { let storage_hash = proof_data.storage_hash; let storage_proof = proof_data.storage_proof.first().context("No proof found")?; - let encoded_key = hex::encode(storage_proof.key); - let stripped_key = encoded_key.strip_prefix("0x").unwrap_or(&encoded_key); - let key = hex::decode(stripped_key)?; + let key = &storage_proof.key; let key_hash = keccak256(key); let encoded_val = storage_proof.value.rlp_bytes().to_vec(); From 886d481b1ed58c1c936427e5246aa91a2b370019 Mon Sep 17 00:00:00 2001 From: Haider-Ali-DS <haiderali.tech_786@outlook.com> Date: Thu, 2 Mar 2023 19:08:37 +0500 Subject: [PATCH 09/10] fmt fix --- chains/ethereum/server/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chains/ethereum/server/src/lib.rs b/chains/ethereum/server/src/lib.rs index 5854b432..8d2b546c 100644 --- a/chains/ethereum/server/src/lib.rs +++ b/chains/ethereum/server/src/lib.rs @@ -1,5 +1,7 @@ use crate::eth_types::GENESIS_BLOCK_INDEX; -use crate::utils::{get_block, get_transaction, parse_method, populate_transactions, EthDetokenizer}; +use crate::utils::{ + get_block, get_transaction, parse_method, populate_transactions, EthDetokenizer, +}; use anyhow::{bail, Context, Result}; use ethers::prelude::*; use ethers::utils::keccak256; From 340b4779472b36671aa7d27fafcf3436644802b1 Mon Sep 17 00:00:00 2001 From: David Craven <david@craven.ch> Date: Thu, 2 Mar 2023 17:18:44 +0100 Subject: [PATCH 10/10] Fix clippy warnings. --- chains/ethereum/server/src/utils.rs | 2 +- chains/ethereum/tx/src/lib.rs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/chains/ethereum/server/src/utils.rs b/chains/ethereum/server/src/utils.rs index a6e50235..8f3555e1 100644 --- a/chains/ethereum/server/src/utils.rs +++ b/chains/ethereum/server/src/utils.rs @@ -708,7 +708,7 @@ fn effective_gas_price(tx: &Transaction, base_fee: Option<U256>) -> Result<U256> .transaction_type .context("transaction type is not available")?; let tx_gas_price = tx.gas_price.context("gas price is not available")?; - let tx_max_priority_fee_per_gas = tx.max_priority_fee_per_gas.unwrap_or(U256::from(0)); + let tx_max_priority_fee_per_gas = tx.max_priority_fee_per_gas.unwrap_or_default(); if tx_transaction_type.as_u64() != 2 { return Ok(tx_gas_price); diff --git a/chains/ethereum/tx/src/lib.rs b/chains/ethereum/tx/src/lib.rs index e731e615..3a86d466 100644 --- a/chains/ethereum/tx/src/lib.rs +++ b/chains/ethereum/tx/src/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Context, Result}; use ethers::abi::token::{LenientTokenizer, Tokenizer}; use ethers::abi::{Abi, Function, HumanReadableParser, Param, Token}; use ethers_core::types::{Eip1559TransactionRequest, Signature, H160, U256}; @@ -31,10 +31,8 @@ impl TransactionBuilder for EthereumTransactionBuilder { let method_str = params["method_signature"] .as_str() - .ok_or(anyhow!("Method signature not found"))?; - let function_params = params["params"] - .as_array() - .ok_or(anyhow!("Params not found"))?; + .context("Method signature not found")?; + let function_params = params["params"].as_array().context("Params not found")?; let function = parse_method(method_str)?;