Merge pull request #792 from ethcore/eth_getTransactionReceipt
eth_getTransactionReceipt
This commit is contained in:
commit
74f7f3f016
@ -103,6 +103,11 @@ pub trait BlockProvider {
|
|||||||
self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index))
|
self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get transaction receipt.
|
||||||
|
fn transaction_receipt(&self, address: &TransactionAddress) -> Option<Receipt> {
|
||||||
|
self.block_receipts(&address.block_hash).and_then(|br| br.receipts.into_iter().nth(address.index))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a list of transactions for a given block.
|
/// Get a list of transactions for a given block.
|
||||||
/// Returns None if block does not exist.
|
/// Returns None if block does not exist.
|
||||||
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
|
fn transactions(&self, hash: &H256) -> Option<Vec<LocalizedTransaction>> {
|
||||||
|
@ -39,6 +39,7 @@ use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
|||||||
use client::{BlockId, TransactionId, ClientConfig, BlockChainClient};
|
use client::{BlockId, TransactionId, ClientConfig, BlockChainClient};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use executive::{Executive, Executed};
|
use executive::{Executive, Executed};
|
||||||
|
use receipt::LocalizedReceipt;
|
||||||
pub use blockchain::CacheSize as BlockChainCacheSize;
|
pub use blockchain::CacheSize as BlockChainCacheSize;
|
||||||
|
|
||||||
/// General block status
|
/// General block status
|
||||||
@ -384,6 +385,16 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
BlockId::Latest => Some(self.chain.best_block_number())
|
BlockId::Latest => Some(self.chain.best_block_number())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_address(&self, id: TransactionId) -> Option<TransactionAddress> {
|
||||||
|
match id {
|
||||||
|
TransactionId::Hash(ref hash) => self.chain.transaction_address(hash),
|
||||||
|
TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress {
|
||||||
|
block_hash: hash,
|
||||||
|
index: index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> BlockChainClient for Client<V> where V: Verifier {
|
impl<V> BlockChainClient for Client<V> where V: Verifier {
|
||||||
@ -535,13 +546,43 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> {
|
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction> {
|
||||||
match id {
|
self.transaction_address(id).and_then(|address| self.chain.transaction(&address))
|
||||||
TransactionId::Hash(ref hash) => self.chain.transaction_address(hash),
|
}
|
||||||
TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress {
|
|
||||||
block_hash: hash,
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> {
|
||||||
index: index
|
self.transaction_address(id).and_then(|address| {
|
||||||
})
|
let t = self.chain.block(&address.block_hash)
|
||||||
}.and_then(|address| self.chain.transaction(&address))
|
.and_then(|block| BlockView::new(&block).localized_transaction_at(address.index));
|
||||||
|
|
||||||
|
match (t, self.chain.transaction_receipt(&address)) {
|
||||||
|
(Some(tx), Some(receipt)) => {
|
||||||
|
let block_hash = tx.block_hash.clone();
|
||||||
|
let block_number = tx.block_number.clone();
|
||||||
|
let transaction_hash = tx.hash();
|
||||||
|
let transaction_index = tx.transaction_index;
|
||||||
|
Some(LocalizedReceipt {
|
||||||
|
transaction_hash: tx.hash(),
|
||||||
|
transaction_index: tx.transaction_index,
|
||||||
|
block_hash: tx.block_hash,
|
||||||
|
block_number: tx.block_number,
|
||||||
|
// TODO: to fix this, query all previous transaction receipts and retrieve their gas usage
|
||||||
|
cumulative_gas_used: receipt.gas_used,
|
||||||
|
gas_used: receipt.gas_used,
|
||||||
|
// TODO: to fix this, store created contract address in db
|
||||||
|
contract_address: None,
|
||||||
|
logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry {
|
||||||
|
entry: log,
|
||||||
|
block_hash: block_hash.clone(),
|
||||||
|
block_number: block_number,
|
||||||
|
transaction_hash: transaction_hash.clone(),
|
||||||
|
transaction_index: transaction_index,
|
||||||
|
log_index: i
|
||||||
|
}).collect()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
||||||
@ -626,7 +667,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
.map(|(i, log)| LocalizedLogEntry {
|
.map(|(i, log)| LocalizedLogEntry {
|
||||||
entry: log,
|
entry: log,
|
||||||
block_hash: hash.clone(),
|
block_hash: hash.clone(),
|
||||||
block_number: number as usize,
|
block_number: number,
|
||||||
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
|
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
|
||||||
transaction_index: index,
|
transaction_index: index,
|
||||||
log_index: log_index + i
|
log_index: log_index + i
|
||||||
|
@ -39,6 +39,7 @@ use transaction::{LocalizedTransaction, SignedTransaction};
|
|||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use error::{ImportResult, Error};
|
use error::{ImportResult, Error};
|
||||||
|
use receipt::LocalizedReceipt;
|
||||||
|
|
||||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||||
pub trait BlockChainClient : Sync + Send {
|
pub trait BlockChainClient : Sync + Send {
|
||||||
@ -76,6 +77,9 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
/// Get transaction with given hash.
|
/// Get transaction with given hash.
|
||||||
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
|
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
|
||||||
|
|
||||||
|
/// Get transaction receipt with given hash.
|
||||||
|
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt>;
|
||||||
|
|
||||||
/// Get a tree route between `from` and `to`.
|
/// Get a tree route between `from` and `to`.
|
||||||
/// See `BlockChain::tree_route`.
|
/// See `BlockChain::tree_route`.
|
||||||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
|
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute>;
|
||||||
|
@ -23,7 +23,7 @@ use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Transaction
|
|||||||
use header::{Header as BlockHeader, BlockNumber};
|
use header::{Header as BlockHeader, BlockNumber};
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use receipt::Receipt;
|
use receipt::{Receipt, LocalizedReceipt};
|
||||||
use extras::BlockReceipts;
|
use extras::BlockReceipts;
|
||||||
use error::{ImportResult};
|
use error::{ImportResult};
|
||||||
|
|
||||||
@ -224,6 +224,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_receipt(&self, _id: TransactionId) -> Option<LocalizedReceipt> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option<Vec<BlockNumber>> {
|
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option<Vec<BlockNumber>> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
|
use header::BlockNumber;
|
||||||
|
|
||||||
/// A record of execution for a `LOG` operation.
|
/// A record of execution for a `LOG` operation.
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
@ -84,7 +85,7 @@ pub struct LocalizedLogEntry {
|
|||||||
/// Block in which this log was created.
|
/// Block in which this log was created.
|
||||||
pub block_hash: H256,
|
pub block_hash: H256,
|
||||||
/// Block number.
|
/// Block number.
|
||||||
pub block_number: usize,
|
pub block_number: BlockNumber,
|
||||||
/// Hash of transaction in which this log was created.
|
/// Hash of transaction in which this log was created.
|
||||||
pub transaction_hash: H256,
|
pub transaction_hash: H256,
|
||||||
/// Index of transaction within block.
|
/// Index of transaction within block.
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use log_entry::LogEntry;
|
use header::BlockNumber;
|
||||||
|
use log_entry::{LogEntry, LocalizedLogEntry};
|
||||||
|
|
||||||
/// Information describing execution of a transaction.
|
/// Information describing execution of a transaction.
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
@ -74,6 +75,26 @@ impl HeapSizeOf for Receipt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receipt with additional info.
|
||||||
|
pub struct LocalizedReceipt {
|
||||||
|
/// Transaction hash.
|
||||||
|
pub transaction_hash: H256,
|
||||||
|
/// Transaction index.
|
||||||
|
pub transaction_index: usize,
|
||||||
|
/// Block hash.
|
||||||
|
pub block_hash: H256,
|
||||||
|
/// Block number.
|
||||||
|
pub block_number: BlockNumber,
|
||||||
|
/// Cumulative gas used.
|
||||||
|
pub cumulative_gas_used: U256,
|
||||||
|
/// Gas used.
|
||||||
|
pub gas_used: U256,
|
||||||
|
/// Contract address.
|
||||||
|
pub contract_address: Option<Address>,
|
||||||
|
/// Logs
|
||||||
|
pub logs: Vec<LocalizedLogEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic() {
|
fn test_basic() {
|
||||||
let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
|
@ -31,7 +31,7 @@ use ethcore::ethereum::Ethash;
|
|||||||
use ethcore::ethereum::denominations::shannon;
|
use ethcore::ethereum::denominations::shannon;
|
||||||
use ethcore::transaction::Transaction as EthTransaction;
|
use ethcore::transaction::Transaction as EthTransaction;
|
||||||
use v1::traits::{Eth, EthFilter};
|
use v1::traits::{Eth, EthFilter};
|
||||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log};
|
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt};
|
||||||
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
||||||
use util::keys::store::AccountProvider;
|
use util::keys::store::AccountProvider;
|
||||||
|
|
||||||
@ -293,6 +293,15 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
.and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value())))
|
.and_then(|(number, index)| self.transaction(TransactionId::Location(number.into(), index.value())))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transaction_receipt(&self, params: Params) -> Result<Value, Error> {
|
||||||
|
from_params::<(H256,)>(params)
|
||||||
|
.and_then(|(hash,)| {
|
||||||
|
let client = take_weak!(self.client);
|
||||||
|
let receipt = client.transaction_receipt(TransactionId::Hash(hash));
|
||||||
|
to_value(&receipt.map(Receipt::from))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
fn uncle_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(H256, Index)>(params)
|
from_params::<(H256, Index)>(params)
|
||||||
.and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value()))
|
.and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value()))
|
||||||
|
@ -24,6 +24,7 @@ mod optionals;
|
|||||||
mod sync;
|
mod sync;
|
||||||
mod transaction;
|
mod transaction;
|
||||||
mod transaction_request;
|
mod transaction_request;
|
||||||
|
mod receipt;
|
||||||
|
|
||||||
pub use self::block::{Block, BlockTransactions};
|
pub use self::block::{Block, BlockTransactions};
|
||||||
pub use self::block_number::BlockNumber;
|
pub use self::block_number::BlockNumber;
|
||||||
@ -35,4 +36,5 @@ pub use self::optionals::OptionalValue;
|
|||||||
pub use self::sync::{SyncStatus, SyncInfo};
|
pub use self::sync::{SyncStatus, SyncInfo};
|
||||||
pub use self::transaction::Transaction;
|
pub use self::transaction::Transaction;
|
||||||
pub use self::transaction_request::TransactionRequest;
|
pub use self::transaction_request::TransactionRequest;
|
||||||
|
pub use self::receipt::Receipt;
|
||||||
|
|
||||||
|
56
rpc/src/v1/types/receipt.rs
Normal file
56
rpc/src/v1/types/receipt.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use util::numbers::U256;
|
||||||
|
use util::hash::{Address, H256};
|
||||||
|
use v1::types::Log;
|
||||||
|
use ethcore::receipt::LocalizedReceipt;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Receipt {
|
||||||
|
#[serde(rename="transactionHash")]
|
||||||
|
pub transaction_hash: H256,
|
||||||
|
#[serde(rename="transactionIndex")]
|
||||||
|
pub transaction_index: U256,
|
||||||
|
#[serde(rename="blockHash")]
|
||||||
|
pub block_hash: H256,
|
||||||
|
#[serde(rename="blockNumber")]
|
||||||
|
pub block_number: U256,
|
||||||
|
#[serde(rename="cumulativeGasUsed")]
|
||||||
|
pub cumulative_gas_used: U256,
|
||||||
|
#[serde(rename="gasUsed")]
|
||||||
|
pub gas_used: U256,
|
||||||
|
#[serde(rename="contractAddress")]
|
||||||
|
pub contract_address: Option<Address>,
|
||||||
|
pub logs: Vec<Log>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LocalizedReceipt> for Receipt {
|
||||||
|
fn from(r: LocalizedReceipt) -> Self {
|
||||||
|
Receipt {
|
||||||
|
transaction_hash: r.transaction_hash,
|
||||||
|
transaction_index: U256::from(r.transaction_index),
|
||||||
|
block_hash: r.block_hash,
|
||||||
|
block_number: U256::from(r.block_number),
|
||||||
|
cumulative_gas_used: r.cumulative_gas_used,
|
||||||
|
gas_used: r.gas_used,
|
||||||
|
contract_address: r.contract_address,
|
||||||
|
logs: r.logs.into_iter().map(From::from).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user