Fill transaction hash on ethGetLog of light client. (#9938)
* Fill transaction hash on ethGetLog of light client. This is enifficient but we keep align with spec. * Using better variables names. * Expose old fast light get log as `parity_getLogsLight`. * Update rpc/src/v1/helpers/light_fetch.rs Fix indent. Co-Authored-By: cheme <emericchevalier.pro@gmail.com> * Factor common code between light_logs and logs. * Remove useless check * Rename parity light logs to 'parity_getLogsNoTransactionHash'. Fix indent and extra white lines. * Use vec instead of tree map to avoid inner function. * better loop
This commit is contained in:
parent
aada1f547b
commit
789bb9c852
@ -46,6 +46,7 @@ use ethereum_types::{U256, Address};
|
|||||||
use hash::H256;
|
use hash::H256;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use fastmap::H256FastMap;
|
use fastmap::H256FastMap;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use transaction::{Action, Transaction as EthTransaction, PendingTransaction, SignedTransaction, LocalizedTransaction};
|
use transaction::{Action, Transaction as EthTransaction, PendingTransaction, SignedTransaction, LocalizedTransaction};
|
||||||
|
|
||||||
use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch};
|
use v1::helpers::{CallRequest as CallRequestHelper, errors, dispatch};
|
||||||
@ -310,9 +311,7 @@ impl LightFetch {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get transaction logs
|
pub fn logs_no_tx_hash(&self, filter: EthcoreFilter) -> impl Future<Item = Vec<Log>, Error = Error> + Send {
|
||||||
pub fn logs(&self, filter: EthcoreFilter) -> impl Future<Item = Vec<Log>, Error = Error> + Send {
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use jsonrpc_core::futures::stream::{self, Stream};
|
use jsonrpc_core::futures::stream::{self, Stream};
|
||||||
|
|
||||||
const MAX_BLOCK_RANGE: u64 = 1000;
|
const MAX_BLOCK_RANGE: u64 = 1000;
|
||||||
@ -343,7 +342,7 @@ impl LightFetch {
|
|||||||
// insert them into a BTreeMap to maintain order by number and block index.
|
// insert them into a BTreeMap to maintain order by number and block index.
|
||||||
stream::futures_unordered(receipts_futures)
|
stream::futures_unordered(receipts_futures)
|
||||||
.fold(BTreeMap::new(), move |mut matches, (num, hash, receipts)| {
|
.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_index, receipt) in receipts.into_iter().enumerate() {
|
||||||
for (transaction_log_index, log) in receipt.logs.into_iter().enumerate() {
|
for (transaction_log_index, log) in receipt.logs.into_iter().enumerate() {
|
||||||
if filter.matches(&log) {
|
if filter.matches(&log) {
|
||||||
@ -366,9 +365,9 @@ impl LightFetch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
future::ok::<_,OnDemandError>(matches)
|
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)
|
.map_err(errors::on_demand_error)
|
||||||
|
.map(|matches| matches.into_iter().map(|(_, v)| v).collect())
|
||||||
});
|
});
|
||||||
|
|
||||||
match maybe_future {
|
match maybe_future {
|
||||||
@ -378,6 +377,39 @@ impl LightFetch {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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_no_tx_hash(filter)
|
||||||
|
// retrieve transaction hash.
|
||||||
|
.and_then(move |mut result| {
|
||||||
|
let mut blocks = BTreeMap::new();
|
||||||
|
for log in result.iter() {
|
||||||
|
let block_hash = log.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()))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// future get blocks (unordered it)
|
||||||
|
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();
|
||||||
|
let block_hash = log.block_hash.clone().expect("Previously initialized with value; qed").into();
|
||||||
|
let tx_hash = transactions_per_block.get(&block_hash)
|
||||||
|
// transaction index is from an enumerate call in log common so not need to check value
|
||||||
|
.and_then(|txs| txs.get(log_index.as_usize()))
|
||||||
|
.map(|tr| tr.hash().into());
|
||||||
|
log.transaction_hash = tx_hash;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Get a transaction by hash. also returns the index in the block.
|
// Get a transaction by hash. also returns the index in the block.
|
||||||
// Only returns transactions in the canonical chain.
|
// Only returns transactions in the canonical chain.
|
||||||
pub fn transaction_by_hash(&self, tx_hash: H256)
|
pub fn transaction_by_hash(&self, tx_hash: H256)
|
||||||
|
@ -146,6 +146,33 @@ enum PendingTransactionId {
|
|||||||
Location(PendingOrBlock, usize)
|
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
|
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,
|
C: miner::BlockChainClient + BlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo,
|
||||||
SN: SnapshotService,
|
SN: SnapshotService,
|
||||||
@ -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>> {
|
fn logs(&self, filter: Filter) -> BoxFuture<Vec<Log>> {
|
||||||
let include_pending = filter.to_block == Some(BlockNumber::Pending);
|
base_logs(&*self.client, &*self.miner, filter.into())
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work> {
|
fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work> {
|
||||||
|
@ -28,7 +28,7 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
use ethcore_logger::RotatingLogger;
|
use ethcore_logger::RotatingLogger;
|
||||||
|
|
||||||
use jsonrpc_core::{Result, BoxFuture};
|
use jsonrpc_core::{Result, BoxFuture};
|
||||||
use jsonrpc_core::futures::Future;
|
use jsonrpc_core::futures::{future, Future};
|
||||||
use jsonrpc_macros::Trailing;
|
use jsonrpc_macros::Trailing;
|
||||||
use v1::helpers::{self, errors, ipfs, SigningQueue, SignerService, NetworkSettings, verify_signature};
|
use v1::helpers::{self, errors, ipfs, SigningQueue, SignerService, NetworkSettings, verify_signature};
|
||||||
use v1::helpers::dispatch::LightDispatcher;
|
use v1::helpers::dispatch::LightDispatcher;
|
||||||
@ -41,7 +41,8 @@ use v1::types::{
|
|||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
LightBlockNumber, ChainStatus, Receipt,
|
LightBlockNumber, ChainStatus, Receipt,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo, AccountInfo, HwAccountInfo, Header, RichHeader, RecoveredAccount
|
OperationsInfo, AccountInfo, HwAccountInfo, Header, RichHeader, RecoveredAccount,
|
||||||
|
Log, Filter,
|
||||||
};
|
};
|
||||||
use Host;
|
use Host;
|
||||||
|
|
||||||
@ -425,6 +426,15 @@ impl Parity for ParityClient {
|
|||||||
Err(errors::status_error(has_peers))
|
Err(errors::status_error(has_peers))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn logs_no_tx_hash(&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_no_tx_hash(filter)) as BoxFuture<_>
|
||||||
|
}
|
||||||
|
|
||||||
fn verify_signature(&self, is_prefixed: bool, message: Bytes, r: H256, s: H256, v: U64) -> Result<RecoveredAccount> {
|
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())
|
verify_signature(is_prefixed, message, r, s, v, self.light_dispatch.client.signing_chain_id())
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ use v1::types::{
|
|||||||
Peers, Transaction, RpcSettings, Histogram,
|
Peers, Transaction, RpcSettings, Histogram,
|
||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo, ChainStatus,
|
OperationsInfo, ChainStatus, Log, Filter,
|
||||||
AccountInfo, HwAccountInfo, RichHeader, Receipt, RecoveredAccount,
|
AccountInfo, HwAccountInfo, RichHeader, Receipt, RecoveredAccount,
|
||||||
block_number_to_id
|
block_number_to_id
|
||||||
};
|
};
|
||||||
@ -505,6 +505,12 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn logs_no_tx_hash(&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> {
|
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())
|
verify_signature(is_prefixed, message, r, s, v, self.client.signing_chain_id())
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ use v1::types::{
|
|||||||
Peers, Transaction, RpcSettings, Histogram, RecoveredAccount,
|
Peers, Transaction, RpcSettings, Histogram, RecoveredAccount,
|
||||||
TransactionStats, LocalTransactionStatus,
|
TransactionStats, LocalTransactionStatus,
|
||||||
BlockNumber, ConsensusCapability, VersionInfo,
|
BlockNumber, ConsensusCapability, VersionInfo,
|
||||||
OperationsInfo, ChainStatus,
|
OperationsInfo, ChainStatus, Log, Filter,
|
||||||
AccountInfo, HwAccountInfo, RichHeader, Receipt,
|
AccountInfo, HwAccountInfo, RichHeader, Receipt,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -241,5 +241,11 @@ build_rpc_trait! {
|
|||||||
/// as well as checks the signature for chain replay protection
|
/// as well as checks the signature for chain replay protection
|
||||||
#[rpc(name = "parity_verifySignature")]
|
#[rpc(name = "parity_verifySignature")]
|
||||||
fn verify_signature(&self, bool, Bytes, H256, H256, U64) -> Result<RecoveredAccount>;
|
fn verify_signature(&self, bool, Bytes, H256, H256, U64) -> Result<RecoveredAccount>;
|
||||||
|
|
||||||
|
/// Returns logs matching given filter object.
|
||||||
|
/// Is allowed to skip filling transaction hash for faster query.
|
||||||
|
#[rpc(name = "parity_getLogsNoTransactionHash")]
|
||||||
|
fn logs_no_tx_hash(&self, Filter) -> BoxFuture<Vec<Log>>;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user