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

Commit 11ee362

Browse files
bkchrgavofyork
authored andcommitted
Implements json_metadata RPC call (#692)
* Adds `impl_json_metadata!` for generating all metadata of a runtime * Adds `json_metadata` RPC call * Adds simple test for the `json_metadata` RPC call * Implements json metadata in the demo runtime * Fix indent * Adds missing copyright headers * Dispatch json metadata renamings and improvements * Replaces `format!` & `String` with `Vec<JSONMetadata` * Implements `Encode` and `Decode` for JSONMetadata * Make `impl_json_metadata!` compileable on `no_std` * Adapt the client to decode the correct type for `json_metadata` * Fixes compile error and warning * Whitespace
1 parent 68137ae commit 11ee362

File tree

13 files changed

+470
-10
lines changed

13 files changed

+470
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/runtime/src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,22 @@ pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Index, Call>;
270270
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances,
271271
(((((((), Treasury), Council), Democracy), Staking), Session), Timestamp)>;
272272

273+
impl_json_metadata!(
274+
for Runtime with modules
275+
system::Module with Storage,
276+
balances::Module with Storage,
277+
consensus::Module with Storage,
278+
timestamp::Module with Storage,
279+
session::Module with Storage,
280+
staking::Module with Storage,
281+
democracy::Module with Storage,
282+
council::Module with Storage
283+
);
284+
273285
pub mod api {
274286
impl_stubs!(
275287
version => |()| super::VERSION,
288+
json_metadata => |()| super::Runtime::json_metadata(),
276289
authorities => |()| super::Consensus::authorities(),
277290
initialise_block => |header| super::Executive::initialise_block(&header),
278291
apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic),

substrate/client/src/client.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use primitives::AuthorityId;
2323
use runtime_primitives::{bft::Justification, generic::{BlockId, SignedBlock, Block as RuntimeBlock}};
2424
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, Zero, One, As, NumberFor};
2525
use runtime_primitives::BuildStorage;
26+
use runtime_support::metadata::JSONMetadataDecodable;
2627
use primitives::{KeccakHasher, RlpCodec};
2728
use primitives::storage::{StorageKey, StorageData};
2829
use codec::{Encode, Decode};
@@ -251,6 +252,28 @@ impl<B, E, Block> Client<B, E, Block> where
251252
&self.executor
252253
}
253254

255+
/// Returns the runtime metadata as JSON.
256+
pub fn json_metadata(&self, id: &BlockId<Block>) -> error::Result<String> {
257+
self.executor.call(id, "json_metadata",&[])
258+
.and_then(|r| Vec::<JSONMetadataDecodable>::decode(&mut &r.return_data[..])
259+
.ok_or("JSON Metadata decoding failed".into()))
260+
.and_then(|metadata| {
261+
let mut json = metadata.into_iter().enumerate().fold(String::from("{"),
262+
|mut json, (i, m)| {
263+
if i > 0 {
264+
json.push_str(",");
265+
}
266+
let (mtype, val) = m.into_json_string();
267+
json.push_str(&format!(r#" "{}": {}"#, mtype, val));
268+
json
269+
}
270+
);
271+
json.push_str(" }");
272+
273+
Ok(json)
274+
})
275+
}
276+
254277
/// Reads storage value at a given block + key, returning read proof.
255278
pub fn read_proof(&self, id: &BlockId<Block>, key: &[u8]) -> error::Result<Vec<Vec<u8>>> {
256279
self.state_at(id)
@@ -756,4 +779,29 @@ mod tests {
756779
assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap());
757780
assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1)
758781
}
782+
783+
#[test]
784+
fn json_metadata() {
785+
let client = test_client::new();
786+
787+
let mut builder = client.new_block().unwrap();
788+
789+
builder.push_transfer(Transfer {
790+
from: Keyring::Alice.to_raw_public().into(),
791+
to: Keyring::Ferdie.to_raw_public().into(),
792+
amount: 42,
793+
nonce: 0,
794+
}).unwrap();
795+
796+
assert!(builder.push_transfer(Transfer {
797+
from: Keyring::Eve.to_raw_public().into(),
798+
to: Keyring::Alice.to_raw_public().into(),
799+
amount: 42,
800+
nonce: 0,
801+
}).is_err());
802+
803+
client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap();
804+
805+
assert_eq!(client.json_metadata(&BlockId::Number(1)).unwrap(), r#"{ "events": "events" }"#);
806+
}
759807
}

substrate/rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ substrate-runtime-primitives = { path = "../runtime/primitives" }
1919
substrate-runtime-version = { path = "../runtime/version" }
2020
substrate-state-machine = { path = "../state-machine" }
2121
tokio = "0.1.7"
22+
serde_json = "1.0"
2223

2324
[dev-dependencies]
2425
assert_matches = "1.1"

substrate/rpc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern crate substrate_runtime_primitives as runtime_primitives;
2929
extern crate substrate_state_machine as state_machine;
3030
extern crate substrate_runtime_version as runtime_version;
3131
extern crate tokio;
32+
extern crate serde_json;
3233

3334
#[macro_use]
3435
extern crate error_chain;

substrate/rpc/src/state/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ use rpc;
1919

2020
use errors;
2121

22+
use serde_json;
23+
2224
error_chain! {
2325
links {
2426
Client(client::error::Error, client::error::ErrorKind) #[doc = "Client error"];
2527
}
2628

29+
foreign_links {
30+
Json(serde_json::Error);
31+
}
32+
2733
errors {
2834
/// Provided block range couldn't be resolved to a list of blocks.
2935
InvalidBlockRange(from: String, to: String, details: String) {

substrate/rpc/src/state/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use rpc::futures::{stream, Future, Sink, Stream};
3333
use runtime_primitives::generic::BlockId;
3434
use runtime_primitives::traits::{Block as BlockT, Header};
3535
use tokio::runtime::TaskExecutor;
36+
use serde_json;
3637

3738
use subscriptions::Subscriptions;
3839

@@ -63,6 +64,10 @@ build_rpc_trait! {
6364
#[rpc(name = "state_getStorageSize", alias = ["state_getStorageSizeAt", ])]
6465
fn storage_size(&self, StorageKey, Trailing<Hash>) -> Result<Option<u64>>;
6566

67+
/// Returns the runtime metadata as JSON.
68+
#[rpc(name = "state_metadata", alias = ["state_metadataAt", ])]
69+
fn json_metadata(&self, Trailing<Hash>) -> Result<serde_json::Value>;
70+
6671
/// Query historical storage entries (by key) starting from a block given as the second parameter.
6772
///
6873
/// NOTE This first returned result contains the initial state of storage for all keys.
@@ -138,6 +143,12 @@ impl<B, E, Block> StateApi<Block::Hash> for State<B, E, Block> where
138143
Ok(self.storage(key, block)?.map(|x| x.0.len() as u64))
139144
}
140145

146+
fn json_metadata(&self, block: Trailing<Block::Hash>) -> Result<serde_json::Value> {
147+
let block = self.unwrap_or_best(block)?;
148+
let metadata = self.client.json_metadata(&BlockId::Hash(block))?;
149+
serde_json::from_str(&metadata).map_err(Into::into)
150+
}
151+
141152
fn query_storage(&self, keys: Vec<StorageKey>, from: Block::Hash, to: Trailing<Block::Hash>) -> Result<Vec<StorageChangeSet<Block::Hash>>> {
142153
let to = self.unwrap_or_best(to)?;
143154

substrate/runtime-support/src/dispatch.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ macro_rules! decl_module {
213213
}
214214
}
215215

216-
__impl_json_metadata! {
216+
__dispatch_impl_json_metadata! {
217217
$mod_type $trait_instance $trait_name $call_type $origin_type
218218
{$( $(#[doc = $doc_attr])* fn $fn_name(origin $(, $param_name : $param )*) -> $result; )*}
219219
}
@@ -240,7 +240,7 @@ macro_rules! __impl_decode {
240240
)*
241241
return Some($call_type:: $fn_name( $( $param_name ),* ));
242242
}
243-
243+
244244
__impl_decode!($input; $input_id; $fn_id + 1; $call_type; $($rest)*)
245245
}
246246
};
@@ -278,7 +278,7 @@ macro_rules! __impl_encode {
278278
$param_name.encode_to($dest);
279279
)*
280280
}
281-
281+
282282
__impl_encode!($dest; $self; $fn_id + 1; $call_type; $($rest)*)
283283
}
284284
};
@@ -368,15 +368,15 @@ macro_rules! __impl_outer_dispatch_common {
368368
/// Implement the `json_metadata` function.
369369
#[macro_export]
370370
#[doc(hidden)]
371-
macro_rules! __impl_json_metadata {
371+
macro_rules! __dispatch_impl_json_metadata {
372372
(
373373
$mod_type:ident $trait_instance:ident $trait_name:ident
374374
$($rest:tt)*
375375
) => {
376376
impl<$trait_instance: $trait_name> $mod_type<$trait_instance> {
377377
pub fn json_metadata() -> &'static str {
378-
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "call": [ "#,
379-
__call_to_json!($($rest)*), " ] }")
378+
concat!(r#"{ "name": ""#, stringify!($mod_type), r#"", "call": "#,
379+
__call_to_json!($($rest)*), " }")
380380
}
381381
}
382382
}
@@ -536,7 +536,7 @@ mod tests {
536536
}
537537

538538
const EXPECTED_METADATA: &str = concat!(
539-
r#"{ "name": "Module", "call": [ "#,
539+
r#"{ "name": "Module", "call": "#,
540540
r#"{ "name": "Call", "functions": { "#,
541541
r#""0": { "name": "aux_0", "params": [ "#,
542542
r#"{ "name": "origin", "type": "T::Origin" }"#,
@@ -551,7 +551,7 @@ mod tests {
551551
r#"{ "name": "data2", "type": "String" }"#,
552552
r#" ], "description": [ ] }"#,
553553
r#" } }"#,
554-
r#" ] }"#,
554+
r#" }"#,
555555
);
556556

557557
impl<T: Trait> Module<T> {
@@ -581,4 +581,4 @@ mod tests {
581581
let _: serde::de::IgnoredAny =
582582
serde_json::from_str(metadata).expect("Is valid json syntax");
583583
}
584-
}
584+
}

substrate/runtime-support/src/event.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
// Copyright 2018 Parity Technologies (UK) Ltd.
2+
// This file is part of Substrate.
3+
4+
// Substrate is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
9+
// Substrate is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
14+
// You should have received a copy of the GNU General Public License
15+
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
16+
117
#[macro_export]
218
macro_rules! impl_outer_event {
319
($(#[$attr:meta])* pub enum $name:ident for $runtime:ident { $( $module:ident ),* }) => {

substrate/runtime-support/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
//! Support code for the runtime.
1818
1919
#![cfg_attr(not(feature = "std"), no_std)]
20+
#![cfg_attr(not(feature = "std"), feature(alloc))]
21+
22+
#[cfg(not(feature = "std"))]
23+
extern crate alloc;
2024

2125
#[cfg(feature = "std")]
2226
extern crate serde;
@@ -41,12 +45,21 @@ extern crate substrate_codec_derive;
4145
pub extern crate substrate_codec as codec;
4246
pub use self::storage::generator::Storage as GenericStorage;
4347

48+
#[cfg(feature = "std")]
49+
pub mod alloc {
50+
pub use std::boxed;
51+
pub use std::vec;
52+
}
53+
4454
#[macro_use]
4555
pub mod dispatch;
56+
#[macro_use]
4657
pub mod storage;
4758
mod hashable;
4859
#[macro_use]
4960
mod event;
61+
#[macro_use]
62+
pub mod metadata;
5063

5164
pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap};
5265
pub use self::hashable::Hashable;
@@ -169,7 +182,7 @@ macro_rules! impl_outer_origin {
169182
impl_outer_origin! {
170183
$(#[$attr])*
171184
pub enum $name for $trait where system = system {
172-
$( $module ),*
185+
$( $module ),*
173186
}
174187
}
175188
}

0 commit comments

Comments
 (0)