diff --git a/client/src/client.rs b/client/src/client.rs index b0931c2..efbe00d 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::sync::Arc; use ethers::prelude::{Address, U256}; -use ethers::types::TransactionReceipt; +use ethers::types::{Transaction, TransactionReceipt}; use eyre::Result; use config::Config; @@ -124,6 +124,12 @@ impl Client { .await } + pub async fn get_transaction_by_hash(&self, tx_hash: &Vec) -> Result> { + self.execution + .get_transaction(tx_hash, &self.payloads) + .await + } + pub fn get_gas_price(&self) -> Result { let payload = self.get_payload(&None)?; let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le()); diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 817b8b5..0bbbc3a 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -1,6 +1,6 @@ use ethers::{ abi::AbiEncode, - types::{Address, TransactionReceipt}, + types::{Address, Transaction, TransactionReceipt}, }; use eyre::Result; use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc}; @@ -68,6 +68,8 @@ trait EthRpc { async fn send_raw_transaction(&self, bytes: &str) -> Result; #[method(name = "getTransactionReceipt")] async fn get_transaction_receipt(&self, hash: &str) -> Result; + #[method(name = "getTransactionByHash")] + async fn get_transaction_by_hash(&self, hash: &str) -> Result; } #[rpc(client, server, namespace = "net")] @@ -179,6 +181,17 @@ impl EthRpcServer for RpcInner { None => Err(Error::Custom("Receipt Not Found".to_string())), } } + + async fn get_transaction_by_hash(&self, hash: &str) -> Result { + let client = self.client.lock().await; + let hash = convert_err(hex_str_to_bytes(hash))?; + let tx = convert_err(client.get_transaction_by_hash(&hash).await)?; + + match tx { + Some(tx) => Ok(tx), + None => Err(Error::Custom("Transaction Not Found".to_string())), + } + } } #[async_trait] diff --git a/execution/src/execution.rs b/execution/src/execution.rs index ce2ae46..437d8ef 100644 --- a/execution/src/execution.rs +++ b/execution/src/execution.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use ethers::abi::AbiEncode; use ethers::prelude::{Address, U256}; -use ethers::types::{TransactionReceipt, H256}; +use ethers::types::{Transaction, TransactionReceipt, H256}; use ethers::utils::keccak256; use ethers::utils::rlp::{encode, RlpStream}; use eyre::Result; @@ -142,7 +142,6 @@ impl ExecutionClient { tx_hash: &Vec, payloads: &HashMap, ) -> Result> { - let receipt = self.rpc.get_transaction_receipt(tx_hash).await?; if receipt.is_none() { return Ok(None); @@ -188,6 +187,46 @@ impl ExecutionClient { Ok(Some(receipt)) } + + pub async fn get_transaction( + &self, + hash: &Vec, + payloads: &HashMap, + ) -> Result> { + let tx = self.rpc.get_transaction(hash).await?; + if tx.is_none() { + return Ok(None); + } + + let tx = tx.unwrap(); + + let block_number = tx.block_number; + if block_number.is_none() { + return Ok(None); + } + + let block_number = block_number.unwrap(); + + let payload = payloads.get(&block_number.as_u64()); + if payload.is_none() { + return Ok(None); + } + + let payload = payload.unwrap(); + + let tx_encoded = tx.rlp().to_vec(); + let txs_encoded = payload + .transactions + .iter() + .map(|tx| tx.to_vec()) + .collect::>(); + + if !txs_encoded.contains(&tx_encoded) { + return Err(eyre::eyre!("Transaction Proof Invalid")); + } + + Ok(Some(tx)) + } } fn encode_receipt(receipt: &TransactionReceipt) -> Vec { diff --git a/execution/src/rpc.rs b/execution/src/rpc.rs index 2e360fa..75c9ed9 100644 --- a/execution/src/rpc.rs +++ b/execution/src/rpc.rs @@ -1,7 +1,7 @@ use ethers::abi::AbiEncode; use ethers::prelude::{Address, U256}; use ethers::providers::{Middleware, Provider}; -use ethers::types::{TransactionReceipt, H256}; +use ethers::types::{Transaction, TransactionReceipt, H256}; use eyre::Result; use jsonrpsee::{ core::client::ClientT, @@ -64,6 +64,11 @@ impl Rpc { .await?) } + pub async fn get_transaction(&self, tx_hash: &Vec) -> Result> { + let provider = Provider::try_from(&self.rpc)?; + Ok(provider.get_transaction(H256::from_slice(tx_hash)).await?) + } + fn client(&self) -> Result { Ok(HttpClientBuilder::default().build(&self.rpc)?) }