Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Fill transaction hash on ethGetLog of light client. #9938

Merged
merged 10 commits into from
Dec 17, 2018
60 changes: 53 additions & 7 deletions rpc/src/v1/helpers/light_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use ethereum_types::{U256, Address};
use hash::H256;
use parking_lot::Mutex;
use fastmap::H256FastMap;
use std::collections::BTreeMap;
use transaction::{Action, Transaction as EthTransaction, PendingTransaction, SignedTransaction, LocalizedTransaction};

use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch};
Expand Down Expand Up @@ -308,11 +309,11 @@ impl LightFetch {
Some(OnDemandResponse::Receipts(b)) => b,
_ => panic!(WRONG_RESPONSE_AMOUNT_TYPE_PROOF),
}))


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra whitespace

}

/// Get transaction logs
pub fn logs(&self, filter: EthcoreFilter) -> impl Future<Item = Vec<Log>, Error = Error> + Send {
use std::collections::BTreeMap;
fn logs_common(&self, filter: EthcoreFilter) -> impl Future<Item = BTreeMap<(u64,usize),Log>, Error = Error> + Send {
ordian marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing spaces

Suggested change
fn logs_common(&self, filter: EthcoreFilter) -> impl Future<Item = BTreeMap<(u64,usize),Log>, Error = Error> + Send {
fn logs_common(&self, filter: EthcoreFilter) -> impl Future<Item = BTreeMap<(u64, usize), Log>, Error = Error> + Send {

use jsonrpc_core::futures::stream::{self, Stream};

const MAX_BLOCK_RANGE: u64 = 1000;
Expand All @@ -321,7 +322,7 @@ impl LightFetch {
self.headers_range_by_block_id(filter.from_block, filter.to_block, MAX_BLOCK_RANGE)
.and_then(move |mut headers| {
if headers.is_empty() {
return Either::A(future::ok(Vec::new()));
return Either::A(future::ok(BTreeMap::new()));
}

let on_demand = &fetcher.on_demand;
Expand All @@ -343,7 +344,7 @@ impl LightFetch {
// insert them into a BTreeMap to maintain order by number and block index.
stream::futures_unordered(receipts_futures)
.fold(BTreeMap::new(), move |mut matches, (num, hash, receipts)| {
let mut block_index = 0;
let mut block_index: usize = 0;
for (transaction_index, receipt) in receipts.into_iter().enumerate() {
for (transaction_log_index, log) in receipt.logs.into_iter().enumerate() {
if filter.matches(&log) {
Expand All @@ -366,8 +367,7 @@ impl LightFetch {
}
}
future::ok::<_,OnDemandError>(matches)
}) // and then collect them into a vector.
.map(|matches| matches.into_iter().map(|(_, v)| v).collect())
})
.map_err(errors::on_demand_error)
});

Expand All @@ -376,6 +376,52 @@ impl LightFetch {
None => Either::B(Either::B(future::err(errors::network_disabled()))),
}
})

}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra whitespace


/// Variant of get transaction logs that does not fetch log transactions hash
pub fn logs_light(&self, filter: EthcoreFilter) -> impl Future<Item = Vec<Log>, Error = Error> + Send {
self.logs_common(filter)
.map(|matches| matches.into_iter().map(|(_, v)| v).collect())
}

/// Get transaction logs
pub fn logs(&self, filter: EthcoreFilter) -> impl Future<Item = Vec<Log>, Error = Error> + Send {
use jsonrpc_core::futures::stream::{self, Stream};
let fetcher_block = self.clone();
self.logs_common(filter)
// retrieve transaction hash.
.and_then(move |matches| {
let mut blocks = BTreeMap::new();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation off

let mut result: Vec<Log> = matches.into_iter().map(|(_, v)| {
{
let block_hash = v.block_hash.as_ref().expect("Previously initialized with value; qed");
blocks.entry(block_hash.clone()).or_insert_with(|| {
fetcher_block.block(BlockId::Hash(block_hash.clone().into()))
});
}
v
}).collect();
// future get blocks (unordered it)
stream::futures_unordered(blocks.into_iter().map(|(_,v)|v)).collect().map(move |blocks| {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
stream::futures_unordered(blocks.into_iter().map(|(_,v)|v)).collect().map(move |blocks| {
stream::futures_unordered(blocks.into_iter().map(|(_, v)| v)).collect().map(move |blocks| {

let transactions_per_block: BTreeMap<_, _> = blocks.iter()
.map(|block| (block.hash(), block.transactions())).collect();
for log in result.iter_mut() {
let log_index: U256 = log.transaction_index.expect("Previously initialized with value; qed").into();
if log_index < usize::max_value().into() {
let block_hash = log.block_hash.clone().expect("Previously initialized with value; qed").into();
let tx_hash = transactions_per_block.get(&block_hash)
.and_then(|txs| txs.get(log_index.as_usize()))
.map(|tr| tr.hash().into());
log.transaction_hash = tx_hash;
} else {
trace!(target: "light_fetch", "A received Receipts indexed other usize length ignored");
ordian marked this conversation as resolved.
Show resolved Hide resolved
}
}
result
})
})
}

// Get a transaction by hash. also returns the index in the block.
Expand Down
50 changes: 28 additions & 22 deletions rpc/src/v1/impls/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,33 @@ enum PendingTransactionId {
Location(PendingOrBlock, usize)
}

pub fn base_logs<C, M, T: StateInfo + 'static> (client: &C, miner: &M, filter: Filter) -> BoxFuture<Vec<Log>> where
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T>,
M: MinerService<State=T> {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = match filter.try_into() {
Ok(value) => value,
Err(err) => return Box::new(future::err(err)),
};
let mut logs = match client.logs(filter.clone()) {
Ok(logs) => logs
.into_iter()
.map(From::from)
.collect::<Vec<Log>>(),
Err(id) => return Box::new(future::err(errors::filter_block_not_found(id))),
};

if include_pending {
let best_block = client.chain_info().best_block_number;
let pending = pending_logs(&*miner, best_block, &filter);
logs.extend(pending);
}

let logs = limit_logs(logs, filter.limit);

Box::new(future::ok(logs))
}

impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S, M, EM> where
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo,
SN: SnapshotService,
Expand Down Expand Up @@ -803,28 +830,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
}

fn logs(&self, filter: Filter) -> BoxFuture<Vec<Log>> {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = match filter.try_into() {
Ok(value) => value,
Err(err) => return Box::new(future::err(err)),
};
let mut logs = match self.client.logs(filter.clone()) {
Ok(logs) => logs
.into_iter()
.map(From::from)
.collect::<Vec<Log>>(),
Err(id) => return Box::new(future::err(errors::filter_block_not_found(id))),
};

if include_pending {
let best_block = self.client.chain_info().best_block_number;
let pending = pending_logs(&*self.miner, best_block, &filter);
logs.extend(pending);
}

let logs = limit_logs(logs, filter.limit);

Box::new(future::ok(logs))
base_logs(&*self.client, &*self.miner, filter.into())
}

fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work> {
Expand Down
14 changes: 12 additions & 2 deletions rpc/src/v1/impls/light/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use ethcore::account_provider::AccountProvider;
use ethcore_logger::RotatingLogger;

use jsonrpc_core::{Result, BoxFuture};
use jsonrpc_core::futures::Future;
use jsonrpc_core::futures::{future, Future};
use jsonrpc_macros::Trailing;
use v1::helpers::{self, errors, ipfs, SigningQueue, SignerService, NetworkSettings, verify_signature};
use v1::helpers::dispatch::LightDispatcher;
Expand All @@ -41,7 +41,8 @@ use v1::types::{
TransactionStats, LocalTransactionStatus,
LightBlockNumber, ChainStatus, Receipt,
BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo, AccountInfo, HwAccountInfo, Header, RichHeader, RecoveredAccount
OperationsInfo, AccountInfo, HwAccountInfo, Header, RichHeader, RecoveredAccount,
Log, Filter,
};
use Host;

Expand Down Expand Up @@ -425,6 +426,15 @@ impl Parity for ParityClient {
Err(errors::status_error(has_peers))
}
}

fn logs_light(&self, filter: Filter) -> BoxFuture<Vec<Log>> {
let filter = match filter.try_into() {
Ok(value) => value,
Err(err) => return Box::new(future::err(err)),
};
Box::new(self.fetcher().logs_light(filter)) as BoxFuture<_>
}

fn verify_signature(&self, is_prefixed: bool, message: Bytes, r: H256, s: H256, v: U64) -> Result<RecoveredAccount> {
verify_signature(is_prefixed, message, r, s, v, self.light_dispatch.client.signing_chain_id())
}
Expand Down
8 changes: 7 additions & 1 deletion rpc/src/v1/impls/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use v1::types::{
Peers, Transaction, RpcSettings, Histogram,
TransactionStats, LocalTransactionStatus,
BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo, ChainStatus,
OperationsInfo, ChainStatus, Log, Filter,
AccountInfo, HwAccountInfo, RichHeader, Receipt, RecoveredAccount,
block_number_to_id
};
Expand Down Expand Up @@ -505,6 +505,12 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
}
}

fn logs_light(&self, filter: Filter) -> BoxFuture<Vec<Log>> {
use v1::impls::eth::base_logs;
// only specific impl for lightclient
base_logs(&*self.client, &*self.miner, filter.into())
}

fn verify_signature(&self, is_prefixed: bool, message: Bytes, r: H256, s: H256, v: U64) -> Result<RecoveredAccount> {
verify_signature(is_prefixed, message, r, s, v, self.client.signing_chain_id())
}
Expand Down
8 changes: 7 additions & 1 deletion rpc/src/v1/traits/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use v1::types::{
Peers, Transaction, RpcSettings, Histogram, RecoveredAccount,
TransactionStats, LocalTransactionStatus,
BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo, ChainStatus,
OperationsInfo, ChainStatus, Log, Filter,
AccountInfo, HwAccountInfo, RichHeader, Receipt,
};

Expand Down Expand Up @@ -241,5 +241,11 @@ build_rpc_trait! {
/// as well as checks the signature for chain replay protection
#[rpc(name = "parity_verifySignature")]
fn verify_signature(&self, bool, Bytes, H256, H256, U64) -> Result<RecoveredAccount>;

/// Returns logs matching given filter object.
/// Skip filling transaction hash for faster query.
#[rpc(name = "parity_getLogsLight")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong opinions on the naming but getLogsLight is not self-explanatory as long the documentation explains this I'm satisfied.

Otherwise, I propose parity_getLogsNoTransactionHash

fn logs_light(&self, Filter) -> BoxFuture<Vec<Log>>;

}
}