Skip to content

Commit

Permalink
Implement transaction_by_hash Runtime API (#35)
Browse files Browse the repository at this point in the history
* Wip implement transaction_by_hash for EthApi

* pallet-ethereum: add Transactions StorageMap

* Implement transaction_by_hash Runtime API

* pallet-ethereum: change Transactions to store references only

* polkadot-evm/frontier/pull/35#discussion_r438019271

* Move Transaction build logic to Rpc module
  • Loading branch information
goldoneen committed Jun 15, 2020
1 parent 233f939 commit 894729c
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 6 deletions.
27 changes: 26 additions & 1 deletion frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionStatus>;
Transactions: map hasher(blake2_128_concat) H256 => Option<(H256, u32)>;
}
}

Expand Down Expand Up @@ -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::<T>::insert(n, hash);
}
Expand Down Expand Up @@ -231,6 +244,18 @@ impl<T: Trait> Module<T> {
pub fn transaction_status(hash: H256) -> Option<TransactionStatus> {
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<ethereum::Block> {
if <BlockNumbers<T>>::contains_key(number) {
Expand Down
2 changes: 1 addition & 1 deletion rpc/core/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ pub trait EthApi {

/// Get transaction by its hash.
#[rpc(name = "eth_getTransactionByHash")]
fn transaction_by_hash(&self, _: H256) -> BoxFuture<Option<Transaction>>;
fn transaction_by_hash(&self, _: H256) -> Result<Option<Transaction>>;

/// Returns transaction at given block hash and index.
#[rpc(name = "eth_getTransactionByBlockHashAndIndex")]
Expand Down
7 changes: 6 additions & 1 deletion rpc/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -46,6 +46,11 @@ sp_api::decl_runtime_apis! {
fn block_transaction_count_by_number(number: u32) -> Option<U256>;
fn block_by_hash(hash: H256) -> Option<EthereumBlock>;
fn block_transaction_count_by_hash(hash: H256) -> Option<U256>;
fn transaction_by_hash(hash: H256) -> Option<(
EthereumTransaction,
EthereumBlock,
TransactionStatus
)>;
}
}

Expand Down
43 changes: 41 additions & 2 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,47 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
unimplemented!("estimate_gas");
}

fn transaction_by_hash(&self, _: H256) -> BoxFuture<Option<Transaction>> {
unimplemented!("transaction_by_hash");
fn transaction_by_hash(&self, hash: H256) -> Result<Option<Transaction>> {
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::<u32>::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(
Expand Down
10 changes: 9 additions & 1 deletion template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down Expand Up @@ -495,6 +496,13 @@ impl_runtime_apis! {
fn block_by_hash(hash: H256) -> Option<EthereumBlock> {
<ethereum::Module<Runtime>>::block_by_hash(hash)
}

fn transaction_by_hash(hash: H256) -> Option<(
EthereumTransaction,
EthereumBlock,
TransactionStatus)> {
<ethereum::Module<Runtime>>::transaction_by_hash(hash)
}
}

impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
Expand Down

0 comments on commit 894729c

Please sign in to comment.