Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement transaction_by_hash Runtime API #35

Merged
merged 8 commits into from
Jun 15, 2020
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