mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 19:21:13 +00:00
Allow batch query for block hash. (#4210)
This commit is contained in:
committed by
Gavin Wood
parent
70bc6eaed6
commit
cfb590ac4b
Generated
+1
@@ -6275,6 +6275,7 @@ name = "substrate-rpc-primitives"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"substrate-primitives 2.0.0",
|
||||
]
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use jsonrpc_core::Result as RpcResult;
|
||||
use jsonrpc_core::futures::Future;
|
||||
use jsonrpc_derive::rpc;
|
||||
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
|
||||
use rpc_primitives::number;
|
||||
use rpc_primitives::{number::NumberOrHex, list::ListOrValue};
|
||||
use self::error::{FutureResult, Result};
|
||||
|
||||
pub use self::gen_client::Client as ChainClient;
|
||||
@@ -45,7 +45,10 @@ pub trait ChainApi<Number, Hash, Header, SignedBlock> {
|
||||
///
|
||||
/// By default returns latest block hash.
|
||||
#[rpc(name = "chain_getBlockHash", alias("chain_getHead"))]
|
||||
fn block_hash(&self, hash: Option<number::NumberOrHex<Number>>) -> Result<Option<Hash>>;
|
||||
fn block_hash(
|
||||
&self,
|
||||
hash: Option<ListOrValue<NumberOrHex<Number>>>,
|
||||
) -> Result<ListOrValue<Option<Hash>>>;
|
||||
|
||||
/// Get hash of the last finalized block in the canon chain.
|
||||
#[rpc(name = "chain_getFinalizedHead", alias("chain_getFinalisedHead"))]
|
||||
@@ -67,7 +70,11 @@ pub trait ChainApi<Number, Hash, Header, SignedBlock> {
|
||||
name = "chain_unsubscribeNewHeads",
|
||||
alias("unsubscribe_newHead", "chain_unsubscribeNewHead")
|
||||
)]
|
||||
fn unsubscribe_new_heads(&self, metadata: Option<Self::Metadata>, id: SubscriptionId) -> RpcResult<bool>;
|
||||
fn unsubscribe_new_heads(
|
||||
&self,
|
||||
metadata: Option<Self::Metadata>,
|
||||
id: SubscriptionId,
|
||||
) -> RpcResult<bool>;
|
||||
|
||||
/// New head subscription
|
||||
#[pubsub(
|
||||
@@ -85,5 +92,9 @@ pub trait ChainApi<Number, Hash, Header, SignedBlock> {
|
||||
name = "chain_unsubscribeFinalizedHeads",
|
||||
alias("chain_unsubscribeFinalisedHeads")
|
||||
)]
|
||||
fn unsubscribe_finalized_heads(&self, metadata: Option<Self::Metadata>, id: SubscriptionId) -> RpcResult<bool>;
|
||||
fn unsubscribe_finalized_heads(
|
||||
&self,
|
||||
metadata: Option<Self::Metadata>,
|
||||
id: SubscriptionId,
|
||||
) -> RpcResult<bool>;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use client::{
|
||||
};
|
||||
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
|
||||
use primitives::{H256, Blake2Hasher};
|
||||
use rpc_primitives::number;
|
||||
use rpc_primitives::{number::NumberOrHex, list::ListOrValue};
|
||||
use sr_primitives::{
|
||||
generic::{BlockId, SignedBlock},
|
||||
traits::{Block as BlockT, Header, NumberFor},
|
||||
@@ -79,7 +79,7 @@ trait ChainBackend<B, E, Block: BlockT, RA>: Send + Sync + 'static
|
||||
/// By default returns latest block hash.
|
||||
fn block_hash(
|
||||
&self,
|
||||
number: Option<number::NumberOrHex<NumberFor<Block>>>,
|
||||
number: Option<NumberOrHex<NumberFor<Block>>>,
|
||||
) -> Result<Option<Block::Hash>> {
|
||||
Ok(match number {
|
||||
None => Some(self.client().info().chain.best_hash),
|
||||
@@ -211,8 +211,19 @@ impl<B, E, Block, RA> ChainApi<NumberFor<Block>, Block::Hash, Block::Header, Sig
|
||||
self.backend.block(hash)
|
||||
}
|
||||
|
||||
fn block_hash(&self, number: Option<number::NumberOrHex<NumberFor<Block>>>) -> Result<Option<Block::Hash>> {
|
||||
self.backend.block_hash(number)
|
||||
fn block_hash(
|
||||
&self,
|
||||
number: Option<ListOrValue<NumberOrHex<NumberFor<Block>>>>
|
||||
) -> Result<ListOrValue<Option<Block::Hash>>> {
|
||||
match number {
|
||||
None => self.backend.block_hash(None).map(ListOrValue::Value),
|
||||
Some(ListOrValue::Value(number)) => self.backend.block_hash(Some(number)).map(ListOrValue::Value),
|
||||
Some(ListOrValue::List(list)) => Ok(ListOrValue::List(list
|
||||
.into_iter()
|
||||
.map(|number| self.backend.block_hash(Some(number)))
|
||||
.collect::<Result<_>>()?
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn finalized_head(&self) -> Result<Block::Hash> {
|
||||
|
||||
@@ -21,6 +21,7 @@ use test_client::{
|
||||
consensus::BlockOrigin,
|
||||
runtime::{H256, Block, Header},
|
||||
};
|
||||
use rpc_primitives::list::ListOrValue;
|
||||
|
||||
#[test]
|
||||
fn should_return_header() {
|
||||
@@ -120,34 +121,39 @@ fn should_return_block_hash() {
|
||||
|
||||
assert_matches!(
|
||||
api.block_hash(None.into()),
|
||||
Ok(Some(ref x)) if x == &client.genesis_hash()
|
||||
Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash()
|
||||
);
|
||||
|
||||
|
||||
assert_matches!(
|
||||
api.block_hash(Some(0u64.into()).into()),
|
||||
Ok(Some(ref x)) if x == &client.genesis_hash()
|
||||
api.block_hash(Some(ListOrValue::Value(0u64.into())).into()),
|
||||
Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash()
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
api.block_hash(Some(1u64.into()).into()),
|
||||
Ok(None)
|
||||
api.block_hash(Some(ListOrValue::Value(1u64.into())).into()),
|
||||
Ok(ListOrValue::Value(None))
|
||||
);
|
||||
|
||||
let block = client.new_block(Default::default()).unwrap().bake().unwrap();
|
||||
client.import(BlockOrigin::Own, block.clone()).unwrap();
|
||||
|
||||
assert_matches!(
|
||||
api.block_hash(Some(0u64.into()).into()),
|
||||
Ok(Some(ref x)) if x == &client.genesis_hash()
|
||||
api.block_hash(Some(ListOrValue::Value(0u64.into())).into()),
|
||||
Ok(ListOrValue::Value(Some(ref x))) if x == &client.genesis_hash()
|
||||
);
|
||||
assert_matches!(
|
||||
api.block_hash(Some(1u64.into()).into()),
|
||||
Ok(Some(ref x)) if x == &block.hash()
|
||||
api.block_hash(Some(ListOrValue::Value(1u64.into())).into()),
|
||||
Ok(ListOrValue::Value(Some(ref x))) if x == &block.hash()
|
||||
);
|
||||
assert_matches!(
|
||||
api.block_hash(Some(::primitives::U256::from(1u64).into()).into()),
|
||||
Ok(Some(ref x)) if x == &block.hash()
|
||||
api.block_hash(Some(ListOrValue::Value(primitives::U256::from(1u64).into())).into()),
|
||||
Ok(ListOrValue::Value(Some(ref x))) if x == &block.hash()
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
api.block_hash(Some(vec![0u64.into(), 1.into(), 2.into()].into())),
|
||||
Ok(ListOrValue::List(list)) if list == &[client.genesis_hash().into(), block.hash().into(), None]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,3 +7,6 @@ edition = "2018"
|
||||
[dependencies]
|
||||
serde = { version = "1.0.101", features = ["derive"] }
|
||||
primitives = { package = "substrate-primitives", path = "../core" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json = "1.0.41"
|
||||
|
||||
@@ -19,3 +19,20 @@
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod number;
|
||||
pub mod list;
|
||||
|
||||
/// A util function to assert the result of serialization and deserialization is the same.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn assert_deser<T>(s: &str, expected: T) where
|
||||
T: std::fmt::Debug + serde::ser::Serialize + serde::de::DeserializeOwned + PartialEq
|
||||
{
|
||||
assert_eq!(
|
||||
serde_json::from_str::<T>(s).unwrap(),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
serde_json::to_string(&expected).unwrap(),
|
||||
s
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2019 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Substrate is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! RPC a lenient list or value type.
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// RPC list or value wrapper.
|
||||
///
|
||||
/// For some RPCs it's convenient to call them with either
|
||||
/// a single value or a whole list of values to get a proper response.
|
||||
/// In theory you could do a batch query, but it's:
|
||||
/// 1. Less convient in client libraries
|
||||
/// 2. If the response value is small, the protocol overhead might be dominant.
|
||||
///
|
||||
/// Also it's nice to be able to maintain backward compatibility for methods that
|
||||
/// were initially taking a value and now we want to expand them to take a list.
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum ListOrValue<T> {
|
||||
/// A list of values of given type.
|
||||
List(Vec<T>),
|
||||
/// A single value of given type.
|
||||
Value(T),
|
||||
}
|
||||
|
||||
impl<T> ListOrValue<T> {
|
||||
/// Map every contained value using function `F`.
|
||||
///
|
||||
/// This allows to easily convert all values in any of the variants.
|
||||
pub fn map<F: Fn(T) -> X, X>(self, f: F) -> ListOrValue<X> {
|
||||
match self {
|
||||
ListOrValue::List(v) => ListOrValue::List(v.into_iter().map(f).collect()),
|
||||
ListOrValue::Value(v) => ListOrValue::Value(f(v)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for ListOrValue<T> {
|
||||
fn from(n: T) -> Self {
|
||||
ListOrValue::Value(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Vec<T>> for ListOrValue<T> {
|
||||
fn from(n: Vec<T>) -> Self {
|
||||
ListOrValue::List(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::assert_deser;
|
||||
|
||||
#[test]
|
||||
fn should_serialize_and_deserialize() {
|
||||
assert_deser(r#"5"#, ListOrValue::Value(5_u64));
|
||||
assert_deser(r#""str""#, ListOrValue::Value("str".to_string()));
|
||||
assert_deser(r#"[1,2,3]"#, ListOrValue::List(vec![1_u64, 2_u64, 3_u64]));
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ use primitives::U256;
|
||||
/// or we attempt to parse given hex value.
|
||||
/// We do that for consistency with the returned type, default generic header
|
||||
/// serializes block number as hex to avoid overflows in JavaScript.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum NumberOrHex<Number> {
|
||||
/// The original header number type of block.
|
||||
@@ -72,3 +72,18 @@ impl<Number> From<U256> for NumberOrHex<Number> {
|
||||
NumberOrHex::Hex(n)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::assert_deser;
|
||||
|
||||
#[test]
|
||||
fn should_serialize_and_deserialize() {
|
||||
assert_deser(r#""0x1234""#, NumberOrHex::<u128>::Hex(0x1234.into()));
|
||||
assert_deser(r#""0x0""#, NumberOrHex::<u64>::Hex(0.into()));
|
||||
assert_deser(r#"5"#, NumberOrHex::Number(5_u64));
|
||||
assert_deser(r#"10000"#, NumberOrHex::Number(10000_u32));
|
||||
assert_deser(r#"0"#, NumberOrHex::Number(0_u16));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user