RPC: parity_getBlockReceipts (#9527)
* Block receipts RPC. * Use lazy evaluation of block receipts (ecrecover). * Optimize transaction_receipt to prevent performance regression. * Fix RPC grumbles. * Add block & transaction receipt tests. * Fix conversion to block id.
This commit is contained in:
committed by
Marek Kotewicz
parent
3f95a62e4f
commit
cc963d42a0
@@ -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, l))
|
||||
})
|
||||
.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>> {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -67,23 +67,6 @@ pub struct EthClient<T> {
|
||||
gas_price_percentile: usize,
|
||||
}
|
||||
|
||||
impl<T> EthClient<T> {
|
||||
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<T> Clone for EthClient<T> {
|
||||
fn clone(&self) -> Self {
|
||||
// each instance should have its own poll manager.
|
||||
@@ -285,7 +268,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
}
|
||||
|
||||
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
|
||||
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<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
}
|
||||
|
||||
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
|
||||
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<BlockNumber>) -> BoxFuture<RpcU256> {
|
||||
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<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
|
||||
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<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
|
||||
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<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
}
|
||||
|
||||
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
|
||||
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<RpcH256> {
|
||||
@@ -438,7 +421,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
}
|
||||
|
||||
fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<Transaction>> {
|
||||
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<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
|
||||
fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<RichBlock>> {
|
||||
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)
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -42,9 +41,9 @@ 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,
|
||||
AccountInfo, HwAccountInfo, Header, RichHeader, Receipt,
|
||||
};
|
||||
use Host;
|
||||
|
||||
@@ -403,18 +402,15 @@ 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<BlockNumber>) -> BoxFuture<Vec<Receipt>> {
|
||||
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())))
|
||||
}
|
||||
|
||||
fn ipfs_cid(&self, content: Bytes) -> Result<String> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
|
||||
@@ -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<C, M, U, S> Parity for ParityClient<C, M, U> where
|
||||
|
||||
fn ws_url(&self) -> Result<String> {
|
||||
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<U256> {
|
||||
@@ -387,7 +387,8 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> 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<C, M, U, S> Parity for ParityClient<C, M, U> 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<C, M, U, S> Parity for ParityClient<C, M, U> where
|
||||
}))
|
||||
}
|
||||
|
||||
fn block_receipts(&self, number: Trailing<BlockNumber>) -> BoxFuture<Vec<Receipt>> {
|
||||
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<String> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
@@ -427,8 +449,8 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> 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<C, M, U, S> Parity for ParityClient<C, M, U> 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)
|
||||
};
|
||||
|
||||
@@ -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<BTreeMap<H256, LocalTransactionStatus>>,
|
||||
/// Pre-existed pending receipts
|
||||
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
||||
pub pending_receipts: Mutex<Vec<RichReceipt>>,
|
||||
/// Next nonces.
|
||||
pub next_nonces: RwLock<HashMap<Address, U256>>,
|
||||
/// 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<RichReceipt> {
|
||||
// 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<BTreeMap<H256, Receipt>> {
|
||||
fn pending_receipts(&self, _best_block: BlockNumber) -> Option<Vec<RichReceipt>> {
|
||||
Some(self.pending_receipts.lock().clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
@@ -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,12 @@ build_rpc_trait! {
|
||||
#[rpc(name = "parity_getBlockHeaderByNumber")]
|
||||
fn block_header(&self, Trailing<BlockNumber>) -> BoxFuture<RichHeader>;
|
||||
|
||||
/// 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<BlockNumber>) -> BoxFuture<Vec<Receipt>>;
|
||||
|
||||
/// Get IPFS CIDv0 given protobuf encoded bytes.
|
||||
#[rpc(name = "parity_cidV0")]
|
||||
fn ipfs_cid(&self, Bytes) -> Result<String>;
|
||||
|
||||
@@ -54,6 +54,31 @@ impl BlockNumber {
|
||||
}
|
||||
}
|
||||
|
||||
/// BlockNumber to BlockId conversion
|
||||
///
|
||||
/// NOTE use only for light clients.
|
||||
pub trait LightBlockNumber {
|
||||
/// Convert block number to block id.
|
||||
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`.
|
||||
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 {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||
match *self {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user