-
Notifications
You must be signed in to change notification settings - Fork 1.7k
RPC: parity_getBlockReceipts #9527
Changes from 5 commits
f8742e4
4311b4e
799d56c
1dd3b94
a066b53
7619f30
fd3e7be
f287e58
8bb8e78
87de315
14c50f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1785,26 +1785,49 @@ impl BlockChainClient for Client { | |
} | ||
|
||
fn transaction_receipt(&self, id: TransactionId) -> Option<LocalizedReceipt> { | ||
// NOTE Don't use block_receipts here for performance reasons | ||
let address = self.transaction_address(id)?; | ||
let hash = address.block_hash; | ||
let chain = self.chain.read(); | ||
self.transaction_address(id) | ||
.and_then(|address| chain.block_number(&address.block_hash).and_then(|block_number| { | ||
let transaction = chain.block_body(&address.block_hash) | ||
.and_then(|body| body.view().localized_transaction_at(&address.block_hash, block_number, address.index)); | ||
|
||
let previous_receipts = (0..address.index + 1) | ||
.map(|index| { | ||
let mut address = address.clone(); | ||
address.index = index; | ||
chain.transaction_receipt(&address) | ||
}) | ||
.collect(); | ||
match (transaction, previous_receipts) { | ||
(Some(transaction), Some(previous_receipts)) => { | ||
Some(transaction_receipt(self.engine().machine(), transaction, previous_receipts)) | ||
}, | ||
_ => None, | ||
} | ||
})) | ||
let number = chain.block_number(&hash)?; | ||
let body = chain.block_body(&hash)?; | ||
let mut receipts = chain.block_receipts(&hash)?.receipts; | ||
receipts.truncate(address.index + 1); | ||
|
||
let transaction = body.view().localized_transaction_at(&hash, number, address.index)?; | ||
let receipt = receipts.pop()?; | ||
let gas_used = receipts.last().map_or_else(|| 0.into(), |r| r.gas_used); | ||
let no_of_logs = receipts.into_iter().map(|receipt| receipt.logs.len()).sum::<usize>(); | ||
|
||
let receipt = transaction_receipt(self.engine().machine(), transaction, receipt, gas_used, no_of_logs); | ||
Some(receipt) | ||
} | ||
|
||
fn block_receipts(&self, id: BlockId) -> Option<Vec<LocalizedReceipt>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method could probably use a test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added for both |
||
let hash = self.block_hash(id)?; | ||
|
||
let chain = self.chain.read(); | ||
let receipts = chain.block_receipts(&hash)?; | ||
let number = chain.block_number(&hash)?; | ||
let body = chain.block_body(&hash)?; | ||
let engine = self.engine.clone(); | ||
|
||
let mut gas_used = 0.into(); | ||
let mut no_of_logs = 0; | ||
|
||
Some(body | ||
.view() | ||
.localized_transactions(&hash, number) | ||
.into_iter() | ||
.zip(receipts.receipts) | ||
.map(move |(transaction, receipt)| { | ||
let result = transaction_receipt(engine.machine(), transaction, receipt, gas_used, no_of_logs); | ||
gas_used = result.cumulative_gas_used; | ||
no_of_logs += result.logs.len(); | ||
result | ||
}) | ||
.collect() | ||
) | ||
} | ||
|
||
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> { | ||
|
@@ -1823,7 +1846,7 @@ impl BlockChainClient for Client { | |
self.state_db.read().journal_db().state(hash) | ||
} | ||
|
||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> { | ||
fn encoded_block_receipts(&self, hash: &H256) -> Option<Bytes> { | ||
self.chain.read().block_receipts(hash).map(|receipts| ::rlp::encode(&receipts).into_vec()) | ||
} | ||
|
||
|
@@ -2378,16 +2401,14 @@ impl Drop for Client { | |
|
||
/// Returns `LocalizedReceipt` given `LocalizedTransaction` | ||
/// and a vector of receipts from given block up to transaction index. | ||
fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTransaction, mut receipts: Vec<Receipt>) -> LocalizedReceipt { | ||
assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided."); | ||
|
||
fn transaction_receipt( | ||
machine: &::machine::EthereumMachine, | ||
mut tx: LocalizedTransaction, | ||
receipt: Receipt, | ||
prior_gas_used: U256, | ||
prior_no_of_logs: usize, | ||
) -> LocalizedReceipt { | ||
let sender = tx.sender(); | ||
let receipt = receipts.pop().expect("Current receipt is provided; qed"); | ||
let prior_gas_used = match tx.transaction_index { | ||
0 => 0.into(), | ||
i => receipts.get(i - 1).expect("All previous receipts are provided; qed").gas_used, | ||
}; | ||
let no_of_logs = receipts.into_iter().map(|receipt| receipt.logs.len()).sum::<usize>(); | ||
let transaction_hash = tx.hash(); | ||
let block_hash = tx.block_hash; | ||
let block_number = tx.block_number; | ||
|
@@ -2416,7 +2437,7 @@ fn transaction_receipt(machine: &::machine::EthereumMachine, mut tx: LocalizedTr | |
transaction_hash: transaction_hash, | ||
transaction_index: transaction_index, | ||
transaction_log_index: i, | ||
log_index: no_of_logs + i, | ||
log_index: prior_no_of_logs + i, | ||
}).collect(), | ||
log_bloom: receipt.log_bloom, | ||
outcome: receipt.outcome, | ||
|
@@ -2507,20 +2528,15 @@ mod tests { | |
topics: vec![], | ||
data: vec![], | ||
}]; | ||
let receipts = vec![Receipt { | ||
outcome: TransactionOutcome::StateRoot(state_root), | ||
gas_used: 5.into(), | ||
log_bloom: Default::default(), | ||
logs: vec![logs[0].clone()], | ||
}, Receipt { | ||
let receipt = Receipt { | ||
outcome: TransactionOutcome::StateRoot(state_root), | ||
gas_used: gas_used, | ||
log_bloom: Default::default(), | ||
logs: logs.clone(), | ||
}]; | ||
}; | ||
|
||
// when | ||
let receipt = transaction_receipt(&machine, transaction, receipts); | ||
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1); | ||
|
||
// then | ||
assert_eq!(receipt, LocalizedReceipt { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,6 @@ use ethcore::account_provider::AccountProvider; | |
use ethcore::client::{BlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo}; | ||
use ethcore::filter::Filter as EthcoreFilter; | ||
use ethcore::header::{BlockNumber as EthBlockNumber}; | ||
use ethcore::log_entry::LogEntry; | ||
use ethcore::miner::{self, MinerService}; | ||
use ethcore::snapshot::SnapshotService; | ||
use ethcore::encoded; | ||
|
@@ -419,11 +418,11 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S | |
pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService { | ||
let receipts = miner.pending_receipts(best_block).unwrap_or_default(); | ||
|
||
let pending_logs = receipts.into_iter() | ||
.flat_map(|(hash, r)| r.logs.into_iter().map(|l| (hash.clone(), l)).collect::<Vec<(H256, LogEntry)>>()) | ||
.collect::<Vec<(H256, LogEntry)>>(); | ||
|
||
pending_logs.into_iter() | ||
receipts.into_iter() | ||
.flat_map(|r| { | ||
let hash = r.transaction_hash; | ||
r.logs.into_iter().map(move |l| (hash.clone(), l)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}) | ||
.filter(|pair| filter.matches(&pair.1)) | ||
.map(|pair| { | ||
let mut log = Log::from(pair.1); | ||
|
@@ -673,16 +672,17 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient< | |
} | ||
|
||
fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> { | ||
let best_block = self.client.chain_info().best_block_number; | ||
let hash: H256 = hash.into(); | ||
|
||
match (self.miner.pending_receipt(best_block, &hash), self.options.allow_pending_receipt_query) { | ||
(Some(receipt), true) => Box::new(future::ok(Some(receipt.into()))), | ||
_ => { | ||
let receipt = self.client.transaction_receipt(TransactionId::Hash(hash)); | ||
Box::new(future::ok(receipt.map(Into::into))) | ||
if self.options.allow_pending_receipt_query { | ||
let best_block = self.client.chain_info().best_block_number; | ||
if let Some(receipt) = self.miner.pending_receipt(best_block, &hash) { | ||
return Box::new(future::ok(Some(receipt.into()))); | ||
} | ||
} | ||
|
||
let receipt = self.client.transaction_receipt(TransactionId::Hash(hash)); | ||
Box::new(future::ok(receipt.map(Into::into))) | ||
} | ||
|
||
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<RichBlock>> { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,7 +44,7 @@ use v1::types::{ | |
TransactionStats, LocalTransactionStatus, | ||
BlockNumber, ConsensusCapability, VersionInfo, | ||
OperationsInfo, ChainStatus, | ||
AccountInfo, HwAccountInfo, Header, RichHeader, | ||
AccountInfo, HwAccountInfo, Header, RichHeader, Receipt, | ||
}; | ||
use Host; | ||
|
||
|
@@ -415,6 +415,19 @@ impl Parity for ParityClient { | |
Box::new(self.fetcher().header(id).and_then(from_encoded)) | ||
} | ||
|
||
fn block_receipts(&self, number: Trailing<BlockNumber>) -> BoxFuture<Vec<Receipt>> { | ||
// Note: Here we treat `Pending` as `Latest`. | ||
// Since light clients don't produce pending blocks | ||
// (they don't have state) we can safely fallback to `Latest`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. redundant extra spaces |
||
let id = match number.unwrap_or_default() { | ||
BlockNumber::Num(n) => BlockId::Number(n), | ||
BlockNumber::Earliest => BlockId::Earliest, | ||
BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since there is no Pending state, I'd say either return an empty vector or keep the deprecation log from |
||
}; | ||
|
||
Box::new(self.fetcher().receipts(id).and_then(|receipts| Ok(receipts.into_iter().map(Into::into).collect()))) | ||
} | ||
|
||
fn ipfs_cid(&self, content: Bytes) -> Result<String> { | ||
ipfs::cid(content) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand these 3 lines. why do we pop a receipt and then take a
gas_used
from the one before it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So to actually generate a
LocalizedReceipt
we need 3 things:So the logic is as follows:
index
(inclusive)receipts.pop()
; point 1.)current.gas_used - previous.gas_used
to figure out whatcurrent
gas usage of transaction was)