From f8742e436e730b2ad7fedd86a2fb3b08eba00c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 11 Sep 2018 13:23:32 +0200 Subject: [PATCH 1/6] Block receipts RPC. --- ethcore/light/src/provider.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 5 -- ethcore/src/client/client.rs | 78 ++++++++++++----------- ethcore/src/client/test_client.rs | 6 +- ethcore/src/client/traits.rs | 5 +- ethcore/src/miner/miner.rs | 28 +++----- ethcore/src/miner/mod.rs | 9 ++- ethcore/sync/src/chain/supplier.rs | 2 +- rpc/src/v1/impls/eth.rs | 11 ++-- rpc/src/v1/impls/light/parity.rs | 15 ++++- rpc/src/v1/impls/parity.rs | 38 ++++++++--- rpc/src/v1/tests/helpers/miner_service.rs | 32 +++------- rpc/src/v1/tests/mocked/parity.rs | 34 +++++++++- rpc/src/v1/traits/parity.rs | 7 +- 14 files changed, 162 insertions(+), 110 deletions(-) diff --git a/ethcore/light/src/provider.rs b/ethcore/light/src/provider.rs index 2ac3ebd9178..72344620653 100644 --- a/ethcore/light/src/provider.rs +++ b/ethcore/light/src/provider.rs @@ -176,7 +176,7 @@ impl Provider for T { } fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option { - BlockChainClient::block_receipts(self, &req.hash) + BlockChainClient::encoded_block_receipts(self, &req.hash) .map(|x| ::request::ReceiptsResponse { receipts: ::rlp::decode_list(&x) }) } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index d9448286f1f..5785aa10343 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -160,11 +160,6 @@ pub trait BlockProvider { .and_then(|n| body.view().localized_transaction_at(&address.block_hash, n, address.index))) } - /// Get transaction receipt. - fn transaction_receipt(&self, address: &TransactionAddress) -> Option { - 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. /// Returns None if block does not exist. fn transactions(&self, hash: &H256) -> Option> { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 470c5361e02..ace4f03d2b9 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1785,26 +1785,35 @@ impl BlockChainClient for Client { } fn transaction_receipt(&self, id: TransactionId) -> Option { + let address = self.transaction_address(id)?; + let receipts = self.block_receipts(BlockId::Hash(address.block_hash))?; + receipts.get(address.index).cloned() + } + + fn block_receipts(&self, id: BlockId) -> Option> { + let hash = self.block_hash(id)?; + 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 receipts = chain.block_receipts(&hash)?; + let number = chain.block_number(&hash)?; + let body = chain.block_body(&hash)?; + let machine = self.engine().machine(); + + 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(|(transaction, receipt)| { + let result = transaction_receipt(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 { @@ -1823,7 +1832,7 @@ impl BlockChainClient for Client { self.state_db.read().journal_db().state(hash) } - fn block_receipts(&self, hash: &H256) -> Option { + fn encoded_block_receipts(&self, hash: &H256) -> Option { self.chain.read().block_receipts(hash).map(|receipts| ::rlp::encode(&receipts).into_vec()) } @@ -2378,16 +2387,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) -> 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::(); let transaction_hash = tx.hash(); let block_hash = tx.block_hash; let block_number = tx.block_number; @@ -2416,7 +2423,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 +2514,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 { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 81fbc4e6f71..fef78e31460 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -687,6 +687,10 @@ impl BlockChainClient for TestBlockChainClient { self.receipts.read().get(&id).cloned() } + fn block_receipts(&self, _id: BlockId) -> Option> { + Some(self.receipts.read().values().cloned().collect()) + } + fn logs(&self, filter: Filter) -> Result, BlockId> { match self.error_on_logs.read().as_ref() { Some(id) => return Err(id.clone()), @@ -786,7 +790,7 @@ impl BlockChainClient for TestBlockChainClient { None } - fn block_receipts(&self, hash: &H256) -> Option { + fn encoded_block_receipts(&self, hash: &H256) -> Option { // starts with 'f' ? if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { let receipt = BlockReceipts::new(vec![Receipt::new( diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 719fce91644..f621c550e86 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -281,6 +281,9 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get transaction receipt with given hash. fn transaction_receipt(&self, id: TransactionId) -> Option; + /// Get receipts for all transaction in given block. + fn block_receipts(&self, id: BlockId) -> Option>; + /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. fn tree_route(&self, from: &H256, to: &H256) -> Option; @@ -292,7 +295,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn state_data(&self, hash: &H256) -> Option; /// Get raw block receipts data by block header hash. - fn block_receipts(&self, hash: &H256) -> Option; + fn encoded_block_receipts(&self, hash: &H256) -> Option; /// Get block queue information. fn queue_info(&self) -> BlockQueueInfo; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 1a0d34b10b7..987d895ab04 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -50,7 +50,7 @@ use executive::contract_address; use header::{Header, BlockNumber}; use miner; use miner::pool_client::{PoolClient, CachedNonceClient, NonceCache}; -use receipt::{Receipt, RichReceipt}; +use receipt::RichReceipt; use spec::Spec; use state::State; use ethkey::Password; @@ -1039,19 +1039,17 @@ impl miner::MinerService for Miner { self.transaction_queue.status() } - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { + fn pending_receipts(&self, best_block: BlockNumber) -> Option> { self.map_existing_pending_block(|pending| { - let txs = pending.transactions(); - txs.iter() - .map(|t| t.hash()) - .position(|t| t == *hash) - .map(|index| { - let receipts = pending.receipts(); + let receipts = pending.receipts(); + pending.transactions() + .into_iter() + .enumerate() + .map(|(index, tx)| { let prev_gas = if index == 0 { Default::default() } else { receipts[index - 1].gas_used }; - let tx = &txs[index]; let receipt = &receipts[index]; RichReceipt { - transaction_hash: hash.clone(), + transaction_hash: tx.hash(), transaction_index: index, cumulative_gas_used: receipt.gas_used, gas_used: receipt.gas_used - prev_gas, @@ -1067,15 +1065,7 @@ impl miner::MinerService for Miner { outcome: receipt.outcome.clone(), } }) - }, best_block).and_then(|x| x) - } - - fn pending_receipts(&self, best_block: BlockNumber) -> Option> { - self.map_existing_pending_block(|pending| { - let hashes = pending.transactions().iter().map(|t| t.hash()); - let receipts = pending.receipts().iter().cloned(); - - hashes.zip(receipts).collect() + .collect() }, best_block) } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index cc56bf01f94..4ba1b036115 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -44,7 +44,7 @@ use client::{ }; use error::Error; use header::{BlockNumber, Header}; -use receipt::{RichReceipt, Receipt}; +use receipt::RichReceipt; use transaction::{self, UnverifiedTransaction, SignedTransaction, PendingTransaction}; use state::StateInfo; use ethkey::Password; @@ -95,10 +95,13 @@ pub trait MinerService : Send + Sync { // Pending block /// Get a list of all pending receipts from pending block. - fn pending_receipts(&self, best_block: BlockNumber) -> Option>; + fn pending_receipts(&self, best_block: BlockNumber) -> Option>; /// Get a particular receipt from pending block. - fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option; + fn pending_receipt(&self, best_block: BlockNumber, hash: &H256) -> Option { + let receipts = self.pending_receipts(best_block)?; + receipts.into_iter().find(|r| &r.transaction_hash == hash) + } /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. fn pending_state(&self, latest_block_number: BlockNumber) -> Option; diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index e2113b0b1c2..201e0d9f35a 100644 --- a/ethcore/sync/src/chain/supplier.rs +++ b/ethcore/sync/src/chain/supplier.rs @@ -226,7 +226,7 @@ impl SyncSupplier { let mut added_receipts = 0usize; let mut data = Bytes::new(); for i in 0..count { - if let Some(mut receipts_bytes) = io.chain().block_receipts(&rlp.val_at::(i)?) { + if let Some(mut receipts_bytes) = io.chain().encoded_block_receipts(&rlp.val_at::(i)?) { data.append(&mut receipts_bytes); added_receipts += receipts_bytes.len(); added_headers += 1; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index e19bfaa2975..4ce20b808d4 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -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 EthClient(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec 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::>()) - .collect::>(); - - 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)) + }) .filter(|pair| filter.matches(&pair.1)) .map(|pair| { let mut log = Log::from(pair.1); diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index f74886e619f..3d368126a8e 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -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) -> BoxFuture> { + // 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`. + let id = match number.unwrap_or_default() { + BlockNumber::Num(n) => BlockId::Number(n), + BlockNumber::Earliest => BlockId::Earliest, + BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, + }; + + Box::new(self.fetcher().receipts(id).and_then(|receipts| Ok(receipts.into_iter().map(Into::into).collect()))) + } + fn ipfs_cid(&self, content: Bytes) -> Result { ipfs::cid(content) } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 3e20d582141..bbf75411eae 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -45,7 +45,7 @@ use v1::types::{ TransactionStats, LocalTransactionStatus, BlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, ChainStatus, - AccountInfo, HwAccountInfo, RichHeader, + AccountInfo, HwAccountInfo, RichHeader, Receipt, block_number_to_id }; use Host; @@ -332,7 +332,7 @@ impl Parity for ParityClient where fn ws_url(&self) -> Result { helpers::to_url(&self.ws_address) - .ok_or_else(|| errors::ws_disabled()) + .ok_or_else(errors::ws_disabled) } fn next_nonce(&self, address: H160) -> BoxFuture { @@ -387,7 +387,8 @@ impl Parity for ParityClient where let (header, extra) = if number == BlockNumber::Pending { let info = self.client.chain_info(); - let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::unknown_block())); + let header = + try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or_else(errors::unknown_block)); (header.encoded(), None) } else { @@ -398,7 +399,7 @@ impl Parity for ParityClient where BlockNumber::Pending => unreachable!(), // Already covered }; - let header = try_bf!(self.client.block_header(id.clone()).ok_or(errors::unknown_block())); + let header = try_bf!(self.client.block_header(id.clone()).ok_or_else(errors::unknown_block)); let info = self.client.block_extra_info(id).expect(EXTRA_INFO_PROOF); (header, Some(info)) @@ -410,6 +411,27 @@ impl Parity for ParityClient where })) } + fn block_receipts(&self, number: Trailing) -> BoxFuture> { + let number = number.unwrap_or_default(); + + let id = match number { + BlockNumber::Pending => { + let info = self.client.chain_info(); + let receipts = try_bf!(self.miner.pending_receipts(info.best_block_number).ok_or_else(errors::unknown_block)); + return Box::new(future::ok(receipts + .into_iter() + .map(Into::into) + .collect() + )) + }, + BlockNumber::Num(num) => BlockId::Number(num), + BlockNumber::Earliest => BlockId::Earliest, + BlockNumber::Latest => BlockId::Latest, + }; + let receipts = try_bf!(self.client.block_receipts(id).ok_or_else(errors::unknown_block)); + Box::new(future::ok(receipts.into_iter().map(Into::into).collect())) + } + fn ipfs_cid(&self, content: Bytes) -> Result { ipfs::cid(content) } @@ -427,8 +449,8 @@ impl Parity for ParityClient where let (mut state, header) = if num == BlockNumber::Pending { let info = self.client.chain_info(); - let state = self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned())?; - let header = self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned())?; + let state = self.miner.pending_state(info.best_block_number).ok_or_else(errors::state_pruned)?; + let header = self.miner.pending_block_header(info.best_block_number).ok_or_else(errors::state_pruned)?; (state, header) } else { @@ -439,8 +461,8 @@ impl Parity for ParityClient where BlockNumber::Pending => unreachable!(), // Already covered }; - let state = self.client.state_at(id).ok_or(errors::state_pruned())?; - let header = self.client.block_header(id).ok_or(errors::state_pruned())?.decode().map_err(errors::decode)?; + let state = self.client.state_at(id).ok_or_else(errors::state_pruned)?; + let header = self.client.block_header(id).ok_or_else(errors::state_pruned)?.decode().map_err(errors::decode)?; (state, header) }; diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index e26290e48eb..088b1d45ddb 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -28,7 +28,7 @@ use ethcore::error::Error; use ethcore::header::{BlockNumber, Header}; use ethcore::ids::BlockId; use ethcore::miner::{self, MinerService, AuthoringParams}; -use ethcore::receipt::{Receipt, RichReceipt}; +use ethcore::receipt::RichReceipt; use ethereum_types::{H256, U256, Address}; use miner::pool::local_transactions::Status as LocalTransactionStatus; use miner::pool::{verifier, VerifiedTransaction, QueueStatus}; @@ -46,7 +46,7 @@ pub struct TestMinerService { /// Pre-existed local transactions pub local_transactions: Mutex>, /// Pre-existed pending receipts - pub pending_receipts: Mutex>, + pub pending_receipts: Mutex>, /// Next nonces. pub next_nonces: RwLock>, /// Password held by Engine. @@ -58,11 +58,11 @@ pub struct TestMinerService { impl Default for TestMinerService { fn default() -> TestMinerService { TestMinerService { - imported_transactions: Mutex::new(Vec::new()), - pending_transactions: Mutex::new(HashMap::new()), - local_transactions: Mutex::new(BTreeMap::new()), - pending_receipts: Mutex::new(BTreeMap::new()), - next_nonces: RwLock::new(HashMap::new()), + imported_transactions: Default::default(), + pending_transactions: Default::default(), + local_transactions: Default::default(), + pending_receipts: Default::default(), + next_nonces: Default::default(), password: RwLock::new("".into()), authoring_params: RwLock::new(AuthoringParams { author: Address::zero(), @@ -230,23 +230,7 @@ impl MinerService for TestMinerService { }).collect() } - fn pending_receipt(&self, _best_block: BlockNumber, hash: &H256) -> Option { - // Not much point implementing this since the logic is complex and the only thing it relies on is pending_receipts, which is already tested. - self.pending_receipts(0).unwrap().get(hash).map(|r| - RichReceipt { - transaction_hash: Default::default(), - transaction_index: Default::default(), - cumulative_gas_used: r.gas_used.clone(), - gas_used: r.gas_used.clone(), - contract_address: None, - logs: r.logs.clone(), - log_bloom: r.log_bloom, - outcome: r.outcome.clone(), - } - ) - } - - fn pending_receipts(&self, _best_block: BlockNumber) -> Option> { + fn pending_receipts(&self, _best_block: BlockNumber) -> Option> { Some(self.pending_receipts.lock().clone()) } diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 68251d30b9b..8ac8e44eb29 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -16,7 +16,8 @@ use std::sync::Arc; use ethcore::account_provider::AccountProvider; -use ethcore::client::{TestBlockChainClient, Executed}; +use ethcore::client::{TestBlockChainClient, Executed, TransactionId}; +use ethcore::receipt::{LocalizedReceipt, TransactionOutcome}; use ethcore_logger::RotatingLogger; use ethereum_types::{Address, U256, H256}; use ethstore::ethkey::{Generator, Random}; @@ -531,3 +532,34 @@ fn rpc_parity_call() { assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } + +#[test] +fn rpc_parity_block_receipts() { + let deps = Dependencies::new(); + deps.client.receipts.write() + .insert(TransactionId::Hash(1.into()), LocalizedReceipt { + transaction_hash: 1.into(), + transaction_index: 0, + block_hash: 3.into(), + block_number: 0, + cumulative_gas_used: 21_000.into(), + gas_used: 21_000.into(), + contract_address: None, + logs: vec![], + log_bloom: 1.into(), + outcome: TransactionOutcome::Unknown, + to: None, + from: 9.into(), + }); + let io = deps.default_client(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "parity_getBlockReceipts", + "params": [], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":[{"blockHash":"0x0000000000000000000000000000000000000000000000000000000000000003","blockNumber":"0x0","contractAddress":null,"cumulativeGasUsed":"0x5208","from":"0x0000000000000000000000000000000000000009","gasUsed":"0x5208","logs":[],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001","root":null,"status":null,"to":null,"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000001","transactionIndex":"0x0"}],"id":1}"#; + + assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 76df05bbc64..190f9725d6b 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -27,7 +27,7 @@ use v1::types::{ TransactionStats, LocalTransactionStatus, BlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, ChainStatus, - AccountInfo, HwAccountInfo, RichHeader, + AccountInfo, HwAccountInfo, RichHeader, Receipt, }; build_rpc_trait! { @@ -211,6 +211,11 @@ build_rpc_trait! { #[rpc(name = "parity_getBlockHeaderByNumber")] fn block_header(&self, Trailing) -> BoxFuture; + /// Get block receipts. + /// Allows you to fetch receipts from the entire block at once. + #[rpc(name = "parity_getBlockReceipts")] + fn block_receipts(&self, Trailing) -> BoxFuture>; + /// Get IPFS CIDv0 given protobuf encoded bytes. #[rpc(name = "parity_cidV0")] fn ipfs_cid(&self, Bytes) -> Result; From 799d56cca458f3cd1b0a451fca5d986108ee122a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 11 Sep 2018 15:33:27 +0200 Subject: [PATCH 2/6] Use lazy evaluation of block receipts (ecrecover). --- ethcore/src/client/client.rs | 25 ++++++++++++++----------- ethcore/src/client/test_client.rs | 4 ++-- ethcore/src/client/traits.rs | 4 ++-- ethcore/src/views/body.rs | 4 ++-- rpc/src/v1/impls/eth.rs | 13 +++++++------ 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ace4f03d2b9..c9bbbfa2ad4 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1786,34 +1786,37 @@ impl BlockChainClient for Client { fn transaction_receipt(&self, id: TransactionId) -> Option { let address = self.transaction_address(id)?; - let receipts = self.block_receipts(BlockId::Hash(address.block_hash))?; - receipts.get(address.index).cloned() + let mut receipts = self.block_receipts(BlockId::Hash(address.block_hash))?; + receipts.nth(address.index) } - fn block_receipts(&self, id: BlockId) -> Option> { + fn block_receipts(&self, id: BlockId) -> Option>> { 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 machine = self.engine().machine(); + 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() + // NOTE We use iterators here, for performance reasons of transaction_receipt function. + // producing LocalizedTransaction and LocalizedReceipt is expensive (ecrecover & hashing) + Some(Box::new( + (0 .. body.view().transactions_count()) + .filter_map(move |index| { + body.view().localized_transaction_at(&hash, number, index) + }) .zip(receipts.receipts) - .map(|(transaction, receipt)| { - let result = transaction_receipt(machine, transaction, receipt, gas_used, no_of_logs); + .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 { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index fef78e31460..f91e38d09a4 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -687,8 +687,8 @@ impl BlockChainClient for TestBlockChainClient { self.receipts.read().get(&id).cloned() } - fn block_receipts(&self, _id: BlockId) -> Option> { - Some(self.receipts.read().values().cloned().collect()) + fn block_receipts(&self, _id: BlockId) -> Option>> { + Some(Box::new(self.receipts.read().values().cloned().collect::>().into_iter())) } fn logs(&self, filter: Filter) -> Result, BlockId> { diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index f621c550e86..b99806bf537 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -281,8 +281,8 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get transaction receipt with given hash. fn transaction_receipt(&self, id: TransactionId) -> Option; - /// Get receipts for all transaction in given block. - fn block_receipts(&self, id: BlockId) -> Option>; + /// Get localized receipts for all transaction in given block. + fn block_receipts(&self, id: BlockId) -> Option>>; /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. diff --git a/ethcore/src/views/body.rs b/ethcore/src/views/body.rs index 6560140cad1..f1a30949b32 100644 --- a/ethcore/src/views/body.rs +++ b/ethcore/src/views/body.rs @@ -38,9 +38,9 @@ impl<'a> BodyView<'a> { /// ``` /// #[macro_use] /// extern crate ethcore; - /// + /// /// use ethcore::views::{BodyView}; - /// + /// /// fn main() { /// let bytes : &[u8] = &[]; /// let body_view = view!(BodyView, bytes); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 4ce20b808d4..697dc4d6f99 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -672,16 +672,17 @@ impl Eth for EthClient< } fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture> { - 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> { From 1dd3b94916b7a1c7b2a756b3cd42498af24cbea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 11 Sep 2018 16:42:20 +0200 Subject: [PATCH 3/6] Optimize transaction_receipt to prevent performance regression. --- ethcore/src/client/client.rs | 47 +++++++++++++++++++------------ ethcore/src/client/test_client.rs | 4 +-- ethcore/src/client/traits.rs | 2 +- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c9bbbfa2ad4..75c3a2ae31d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1785,12 +1785,25 @@ impl BlockChainClient for Client { } fn transaction_receipt(&self, id: TransactionId) -> Option { + // NOTE Don't use block_receipts here for performance reasons let address = self.transaction_address(id)?; - let mut receipts = self.block_receipts(BlockId::Hash(address.block_hash))?; - receipts.nth(address.index) + let hash = address.block_hash; + let chain = self.chain.read(); + 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::(); + + let receipt = transaction_receipt(self.engine().machine(), transaction, receipt, gas_used, no_of_logs); + Some(receipt) } - fn block_receipts(&self, id: BlockId) -> Option>> { + fn block_receipts(&self, id: BlockId) -> Option> { let hash = self.block_hash(id)?; let chain = self.chain.read(); @@ -1802,21 +1815,19 @@ impl BlockChainClient for Client { let mut gas_used = 0.into(); let mut no_of_logs = 0; - // NOTE We use iterators here, for performance reasons of transaction_receipt function. - // producing LocalizedTransaction and LocalizedReceipt is expensive (ecrecover & hashing) - Some(Box::new( - (0 .. body.view().transactions_count()) - .filter_map(move |index| { - body.view().localized_transaction_at(&hash, number, index) - }) - .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 - }) - )) + 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 { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index f91e38d09a4..fef78e31460 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -687,8 +687,8 @@ impl BlockChainClient for TestBlockChainClient { self.receipts.read().get(&id).cloned() } - fn block_receipts(&self, _id: BlockId) -> Option>> { - Some(Box::new(self.receipts.read().values().cloned().collect::>().into_iter())) + fn block_receipts(&self, _id: BlockId) -> Option> { + Some(self.receipts.read().values().cloned().collect()) } fn logs(&self, filter: Filter) -> Result, BlockId> { diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index b99806bf537..cadf5b8b414 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -282,7 +282,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn transaction_receipt(&self, id: TransactionId) -> Option; /// Get localized receipts for all transaction in given block. - fn block_receipts(&self, id: BlockId) -> Option>>; + fn block_receipts(&self, id: BlockId) -> Option>; /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. From fd3e7be8ac3066f69acd98ec63f1d57e5fdd1b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 13 Sep 2018 10:28:35 +0200 Subject: [PATCH 4/6] Fix RPC grumbles. --- rpc/src/v1/impls/eth.rs | 2 +- rpc/src/v1/impls/light/eth.rs | 33 ++++++++------------------------ rpc/src/v1/impls/light/parity.rs | 21 ++------------------ rpc/src/v1/traits/parity.rs | 1 + rpc/src/v1/types/block_number.rs | 16 ++++++++++++++++ 5 files changed, 28 insertions(+), 45 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 697dc4d6f99..64191a06cbd 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -421,7 +421,7 @@ pub fn pending_logs(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi receipts.into_iter() .flat_map(|r| { let hash = r.transaction_hash; - r.logs.into_iter().map(move |l| (hash.clone(), l)) + r.logs.into_iter().map(move |l| (hash, l)) }) .filter(|pair| filter.matches(&pair.1)) .map(|pair| { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 77c59e11c0a..5e6430bf01c 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -67,23 +67,6 @@ pub struct EthClient { gas_price_percentile: usize, } -impl EthClient { - fn num_to_id(num: BlockNumber) -> BlockId { - // 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`. - match num { - BlockNumber::Num(n) => BlockId::Number(n), - BlockNumber::Earliest => BlockId::Earliest, - BlockNumber::Latest => BlockId::Latest, - BlockNumber::Pending => { - warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); - BlockId::Latest - } - } - } -} - impl Clone for EthClient { fn clone(&self) -> Self { // each instance should have its own poll manager. @@ -285,7 +268,7 @@ impl Eth for EthClient { } fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { - Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default())) + Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().to_block_id()) .map(|acc| acc.map_or(0.into(), |a| a.balance).into())) } @@ -298,11 +281,11 @@ impl Eth for EthClient { } fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture> { - Box::new(self.rich_block(Self::num_to_id(num), include_txs).map(Some)) + Box::new(self.rich_block(num.to_block_id(), include_txs).map(Some)) } fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { - Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default())) + Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().to_block_id()) .map(|acc| acc.map_or(0.into(), |a| a.nonce).into())) } @@ -325,7 +308,7 @@ impl Eth for EthClient { fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| { + Box::new(self.fetcher().header(num.to_block_id()).and_then(move |hdr| { if hdr.transactions_root() == KECCAK_NULL_RLP { Either::A(future::ok(Some(U256::from(0).into()))) } else { @@ -357,7 +340,7 @@ impl Eth for EthClient { fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture> { let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone()); - Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| { + Box::new(self.fetcher().header(num.to_block_id()).and_then(move |hdr| { if hdr.uncles_hash() == KECCAK_EMPTY_LIST_RLP { Either::B(future::ok(Some(U256::from(0).into()))) } else { @@ -371,7 +354,7 @@ impl Eth for EthClient { } fn code_at(&self, address: RpcH160, num: Trailing) -> BoxFuture { - Box::new(self.fetcher().code(address.into(), Self::num_to_id(num.unwrap_or_default())).map(Into::into)) + Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().to_block_id()).map(Into::into)) } fn send_raw_transaction(&self, raw: Bytes) -> Result { @@ -438,7 +421,7 @@ impl Eth for EthClient { } fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture> { - Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| { + Box::new(self.fetcher().block(num.to_block_id()).map(move |block| { light_fetch::extract_transaction_at_index(block, idx.value()) })) } @@ -482,7 +465,7 @@ impl Eth for EthClient { fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture> { let client = self.client.clone(); - Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| { + Box::new(self.fetcher().block(num.to_block_id()).map(move |block| { extract_uncle_at_index(block, idx, client) })) } diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 3d368126a8e..6f76ca4738d 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -26,7 +26,6 @@ use ethstore::random_phrase; use sync::LightSyncProvider; use ethcore::account_provider::AccountProvider; use ethcore_logger::RotatingLogger; -use ethcore::ids::BlockId; use light::client::LightChainClient; @@ -403,28 +402,12 @@ impl Parity for ParityClient { extra_info: extra_info, }) }; - // 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`. - let id = match number.unwrap_or_default() { - BlockNumber::Num(n) => BlockId::Number(n), - BlockNumber::Earliest => BlockId::Earliest, - BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, - }; - + let id = number.unwrap_or_default().to_block_id(); Box::new(self.fetcher().header(id).and_then(from_encoded)) } fn block_receipts(&self, number: Trailing) -> BoxFuture> { - // 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`. - let id = match number.unwrap_or_default() { - BlockNumber::Num(n) => BlockId::Number(n), - BlockNumber::Earliest => BlockId::Earliest, - BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest, - }; - + let id = number.unwrap_or_default().to_block_id(); Box::new(self.fetcher().receipts(id).and_then(|receipts| Ok(receipts.into_iter().map(Into::into).collect()))) } diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 190f9725d6b..c71e6d8dc6a 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -213,6 +213,7 @@ build_rpc_trait! { /// Get block receipts. /// Allows you to fetch receipts from the entire block at once. + /// If no parameter is provided defaults to `latest`. #[rpc(name = "parity_getBlockReceipts")] fn block_receipts(&self, Trailing) -> BoxFuture>; diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index b92a0d4a3fe..082063df2b6 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -52,6 +52,22 @@ impl BlockNumber { _ => None, } } + + /// Convert block number to block id. + pub fn to_block_id(self) -> BlockId { + // 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`. + match self { + BlockNumber::Num(n) => BlockId::Number(n), + BlockNumber::Earliest => BlockId::Earliest, + BlockNumber::Latest => BlockId::Latest, + BlockNumber::Pending => { + warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`"); + BlockId::Latest + } + } + } } impl Serialize for BlockNumber { From f287e5878e9cd2da39a5dcd9bc40d13f62dc165a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 13 Sep 2018 14:12:35 +0200 Subject: [PATCH 5/6] Add block & transaction receipt tests. --- ethcore/src/client/client.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 75c3a2ae31d..db488c8d52e 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2485,6 +2485,33 @@ mod tests { assert!(client.tree_route(&genesis, &new_hash).is_none()); } + #[test] + fn should_return_block_receipts() { + use client::{BlockChainClient, BlockId, TransactionId}; + use test_helpers::{generate_dummy_client_with_data}; + + let client = generate_dummy_client_with_data(2, 2, &[1.into(), 1.into()]); + let receipts = client.block_receipts(BlockId::Latest).unwrap(); + + assert_eq!(receipts.len(), 2); + assert_eq!(receipts[0].transaction_index, 0); + assert_eq!(receipts[0].block_number, 2); + assert_eq!(receipts[0].cumulative_gas_used, 53_000.into()); + assert_eq!(receipts[0].gas_used, 53_000.into()); + + assert_eq!(receipts[1].transaction_index, 1); + assert_eq!(receipts[1].block_number, 2); + assert_eq!(receipts[1].cumulative_gas_used, 106_000.into()); + assert_eq!(receipts[1].gas_used, 53_000.into()); + + + let receipt = client.transaction_receipt(TransactionId::Hash(receipts[0].transaction_hash)); + assert_eq!(receipt, Some(receipts[0].clone())); + + let receipt = client.transaction_receipt(TransactionId::Hash(receipts[1].transaction_hash)); + assert_eq!(receipt, Some(receipts[1].clone())); + } + #[test] fn should_return_correct_log_index() { use hash::keccak; From 8bb8e78d373c28df453ef379b7853b8a759cee39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 17 Sep 2018 08:04:42 +0200 Subject: [PATCH 6/6] Fix conversion to block id. --- rpc/src/v1/impls/light/eth.rs | 2 +- rpc/src/v1/impls/light/parity.rs | 2 +- rpc/src/v1/types/block_number.rs | 11 ++++++++++- rpc/src/v1/types/mod.rs | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 5e6430bf01c..d03b2c002fb 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -46,7 +46,7 @@ use v1::helpers::{SyncPollFilter, PollManager}; use v1::helpers::light_fetch::{self, LightFetch}; use v1::traits::Eth; use v1::types::{ - RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, + RichBlock, Block, BlockTransactions, BlockNumber, LightBlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, Work, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, }; diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 6f76ca4738d..4ab456e6836 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -41,7 +41,7 @@ use v1::types::{ Bytes, U256, U64, H160, H256, H512, CallRequest, Peers, Transaction, RpcSettings, Histogram, TransactionStats, LocalTransactionStatus, - BlockNumber, ConsensusCapability, VersionInfo, + BlockNumber, LightBlockNumber, ConsensusCapability, VersionInfo, OperationsInfo, ChainStatus, AccountInfo, HwAccountInfo, Header, RichHeader, Receipt, }; diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs index 082063df2b6..085886998e2 100644 --- a/rpc/src/v1/types/block_number.rs +++ b/rpc/src/v1/types/block_number.rs @@ -52,9 +52,18 @@ impl BlockNumber { _ => None, } } +} +/// BlockNumber to BlockId conversion +/// +/// NOTE use only for light clients. +pub trait LightBlockNumber { /// Convert block number to block id. - pub fn to_block_id(self) -> BlockId { + fn to_block_id(self) -> BlockId; +} + +impl LightBlockNumber for BlockNumber { + fn to_block_id(self) -> BlockId { // 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`. diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index fe35dd50a09..eb8c0dc226c 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -49,7 +49,7 @@ pub mod pubsub; pub use self::account_info::{AccountInfo, ExtAccountInfo, HwAccountInfo}; pub use self::bytes::Bytes; pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich}; -pub use self::block_number::{BlockNumber, block_number_to_id}; +pub use self::block_number::{BlockNumber, LightBlockNumber, block_number_to_id}; pub use self::call_request::CallRequest; pub use self::confirmations::{ ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken,