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

rpc: Implement chainSpec RPC API #12261

Merged
merged 10 commits into from
Sep 20, 2022
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ members = [
"client/rpc",
"client/rpc-api",
"client/rpc-servers",
"client/rpc-spec-v2",
"client/service",
"client/service/test",
"client/state-db",
Expand Down
1 change: 1 addition & 0 deletions bin/node/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality
sc-finality-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/finality-grandpa/rpc" }
sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" }
sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" }
sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../../../client/rpc-spec-v2" }
sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" }
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" }
sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" }
Expand Down
6 changes: 6 additions & 0 deletions bin/node/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ where
use sc_consensus_babe_rpc::{Babe, BabeApiServer};
use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer};
use sc_rpc::dev::{Dev, DevApiServer};
use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer};
use sc_sync_state_rpc::{SyncState, SyncStateApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer};
Expand All @@ -140,6 +141,11 @@ where
finality_provider,
} = grandpa;

let chain_name = chain_spec.name().to_string();
let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
let properties = chain_spec.properties();
io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?;

io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
// Making synchronous calls in light client freezes the browser currently,
// more context: https://github.com/paritytech/substrate/pull/3480
Expand Down
1 change: 0 additions & 1 deletion client/rpc-servers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ fn build_rpc_api<M: Send + Sync + 'static>(mut rpc_api: RpcModule<M>) -> RpcModu
rpc_api
.register_method("rpc_methods", move |_, _| {
Ok(serde_json::json!({
"version": 1,
"methods": available_methods,
}))
})
Expand Down
23 changes: 23 additions & 0 deletions client/rpc-spec-v2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "sc-rpc-spec-v2"
version = "0.10.0-dev"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Substrate RPC interface v2."
readme = "README.md"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
jsonrpsee = { version = "0.15.1", features = ["server", "macros"] }
# Internal chain structures for "chain_spec".
sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" }
hex = "0.4"

[dev-dependencies]
serde_json = "1.0"
tokio = { version = "1.17.0", features = ["macros"] }
5 changes: 5 additions & 0 deletions client/rpc-spec-v2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Substrate RPC interfaces.

A collection of RPC methods and subscriptions supported by all substrate clients.

License: GPL-3.0-or-later WITH Classpath-exception-2.0
53 changes: 53 additions & 0 deletions client/rpc-spec-v2/src/chain_spec/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// This file is part of Substrate.

// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! API trait of the chain spec.

use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use sc_chain_spec::Properties;

#[rpc(client, server)]
pub trait ChainSpecApi {
/// Get the chain name, as present in the chain specification.
///
/// # Unstable
///
/// This method is unstable and subject to change in the future.
Copy link
Contributor

@kianenigma kianenigma Sep 16, 2022

Choose a reason for hiding this comment

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

why are these all unstable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Although they will be part of the final RPC, these methods are expected to go through a testing phase before standardizing and replacing the old API. During this time (1-2months TBD), we can still add breaking changes. At least, that's how I interpret the unstable from the spec

Copy link
Contributor

Choose a reason for hiding this comment

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

That is my understanding of Pierre's suggestion with this spec; we get them in marked as unstable and then have the opporunity to stabilise them when we're happy.

#[method(name = "chainSpec_unstable_chainName")]
fn chain_spec_unstable_chain_name(&self) -> RpcResult<String>;

/// Get the chain's genesis hash.
///
/// # Unstable
///
/// This method is unstable and subject to change in the future.
#[method(name = "chainSpec_unstable_genesisHash")]
fn chain_spec_unstable_genesis_hash(&self) -> RpcResult<String>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Tiny thing; I think of chainspec as one word personally; chainspec_unstable_genesis_hash for instance.

Not bothered either way though :)


/// Get the properties of the chain, as present in the chain specification.
///
/// # Note
///
/// The json whitespaces are not guaranteed to persist.
///
/// # Unstable
///
/// This method is unstable and subject to change in the future.
#[method(name = "chainSpec_unstable_properties")]
fn chain_spec_unstable_properties(&self) -> RpcResult<Properties>;
}
60 changes: 60 additions & 0 deletions client/rpc-spec-v2/src/chain_spec/chain_spec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// This file is part of Substrate.

// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! API implementation for the specification of a chain.

use crate::chain_spec::api::ChainSpecApiServer;
use jsonrpsee::core::RpcResult;
use sc_chain_spec::Properties;

/// An API for chain spec RPC calls.
pub struct ChainSpec {
/// The name of the chain.
name: String,
/// The hexadecimal encoded hash of the genesis block.
genesis_hash: String,
/// Chain properties.
properties: Properties,
}

impl ChainSpec {
/// Creates a new [`ChainSpec`].
pub fn new<Hash: AsRef<[u8]>>(
name: String,
genesis_hash: Hash,
properties: Properties,
) -> Self {
let genesis_hash = format!("0x{}", hex::encode(genesis_hash));

Self { name, properties, genesis_hash }
}
}

impl ChainSpecApiServer for ChainSpec {
fn chain_spec_unstable_chain_name(&self) -> RpcResult<String> {
Ok(self.name.clone())
}

fn chain_spec_unstable_genesis_hash(&self) -> RpcResult<String> {
Ok(self.genesis_hash.clone())
}

fn chain_spec_unstable_properties(&self) -> RpcResult<Properties> {
Ok(self.properties.clone())
}
}
38 changes: 38 additions & 0 deletions client/rpc-spec-v2/src/chain_spec/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// This file is part of Substrate.

// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! Substrate chain specification API.
//!
//! The *chain spec* (short for *chain specification*) allows inspecting the content of
//! the specification of the chain that a JSON-RPC server is targeting.
//!
//! The values returned by the API are guaranteed to never change during the lifetime of the
//! JSON-RPC server.
//!
//! # Note
//!
//! Methods are prefixed by `chainSpec`.

#[cfg(test)]
mod tests;

pub mod api;
pub mod chain_spec;

pub use api::ChainSpecApiServer;
pub use chain_spec::ChainSpec;
61 changes: 61 additions & 0 deletions client/rpc-spec-v2/src/chain_spec/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// This file is part of Substrate.

// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use super::*;
use jsonrpsee::{types::EmptyParams, RpcModule};
use sc_chain_spec::Properties;

const CHAIN_NAME: &'static str = "TEST_CHAIN_NAME";
const CHAIN_GENESIS: [u8; 32] = [0; 32];
const CHAIN_PROPERTIES: &'static str = r#"{"three": "123", "one": 1, "two": 12}"#;

fn api() -> RpcModule<ChainSpec> {
ChainSpec::new(
CHAIN_NAME.to_string(),
CHAIN_GENESIS,
serde_json::from_str(CHAIN_PROPERTIES).unwrap(),
)
.into_rpc()
}

#[tokio::test]
async fn chain_spec_chain_name_works() {
let name = api()
.call::<_, String>("chainSpec_unstable_chainName", EmptyParams::new())
.await
.unwrap();
assert_eq!(name, CHAIN_NAME);
}

#[tokio::test]
async fn chain_spec_genesis_hash_works() {
let genesis = api()
.call::<_, String>("chainSpec_unstable_genesisHash", EmptyParams::new())
.await
.unwrap();
assert_eq!(genesis, format!("0x{}", hex::encode(CHAIN_GENESIS)));
}

#[tokio::test]
async fn chain_spec_properties_works() {
let properties = api()
.call::<_, Properties>("chainSpec_unstable_properties", EmptyParams::new())
.await
.unwrap();
assert_eq!(properties, serde_json::from_str(CHAIN_PROPERTIES).unwrap());
}
26 changes: 26 additions & 0 deletions client/rpc-spec-v2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is part of Substrate.

// Copyright (C) 2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

//! Substrate JSON-RPC interface v2.
//!
//! Specification [document](https://paritytech.github.io/json-rpc-interface-spec/).

#![warn(missing_docs)]
#![deny(unused_crate_dependencies)]

pub mod chain_spec;