diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs index 32d581abac..afb28a2115 100644 --- a/frame/ethereum/src/lib.rs +++ b/frame/ethereum/src/lib.rs @@ -67,6 +67,7 @@ decl_storage! { BlockNumbers: map hasher(blake2_128_concat) T::BlockNumber => H256; PendingTransactionsAndReceipts: Vec<(ethereum::Transaction, ethereum::Receipt)>; TransactionStatuses: map hasher(blake2_128_concat) H256 => Option; + Transactions: map hasher(blake2_128_concat) H256 => Option<(H256, u32)>; } } @@ -193,10 +194,22 @@ decl_module! { let block = ethereum::Block { header, - transactions, + transactions: transactions.clone(), ommers, }; + for t in &transactions { + let transaction_hash = H256::from_slice( + Keccak256::digest(&rlp::encode(t)).as_slice() + ); + if let Some(status) = TransactionStatuses::get(transaction_hash) { + Transactions::insert( + transaction_hash, + (hash, status.transaction_index) + ); + } + } + BlocksAndReceipts::insert(hash, (block, receipts)); BlockNumbers::::insert(n, hash); } @@ -231,6 +244,18 @@ impl Module { pub fn transaction_status(hash: H256) -> Option { TransactionStatuses::get(hash) } + + pub fn transaction_by_hash(hash: H256) -> Option<( + ethereum::Transaction, + ethereum::Block, + TransactionStatus + )> { + let (block_hash, transaction_index) = Transactions::get(hash)?; + let transaction_status = TransactionStatuses::get(hash)?; + let (block,_receipt) = BlocksAndReceipts::get(block_hash)?; + let transaction = &block.transactions[transaction_index as usize]; + Some((transaction.clone(), block, transaction_status)) + } pub fn block_by_number(number: T::BlockNumber) -> Option { if >::contains_key(number) { diff --git a/rpc/core/src/eth.rs b/rpc/core/src/eth.rs index 305700e877..f600deabd0 100644 --- a/rpc/core/src/eth.rs +++ b/rpc/core/src/eth.rs @@ -129,7 +129,7 @@ pub trait EthApi { /// Get transaction by its hash. #[rpc(name = "eth_getTransactionByHash")] - fn transaction_by_hash(&self, _: H256) -> BoxFuture>; + fn transaction_by_hash(&self, _: H256) -> Result>; /// Returns transaction at given block hash and index. #[rpc(name = "eth_getTransactionByBlockHashAndIndex")] diff --git a/rpc/primitives/src/lib.rs b/rpc/primitives/src/lib.rs index 181bb7fbd1..9c4cf8304c 100644 --- a/rpc/primitives/src/lib.rs +++ b/rpc/primitives/src/lib.rs @@ -17,7 +17,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_core::{H160, H256, U256}; -use ethereum::{Log, Block as EthereumBlock}; +use ethereum::{Log, Block as EthereumBlock, Transaction as EthereumTransaction}; use ethereum_types::Bloom; use codec::{Encode, Decode}; use sp_std::vec::Vec; @@ -46,6 +46,11 @@ sp_api::decl_runtime_apis! { fn block_transaction_count_by_number(number: u32) -> Option; fn block_by_hash(hash: H256) -> Option; fn block_transaction_count_by_hash(hash: H256) -> Option; + fn transaction_by_hash(hash: H256) -> Option<( + EthereumTransaction, + EthereumBlock, + TransactionStatus + )>; } } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 98ca990a0e..835896a77f 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -348,8 +348,47 @@ impl EthApiT for EthApi where unimplemented!("estimate_gas"); } - fn transaction_by_hash(&self, _: H256) -> BoxFuture> { - unimplemented!("transaction_by_hash"); + fn transaction_by_hash(&self, hash: H256) -> Result> { + let header = self + .select_chain + .best_chain() + .map_err(|_| internal_err("fetch header failed"))?; + + if let Ok(Some((transaction, block, status))) = self.client.runtime_api() + .transaction_by_hash(&BlockId::Hash(header.hash()), hash) { + + return Ok(Some( + Transaction { + hash: hash, + nonce: transaction.nonce, + block_hash: Some(H256::from_slice( + Keccak256::digest(&rlp::encode(&block.header)).as_slice() + )), + block_number: Some(block.header.number), + transaction_index: Some(U256::from( + UniqueSaturatedInto::::unique_saturated_into( + status.transaction_index + ) + )), + from: status.from, + to: status.to, + value: transaction.value, + gas_price: transaction.gas_price, + gas: transaction.gas_limit, + input: Bytes(transaction.input), + creates: status.contract_address, + raw: Bytes(vec![]), // TODO + public_key: None, // TODO + chain_id: None, // TODO + standard_v: U256::zero(), // TODO + v: U256::zero(), // TODO + r: U256::zero(), // TODO + s: U256::zero(), // TODO + condition: None // TODO + } + )); + } + Ok(None) } fn transaction_by_block_hash_and_index( diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index d0a298af4c..d4a6ef52dd 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -58,7 +58,8 @@ pub use frame_support::{ }, StorageValue, }; -use ethereum::Block as EthereumBlock; +use ethereum::{Block as EthereumBlock, Transaction as EthereumTransaction}; +use frontier_rpc_primitives::{TransactionStatus}; #[cfg(any(feature = "std", test))] @@ -495,6 +496,13 @@ impl_runtime_apis! { fn block_by_hash(hash: H256) -> Option { >::block_by_hash(hash) } + + fn transaction_by_hash(hash: H256) -> Option<( + EthereumTransaction, + EthereumBlock, + TransactionStatus)> { + >::transaction_by_hash(hash) + } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<