diff --git a/Cargo.lock b/Cargo.lock index 5fdd31a0a..da569b66a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1134,7 +1134,7 @@ dependencies = [ [[package]] name = "dock-node" -version = "0.3.0" +version = "0.4.0" dependencies = [ "dock-runtime", "frame-benchmarking", @@ -1142,9 +1142,11 @@ dependencies = [ "futures 0.3.5", "hex-literal 0.3.1", "jsonrpc-core", + "jsonrpc-derive", "log", "pallet-transaction-payment-rpc", "parking_lot 0.10.2", + "poa_rpc", "sc-basic-authorship", "sc-cli", "sc-client-api", @@ -1176,7 +1178,7 @@ dependencies = [ [[package]] name = "dock-runtime" -version = "0.3.0" +version = "0.4.0" dependencies = [ "frame-benchmarking", "frame-executive", @@ -4195,7 +4197,7 @@ checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" [[package]] name = "poa" -version = "0.2.0" +version = "0.3.0" dependencies = [ "frame-support", "frame-system", @@ -4204,6 +4206,7 @@ dependencies = [ "pallet-session", "parity-scale-codec", "serde", + "sp-api", "sp-arithmetic", "sp-core", "sp-io", @@ -4211,6 +4214,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "poa_rpc" +version = "0.0.1" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "parity-scale-codec", + "poa", + "serde", + "sp-api", + "sp-blockchain", + "sp-rpc", + "sp-runtime", +] + [[package]] name = "polling" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 5a4595f70..4144a7147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ 'node', 'pallets/poa', + 'pallets/poa/rpc', 'pallets/token_migration', 'runtime', ] diff --git a/node/Cargo.toml b/node/Cargo.toml index 1d0927bfc..0482ddcc5 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -3,7 +3,7 @@ authors = ['Dock.io'] build = 'build.rs' edition = '2018' name = 'dock-node' -version = '0.3.0' +version = '0.4.0' [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -14,6 +14,7 @@ log = '0.4.8' parking_lot = '0.10.0' hex-literal = "0.3.0" jsonrpc-core = '14.0.3' +jsonrpc-derive = '14.0.3' serde = { version = '1.0.101', features = ['derive'] } serde_json = '1.0.41' @@ -23,7 +24,7 @@ optional = true [dependencies.dock-runtime] path = '../runtime' -version = '0.3.0' +version = '0.4.0' [dependencies.sc-basic-authorship] git = 'https://github.com/paritytech/substrate.git' @@ -165,6 +166,10 @@ git = 'https://github.com/paritytech/substrate.git' tag = 'v2.0.0-rc6' version = '2.0.0-rc6' +[dependencies.poa_rpc] +path = '../pallets/poa/rpc' +version = '0.0.1' + [[bin]] name = 'dock-node' path = 'src/main.rs' diff --git a/node/src/rpc.rs b/node/src/rpc.rs index ac3c0b058..032921413 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -32,10 +32,12 @@ where C: Send + Sync + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, + C::Api: poa_rpc::PoARuntimeApi, C::Api: BlockBuilder, P: TransactionPool + 'static, { use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; + use poa_rpc::{PoA, PoAApi}; use substrate_frame_rpc_system::{FullSystem, SystemApi}; let mut io = jsonrpc_core::IoHandler::default(); @@ -55,10 +57,8 @@ where client.clone(), ))); - // Extend this RPC with a custom API by using the following syntax. - // `YourRpcStruct` should have a reference to a client, which is needed - // to call into the runtime. - // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` + // RPC calls for PoA pallet + io.extend_with(PoAApi::to_delegate(PoA::new(client.clone()))); io } diff --git a/pallets/poa/Cargo.toml b/pallets/poa/Cargo.toml index b5a86359e..c66cdeb16 100644 --- a/pallets/poa/Cargo.toml +++ b/pallets/poa/Cargo.toml @@ -1,9 +1,10 @@ [package] name = "poa" -version = "0.2.0" +version = "0.3.0" authors = ["Dock.io"] edition = "2018" license = 'Apache-2.0' + [package.metadata.docs.rs] targets = ['x86_64-unknown-linux-gnu'] @@ -66,12 +67,18 @@ default-features = false tag = 'v2.0.0-rc6' version = '2.0.0-rc6' -[dev-dependencies.sp-runtime] +[dependencies.sp-runtime] default-features = false git = 'https://github.com/paritytech/substrate.git' tag = 'v2.0.0-rc6' version = '2.0.0-rc6' +[dependencies.sp-api] +git = 'https://github.com/paritytech/substrate.git' +default-features = false +tag = 'v2.0.0-rc6' +version = '2.0.0-rc6' + [dev-dependencies.balances] git = 'https://github.com/paritytech/substrate.git' default-features = false @@ -86,6 +93,8 @@ std = [ 'frame-support/std', 'frame-system/std', 'sp-std/std', + 'sp-runtime/std', + 'sp-api/std', 'serde', 'pallet-session/std', 'pallet-authorship/std', diff --git a/pallets/poa/rpc/Cargo.toml b/pallets/poa/rpc/Cargo.toml new file mode 100644 index 000000000..2de83ef07 --- /dev/null +++ b/pallets/poa/rpc/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "poa_rpc" +version = "0.0.1" +authors = ["Dock.io"] +edition = "2018" +license = 'Apache-2.0' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +[dependencies] +codec = { package = "parity-scale-codec", version = "1.3.1" } +jsonrpc-core = "14.0.3" +jsonrpc-core-client = "14.0.3" +jsonrpc-derive = "14.0.3" +serde = { version = "1.0.101", features = ["derive"], optional = true } +sp-rpc = { git = 'https://github.com/paritytech/substrate.git', tag = 'v2.0.0-rc6', version = '2.0.0-rc6' } +sp-runtime = { git = 'https://github.com/paritytech/substrate.git', tag = 'v2.0.0-rc6', version = '2.0.0-rc6' } +sp-api = { git = 'https://github.com/paritytech/substrate.git', tag = 'v2.0.0-rc6', version = '2.0.0-rc6' } +sp-blockchain = { git = 'https://github.com/paritytech/substrate.git', tag = 'v2.0.0-rc6', version = '2.0.0-rc6' } +poa = { version = '0.3.0', path = '..' } \ No newline at end of file diff --git a/pallets/poa/rpc/src/lib.rs b/pallets/poa/rpc/src/lib.rs new file mode 100644 index 000000000..af1b025ac --- /dev/null +++ b/pallets/poa/rpc/src/lib.rs @@ -0,0 +1,76 @@ +pub use self::gen_client::Client as PoAClient; +use codec::Codec; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +pub use poa::runtime_api::PoAApi as PoARuntimeApi; +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, MaybeDisplay, MaybeFromStr}, +}; +use std::sync::Arc; + +#[rpc] +pub trait PoAApi { + /// Return account address of treasury. The account address can then be used to query the + /// chain for balance + #[rpc(name = "poa_treasuryAccount")] + fn treasury_account(&self, at: Option) -> Result; + + /// Return free balance of treasury account. In the context of PoA, only free balance makes + /// sense for treasury. But just in case, to check all kinds of balance (locked, reserved, etc), + /// get the account address with above call and query the chain. + #[rpc(name = "poa_treasuryBalance")] + fn treasury_balance(&self, at: Option) -> Result; +} + +/// A struct that implements the [`PoAApi`]. +pub struct PoA { + client: Arc, + _marker: std::marker::PhantomData

, +} + +impl PoA { + /// Create new `PoA` with the given reference to the client. + pub fn new(client: Arc) -> Self { + PoA { + client, + _marker: Default::default(), + } + } +} + +impl PoAApi<::Hash, AccountId, Balance> + for PoA +where + Block: BlockT, + C: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, + C::Api: PoARuntimeApi, + AccountId: Codec + MaybeDisplay + MaybeFromStr, + Balance: Codec + MaybeDisplay + MaybeFromStr, +{ + fn treasury_account(&self, at: Option<::Hash>) -> Result { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + api.get_treasury_account(&at).map_err(|e| RpcError { + code: ErrorCode::ServerError(1), + message: "Unable to query treasury account address.".into(), + data: Some(format!("{:?}", e).into()), + }) + } + + fn treasury_balance(&self, at: Option<::Hash>) -> Result { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash)); + api.get_treasury_balance(&at).map_err(|e| RpcError { + code: ErrorCode::ServerError(2), + message: "Unable to query treasury account balance.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/pallets/poa/src/lib.rs b/pallets/poa/src/lib.rs index ab62e089e..ea5d2c904 100644 --- a/pallets/poa/src/lib.rs +++ b/pallets/poa/src/lib.rs @@ -25,6 +25,8 @@ extern crate alloc; use alloc::collections::{BTreeMap, BTreeSet}; +pub mod runtime_api; + // TODO: Remove all print statements and panics before releasing for mainnet type EpochNo = u32; @@ -610,7 +612,7 @@ impl Module { TREASURY_ID.into_account() } - /// Treasury's balance + /// Treasury's free balance. Only free balance makes sense for treasury in context of PoA pub fn treasury_balance() -> BalanceOf { T::Currency::free_balance(&Self::treasury_account()) } diff --git a/pallets/poa/src/runtime_api.rs b/pallets/poa/src/runtime_api.rs new file mode 100644 index 000000000..2167ad2c9 --- /dev/null +++ b/pallets/poa/src/runtime_api.rs @@ -0,0 +1,20 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Codec; +use sp_runtime::traits::{MaybeDisplay, MaybeFromStr}; + +sp_api::decl_runtime_apis! { + pub trait PoAApi where + AccountId: Codec + MaybeDisplay + MaybeFromStr, + Balance: Codec + MaybeDisplay + MaybeFromStr, { + + /// Return account address of treasury. The account address can then be used to query the + /// chain for balance + fn get_treasury_account() -> AccountId; + + /// Return free balance of treasury account. In the context of PoA, only free balance makes + /// sense for treasury. But just in case, to check all kinds of balance (locked, reserved, etc), + /// get the account address with above call and query the chain. + fn get_treasury_balance() -> Balance; + } +} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5cb7915ad..a74ff8863 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -2,7 +2,7 @@ authors = ['Dock.io'] edition = '2018' name = 'dock-runtime' -version = '0.3.0' +version = '0.4.0' license = 'Apache-2.0' [package.metadata.docs.rs] @@ -219,7 +219,7 @@ optional = true [dependencies.poa] default-features = false path = '../pallets/poa' -version = '0.2.0' +version = '0.3.0' [dependencies.token_migration] default-features = false diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index a4c837af9..2e5e5916c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -130,7 +130,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("dock-testnet"), impl_name: create_runtime_str!("dock-runtime"), authoring_version: 1, - spec_version: 7, + spec_version: 8, impl_version: 1, transaction_version: 1, apis: RUNTIME_API_VERSIONS, @@ -530,6 +530,16 @@ impl_runtime_apis! { } } + impl poa::runtime_api::PoAApi for Runtime { + fn get_treasury_account() -> AccountId { + PoAModule::treasury_account() + } + + fn get_treasury_balance() -> Balance { + PoAModule::treasury_balance() + } + } + #[cfg(feature = "runtime-benchmarks")] impl frame_benchmarking::Benchmark for Runtime { fn dispatch_benchmark(