Skip to content

Commit

Permalink
Implement transaction_by_block_hash_and_index for Runtime API (#39)
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

* Implement transaction_by_block_hash_and_index for Runtime API
  • Loading branch information
tgmichel authored Jun 15, 2020
1 parent f481e0d commit 646338b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 37 deletions.
21 changes: 21 additions & 0 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,27 @@ impl<T: Trait> Module<T> {
Some((transaction.clone(), block, transaction_status))
}

pub fn transaction_by_block_hash_and_index(
hash: H256,
index: u32
) -> Option<(
ethereum::Transaction,
ethereum::Block,
TransactionStatus
)> {
let (block,_receipt) = BlocksAndReceipts::get(hash)?;
if index < block.transactions.len() as u32 {
let transaction = &block.transactions[index as usize];
let transaction_hash = H256::from_slice(
Keccak256::digest(&rlp::encode(transaction)).as_slice()
);
let transaction_status = TransactionStatuses::get(transaction_hash)?;
Some((transaction.clone(), block, transaction_status))
} else {
None
}
}

pub fn block_by_number(number: T::BlockNumber) -> Option<ethereum::Block> {
if <BlockNumbers<T>>::contains_key(number) {
let hash = <BlockNumbers<T>>::get(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 @@ -137,7 +137,7 @@ pub trait EthApi {
&self,
_: H256,
_: Index,
) -> BoxFuture<Option<Transaction>>;
) -> Result<Option<Transaction>>;

/// Returns transaction by given block number and index.
#[rpc(name = "eth_getTransactionByBlockNumberAndIndex")]
Expand Down
8 changes: 8 additions & 0 deletions rpc/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ sp_api::decl_runtime_apis! {
EthereumBlock,
TransactionStatus
)>;
fn transaction_by_block_hash_and_index(
hash: H256,
index: u32
) -> Option<(
EthereumTransaction,
EthereumBlock,
TransactionStatus
)>;
}
}

Expand Down
99 changes: 63 additions & 36 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use std::{marker::PhantomData, sync::Arc};
use std::collections::BTreeMap;
use ethereum::{Block as EthereumBlock, Transaction as EthereumTransaction};
use ethereum_types::{H160, H256, H64, U256, U64};
use jsonrpc_core::{BoxFuture, Result, ErrorCode, Error, futures::future::{self, Future}};
use futures::future::TryFutureExt;
Expand All @@ -32,7 +33,7 @@ use frontier_rpc_core::types::{
BlockNumber, Bytes, CallRequest, EthAccount, Filter, Index, Log, Receipt, RichBlock,
SyncStatus, Transaction, Work, Rich, Block, BlockTransactions
};
use frontier_rpc_primitives::{EthereumRuntimeApi, ConvertTransaction};
use frontier_rpc_primitives::{EthereumRuntimeApi, ConvertTransaction, TransactionStatus};

pub use frontier_rpc_core::EthApiServer;

Expand Down Expand Up @@ -93,6 +94,43 @@ fn rich_block_build(block: ethereum::Block) -> RichBlock {
}
}

fn transaction_build(
transaction: EthereumTransaction,
block: EthereumBlock,
status: TransactionStatus
) -> Transaction {
Transaction {
hash: H256::from_slice(
Keccak256::digest(&rlp::encode(&transaction)).as_slice()
),
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
}
}

impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where
C: ProvideRuntimeApi<B> + StorageProvider<B,BE>,
C::Api: EthereumRuntimeApi<B>,
Expand Down Expand Up @@ -356,47 +394,36 @@ impl<B, C, SC, P, CT, BE> EthApiT for EthApi<B, C, SC, P, CT, BE> where

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
}
));
return Ok(Some(transaction_build(
transaction,
block,
status
)));
}
Ok(None)
}

fn transaction_by_block_hash_and_index(
&self,
_: H256,
_: Index,
) -> BoxFuture<Option<Transaction>> {
unimplemented!("transaction_by_block_hash_and_index");
hash: H256,
index: Index,
) -> Result<Option<Transaction>> {
let header = self
.select_chain
.best_chain()
.map_err(|_| internal_err("fetch header failed"))?;

let index_param = index.value() as u32;

if let Ok(Some((transaction, block, status))) = self.client.runtime_api()
.transaction_by_block_hash_and_index(&BlockId::Hash(header.hash()), hash, index_param) {
return Ok(Some(transaction_build(
transaction,
block,
status
)));
}
Ok(None)
}

fn transaction_by_block_number_and_index(
Expand Down
7 changes: 7 additions & 0 deletions template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,13 @@ impl_runtime_apis! {
TransactionStatus)> {
<ethereum::Module<Runtime>>::transaction_by_hash(hash)
}

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

impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
Expand Down

0 comments on commit 646338b

Please sign in to comment.