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

RPC: Block number to block hash #584

Merged
merged 5 commits into from
Aug 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion substrate/codec/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
//! Derives serialization and deserialization codec for complex structs for simple marshalling.

#![cfg_attr(not(feature = "std"), no_std)]
//#![cfg_attr(not(feature = "std"), feature(alloc))]

extern crate proc_macro;
extern crate proc_macro2;
Expand Down
4 changes: 2 additions & 2 deletions substrate/rpc-servers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extern crate substrate_runtime_primitives;
extern crate log;

use std::io;
use substrate_runtime_primitives::traits::Block as BlockT;
use substrate_runtime_primitives::traits::{Block as BlockT, NumberFor};

type Metadata = apis::metadata::Metadata;
type RpcHandler = pubsub::PubSubHandler<Metadata>;
Expand All @@ -49,7 +49,7 @@ pub fn rpc_handler<Block: BlockT, ExHash, PendingExtrinsics, S, C, A, Y>(
ExHash: Send + Sync + 'static + substrate_runtime_primitives::Serialize + substrate_runtime_primitives::DeserializeOwned,
PendingExtrinsics: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static,
S: apis::state::StateApi<Block::Hash, Metadata=Metadata>,
C: apis::chain::ChainApi<Block::Hash, Block::Header, Block::Extrinsic, Metadata=Metadata>,
C: apis::chain::ChainApi<Block::Hash, Block::Header, NumberFor<Block>, Block::Extrinsic, Metadata=Metadata>,
A: apis::author::AuthorApi<ExHash, Block::Extrinsic, PendingExtrinsics, Metadata=Metadata>,
Y: apis::system::SystemApi,
{
Expand Down
38 changes: 22 additions & 16 deletions substrate/rpc/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@
use std::sync::Arc;

use client::{self, Client, BlockchainEvents};
use jsonrpc_macros::pubsub;
use jsonrpc_macros::{pubsub, Trailing};
use jsonrpc_pubsub::SubscriptionId;
use jsonrpc_macros::Trailing;
use rpc::Result as RpcResult;
use rpc::futures::{stream, Future, Sink, Stream};
use runtime_primitives::generic::{BlockId, SignedBlock};
use runtime_primitives::traits::Block as BlockT;
use runtime_primitives::traits::{Block as BlockT, Header, NumberFor};
use runtime_version::RuntimeVersion;
use tokio::runtime::TaskExecutor;
use primitives::{KeccakHasher, RlpCodec};
Expand All @@ -40,20 +39,22 @@ use self::error::Result;

build_rpc_trait! {
/// Polkadot blockchain API
pub trait ChainApi<Hash, Header, Extrinsic> {
pub trait ChainApi<Hash, Header, Number, Extrinsic> {
Copy link
Member

Choose a reason for hiding this comment

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

Why not just use Header::Number?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can't specify bounds in build_rpc_trait macro.

type Metadata;

/// Get header of a relay chain block.
#[rpc(name = "chain_getHeader")]
fn header(&self, Hash) -> Result<Option<Header>>;
fn header(&self, Trailing<Hash>) -> Result<Option<Header>>;

/// Get header and body of a relay chain block.
#[rpc(name = "chain_getBlock")]
fn block(&self, Hash) -> Result<Option<SignedBlock<Header, Extrinsic, Hash>>>;
fn block(&self, Trailing<Hash>) -> Result<Option<SignedBlock<Header, Extrinsic, Hash>>>;

/// Get hash of the head.
#[rpc(name = "chain_getHead")]
fn head(&self) -> Result<Hash>;
/// Get hash of the n-th block in the canon chain.
///
/// By default returns latest block hash.
#[rpc(name = "chain_getBlockHash", alias = ["chain_getHead", ])]
fn block_hash(&self, Trailing<Number>) -> Result<Option<Hash>>;

/// Get the runtime version.
#[rpc(name = "chain_getRuntimeVersion")]
Expand Down Expand Up @@ -102,23 +103,28 @@ impl<B, E, Block> Chain<B, E, Block> where
}
}

impl<B, E, Block> ChainApi<Block::Hash, Block::Header, Block::Extrinsic> for Chain<B, E, Block> where
impl<B, E, Block> ChainApi<Block::Hash, Block::Header, NumberFor<Block>, Block::Extrinsic> for Chain<B, E, Block> where
Block: BlockT + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: client::CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
{
type Metadata = ::metadata::Metadata;

fn header(&self, hash: Block::Hash) -> Result<Option<Block::Header>> {
fn header(&self, hash: Trailing<Block::Hash>) -> Result<Option<Block::Header>> {
let hash = self.unwrap_or_best(hash)?;
Ok(self.client.header(&BlockId::Hash(hash))?)
}

fn block(&self, hash: Block::Hash) -> Result<Option<SignedBlock<Block::Header, Block::Extrinsic, Block::Hash>>> {
fn block(&self, hash: Trailing<Block::Hash>) -> Result<Option<SignedBlock<Block::Header, Block::Extrinsic, Block::Hash>>> {
let hash = self.unwrap_or_best(hash)?;
Ok(self.client.block(&BlockId::Hash(hash))?)
}

fn head(&self) -> Result<Block::Hash> {
Ok(self.client.info()?.chain.best_hash)
fn block_hash(&self, number: Trailing<NumberFor<Block>>) -> Result<Option<Block::Hash>> {
Ok(match number.into() {
None => Some(self.client.info()?.chain.best_hash),
Some(number) => self.client.header(&BlockId::number(number))?.map(|h| h.hash()),
})
}

fn runtime_version(&self, at: Trailing<Block::Hash>) -> Result<RuntimeVersion> {
Expand All @@ -129,8 +135,8 @@ impl<B, E, Block> ChainApi<Block::Hash, Block::Header, Block::Extrinsic> for Cha
fn subscribe_new_head(&self, _metadata: Self::Metadata, subscriber: pubsub::Subscriber<Block::Header>) {
self.subscriptions.add(subscriber, |sink| {
// send current head right at the start.
let header = self.head()
.and_then(|hash| self.header(hash))
let header = self.block_hash(None.into())
.and_then(|hash| self.header(hash.into()))
.and_then(|header| {
header.ok_or_else(|| self::error::ErrorKind::Unimplemented.into())
})
Expand Down
76 changes: 71 additions & 5 deletions substrate/rpc/src/chain/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ fn should_return_header() {
client: Arc::new(test_client::new()),
subscriptions: Subscriptions::new(remote),
};

assert_matches!(
client.header(client.client.genesis_hash()),
client.header(Some(client.client.genesis_hash()).into()),
Ok(Some(ref x)) if x == &Header {
parent_hash: 0.into(),
number: 0,
Expand All @@ -41,7 +42,18 @@ fn should_return_header() {
);

assert_matches!(
client.header(5.into()),
client.header(None.into()),
Ok(Some(ref x)) if x == &Header {
parent_hash: 0.into(),
number: 0,
state_root: x.state_root.clone(),
extrinsics_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".into(),
digest: Default::default(),
}
);

assert_matches!(
client.header(Some(5.into()).into()),
Ok(None)
);
}
Expand All @@ -63,12 +75,26 @@ fn should_return_a_block() {

// Genesis block is not justified, so we can't query it?
assert_matches!(
api.block(api.client.genesis_hash()),
api.block(Some(api.client.genesis_hash()).into()),
Ok(None)
);

assert_matches!(
api.block(block_hash),
api.block(Some(block_hash).into()),
Ok(Some(ref x)) if x.block == Block {
header: Header {
parent_hash: api.client.genesis_hash(),
number: 1,
state_root: x.block.header.state_root.clone(),
extrinsics_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".into(),
digest: Default::default(),
},
extrinsics: vec![],
}
);

assert_matches!(
api.block(None.into()),
Ok(Some(ref x)) if x.block == Block {
header: Header {
parent_hash: api.client.genesis_hash(),
Expand All @@ -82,9 +108,49 @@ fn should_return_a_block() {
);

assert_matches!(
api.block(5.into()),
api.block(Some(5.into()).into()),
Ok(None)
);
}

#[test]
fn should_return_block_hash() {
let core = ::tokio::runtime::Runtime::new().unwrap();
let remote = core.executor();

let client = Chain {
client: Arc::new(test_client::new()),
subscriptions: Subscriptions::new(remote),
};

assert_matches!(
client.block_hash(None.into()),
Ok(Some(ref x)) if x == &client.client.genesis_hash()
);


assert_matches!(
client.block_hash(Some(0u64).into()),
Ok(Some(ref x)) if x == &client.client.genesis_hash()
);

assert_matches!(
client.block_hash(Some(1u64).into()),
Ok(None)
);

let block = client.client.new_block().unwrap().bake().unwrap();
client.client.justify_and_import(BlockOrigin::Own, block.clone()).unwrap();

assert_matches!(
client.block_hash(Some(0u64).into()),
Ok(Some(ref x)) if x == &client.client.genesis_hash()
);
assert_matches!(
client.block_hash(Some(1u64).into()),
Ok(Some(ref x)) if x == &block.hash()
);

}

#[test]
Expand Down
25 changes: 25 additions & 0 deletions substrate/rpc/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2018 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/>.

/// Unwraps the trailing parameter or falls back with the closure result.
pub fn unwrap_or_else<F, H, E>(or_else: F, optional: ::jsonrpc_macros::Trailing<H>) -> Result<H, E> where
F: FnOnce() -> Result<H, E>,
{
match optional.into() {
None => or_else(),
Some(x) => Ok(x),
}
}
1 change: 1 addition & 0 deletions substrate/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern crate substrate_test_client as test_client;
extern crate rustc_hex;

mod errors;
mod helpers;
mod subscriptions;

pub mod author;
Expand Down
11 changes: 4 additions & 7 deletions substrate/rpc/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,12 @@ impl<B, E, Block: BlockT> State<B, E, Block> {
}

impl<B, E, Block> State<B, E, Block> where
Block: BlockT + 'static,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
E: CallExecutor<Block, KeccakHasher, RlpCodec> + Send + Sync + 'static,
Block: BlockT,
B: client::backend::Backend<Block, KeccakHasher, RlpCodec>,
E: CallExecutor<Block, KeccakHasher, RlpCodec>,
{
fn unwrap_or_best(&self, hash: Trailing<Block::Hash>) -> Result<Block::Hash> {
Ok(match hash.into() {
None => self.client.info()?.chain.best_hash,
Some(hash) => hash,
})
::helpers::unwrap_or_else(|| Ok(self.client.info()?.chain.best_hash), hash)
}
}

Expand Down