diff --git a/Cargo.lock b/Cargo.lock index f83f550fdc2c6..b42da79f88842 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2417,12 +2417,8 @@ dependencies = [ name = "node-primitives" version = "2.0.0" dependencies = [ - "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-client 2.0.0", "substrate-primitives 2.0.0", "substrate-serializer 2.0.0", ] @@ -2431,23 +2427,12 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ - "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-pubsub 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", - "node-runtime 2.0.0", - "node-testing 2.0.0", - "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", + "srml-contracts-rpc 2.0.0", + "srml-system-rpc 2.0.0", "substrate-client 2.0.0", - "substrate-keyring 2.0.0", - "substrate-primitives 2.0.0", - "substrate-rpc-primitives 2.0.0", "substrate-transaction-pool 2.0.0", ] @@ -2484,6 +2469,7 @@ dependencies = [ "srml-balances 2.0.0", "srml-collective 2.0.0", "srml-contracts 2.0.0", + "srml-contracts-rpc-runtime-api 2.0.0", "srml-democracy 2.0.0", "srml-elections 2.0.0", "srml-executive 2.0.0", @@ -2500,6 +2486,7 @@ dependencies = [ "srml-sudo 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", @@ -4047,6 +4034,31 @@ dependencies = [ "wasmi-validation 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "srml-contracts-rpc" +version = "2.0.0" +dependencies = [ + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-contracts-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-rpc-primitives 2.0.0", +] + +[[package]] +name = "srml-contracts-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "srml-democracy" version = "2.0.0" @@ -4434,6 +4446,34 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-system-rpc" +version = "2.0.0" +dependencies = [ + "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-test-runtime-client 2.0.0", + "substrate-transaction-pool 2.0.0", +] + +[[package]] +name = "srml-system-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-client 2.0.0", +] + [[package]] name = "srml-timestamp" version = "2.0.0" @@ -5535,6 +5575,7 @@ dependencies = [ "srml-executive 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "substrate-application-crypto 2.0.0", "substrate-client 2.0.0", diff --git a/Cargo.toml b/Cargo.toml index 7e34a0bd6ccd0..6508e2b41e994 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ members = [ "srml/staking/reward-curve", "srml/sudo", "srml/system", + "srml/system/rpc", "srml/timestamp", "srml/treasury", "srml/utility", diff --git a/core/rpc/src/state/tests.rs b/core/rpc/src/state/tests.rs index ba1aac4cc3eb4..3790b3ea11657 100644 --- a/core/rpc/src/state/tests.rs +++ b/core/rpc/src/state/tests.rs @@ -282,7 +282,7 @@ fn should_return_runtime_version() { \"specVersion\":1,\"implVersion\":1,\"apis\":[[\"0xdf6acb689907609b\",2],\ [\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",1],[\"0x40fe3ad401f8959a\",3],\ [\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",1],\ - [\"0xf78b278be53f454c\",1],[\"0xab3c0572291feb8b\",1]]}"; + [\"0xf78b278be53f454c\",1],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]]}"; let runtime_version = api.runtime_version(None.into()).wait().unwrap(); let serialized = serde_json::to_string(&runtime_version).unwrap(); diff --git a/core/test-runtime/Cargo.toml b/core/test-runtime/Cargo.toml index 313db0fd070f1..fec9128ef5d22 100644 --- a/core/test-runtime/Cargo.toml +++ b/core/test-runtime/Cargo.toml @@ -31,6 +31,7 @@ cfg-if = "0.1.10" srml-babe = { path = "../../srml/babe", default-features = false } srml-timestamp = { path = "../../srml/timestamp", default-features = false } srml-system = { path = "../../srml/system", default-features = false } +srml-system-rpc-runtime-api = { path = "../../srml/system/rpc/runtime-api", default-features = false } [dev-dependencies] substrate-executor = { path = "../executor" } @@ -68,6 +69,7 @@ std = [ "srml-babe/std", "srml-timestamp/std", "srml-system/std", + "srml-system-rpc-runtime-api/std", "app-crypto/std", "session/std", ] diff --git a/core/test-runtime/src/lib.rs b/core/test-runtime/src/lib.rs index e75cb69149d8d..fddee22be22f6 100644 --- a/core/test-runtime/src/lib.rs +++ b/core/test-runtime/src/lib.rs @@ -648,6 +648,12 @@ cfg_if! { SessionKeys::generate(None) } } + + impl srml_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_account: AccountId) -> Index { + 0 + } + } } } else { impl_runtime_apis! { @@ -858,6 +864,12 @@ cfg_if! { SessionKeys::generate(None) } } + + impl srml_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(_account: AccountId) -> Index { + 0 + } + } } } } diff --git a/core/test-runtime/src/system.rs b/core/test-runtime/src/system.rs index f3359aa1baf25..d06bef5923d99 100644 --- a/core/test-runtime/src/system.rs +++ b/core/test-runtime/src/system.rs @@ -18,7 +18,7 @@ //! and depositing logs. use rstd::prelude::*; -use runtime_io::{storage_root, storage_changes_root, twox_128, blake2_256}; +use runtime_io::{storage_root, storage_changes_root, blake2_256}; use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_support::storage_items; use sr_primitives::{ @@ -170,22 +170,14 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity { return InvalidTransaction::Future.into(); } - let hash = |from: &AccountId, nonce: u64| { - twox_128(&nonce.to_keyed_vec(&from.encode())).to_vec() - }; + let encode = |from: &AccountId, nonce: u64| (from, nonce).encode(); let requires = if tx.nonce != expected_nonce && tx.nonce > 0 { - let mut deps = Vec::new(); - deps.push(hash(&tx.from, tx.nonce - 1)); - deps + vec![encode(&tx.from, tx.nonce - 1)] } else { - Vec::new() + vec![] }; - let provides = { - let mut p = Vec::new(); - p.push(hash(&tx.from, tx.nonce)); - p - }; + let provides = vec![encode(&tx.from, tx.nonce)]; Ok(ValidTransaction { priority: tx.amount, @@ -324,6 +316,7 @@ mod tests { use crate::{Header, Transfer, WASM_BINARY}; use primitives::{NeverNativeValue, map, traits::CodeExecutor}; use substrate_executor::{NativeExecutor, WasmExecutionMethod, native_executor_instance}; + use runtime_io::twox_128; // Declare an instance of the native executor dispatch for the test runtime. native_executor_instance!( diff --git a/node/primitives/Cargo.toml b/node/primitives/Cargo.toml index 266720b0246a0..25725449a3a5a 100644 --- a/node/primitives/Cargo.toml +++ b/node/primitives/Cargo.toml @@ -5,11 +5,7 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -client = { package = "substrate-client", path = "../../core/client", default-features = false } -codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } primitives = { package = "substrate-primitives", path = "../../core/primitives", default-features = false } -rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } -serde = { version = "1.0.101", optional = true, features = ["derive"] } sr-primitives = { path = "../../core/sr-primitives", default-features = false } [dev-dependencies] @@ -19,10 +15,6 @@ pretty_assertions = "0.6.1" [features] default = ["std"] std = [ - "client/std", - "codec/std", "primitives/std", - "rstd/std", - "serde", "sr-primitives/std", ] diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 907b78a017eea..b8abdd7421f13 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -20,15 +20,10 @@ #![cfg_attr(not(feature = "std"), no_std)] -use rstd::prelude::*; use sr_primitives::{ generic, traits::{Verify, BlakeTwo256}, OpaqueExtrinsic, AnySignature }; -#[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; -use codec::{Encode, Decode}; - /// An index to a block. pub type BlockNumber = u32; @@ -72,43 +67,3 @@ pub type BlockId = generic::BlockId; /// Opaque, encoded, unchecked extrinsic. pub type UncheckedExtrinsic = OpaqueExtrinsic; -/// A result of execution of a contract. -#[derive(Eq, PartialEq, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -pub enum ContractExecResult { - /// The contract returned successfully. - /// - /// There is a status code and, optionally, some data returned by the contract. - Success { - /// Status code returned by the contract. - status: u8, - /// Output data returned by the contract. - /// - /// Can be empty. - data: Vec, - }, - /// The contract execution either trapped or returned an error. - Error, -} - -client::decl_runtime_apis! { - /// The API to query account account nonce (aka index). - pub trait AccountNonceApi { - /// Get current account nonce of given `AccountId`. - fn account_nonce(account: AccountId) -> Index; - } - - /// The API to interact with contracts without using executive. - pub trait ContractsApi { - /// Perform a call from a specified account to a given contract. - /// - /// See the contracts' `call` dispatchable function for more details. - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: u64, - input_data: Vec, - ) -> ContractExecResult; - } -} diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 6985d94e54f32..5d2ca81e0ff84 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -7,21 +7,8 @@ edition = "2018" [dependencies] client = { package = "substrate-client", path = "../../core/client" } jsonrpc-core = "13.2.0" -jsonrpc-core-client = "13.2.0" -jsonrpc-derive = "13.2.0" -jsonrpc-pubsub = "13.2.0" -keyring = { package = "substrate-keyring", path = "../../core/keyring" } -log = "0.4.8" node-primitives = { path = "../primitives" } -codec = { package = "parity-scale-codec", version = "1.0.0" } -serde = { version = "1.0.101", features = ["derive"] } sr-primitives = { path = "../../core/sr-primitives" } -substrate-primitives = { path = "../../core/primitives" } -rpc-primitives = { package = "substrate-rpc-primitives", path = "../../core/rpc/primitives" } +srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } +srml-system-rpc = { path = "../../srml/system/rpc/" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } - -[dev-dependencies] -node-testing = { path = "../testing" } -node-runtime = { path = "../runtime" } -env_logger = "0.7.0" -futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19" } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 43f723f7964bc..398d458e63a20 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -25,43 +25,32 @@ //! The RPCs available in this crate however can make some assumptions //! about how the runtime is constructed and what `SRML` modules //! are part of it. Therefore all node-runtime-specific RPCs can -//! be placed here. +//! be placed here or imported from corresponding `SRML` RPC definitions. #![warn(missing_docs)] use std::sync::Arc; -use node_primitives::{Block, AccountNonceApi, ContractsApi}; +use node_primitives::{Block, AccountId, Index, Balance}; use sr_primitives::traits::ProvideRuntimeApi; use transaction_pool::txpool::{ChainApi, Pool}; -pub mod accounts; -pub mod contracts; - -mod constants { - /// A status code indicating an error happened while trying to call into the runtime. - /// - /// This typically means that the runtime trapped. - pub const RUNTIME_ERROR: i64 = 1; -} - /// Instantiate all RPC extensions. pub fn create(client: Arc, pool: Arc>) -> jsonrpc_core::IoHandler where C: ProvideRuntimeApi, C: client::blockchain::HeaderBackend, C: Send + Sync + 'static, - C::Api: AccountNonceApi + ContractsApi, + C::Api: srml_system_rpc::AccountNonceApi, + C::Api: srml_contracts_rpc::ContractsRuntimeApi, P: ChainApi + Sync + Send + 'static, M: jsonrpc_core::Metadata + Default, { - use self::{ - accounts::{Accounts, AccountsApi}, - contracts::{Contracts, ContractsApi}, - }; + use srml_system_rpc::{System, SystemApi}; + use srml_contracts_rpc::{Contracts, ContractsApi}; let mut io = jsonrpc_core::IoHandler::default(); io.extend_with( - AccountsApi::to_delegate(Accounts::new(client.clone(), pool)) + SystemApi::to_delegate(System::new(client.clone(), pool)) ); io.extend_with( ContractsApi::to_delegate(Contracts::new(client)) diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index a47d65210096f..f9818c096e8e5 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -31,6 +31,7 @@ babe = { package = "srml-babe", path = "../../srml/babe", default-features = fal balances = { package = "srml-balances", path = "../../srml/balances", default-features = false } collective = { package = "srml-collective", path = "../../srml/collective", default-features = false } contracts = { package = "srml-contracts", path = "../../srml/contracts", default-features = false } +contracts-rpc-runtime-api = { package = "srml-contracts-rpc-runtime-api", path = "../../srml/contracts/rpc/runtime-api/", default-features = false } democracy = { package = "srml-democracy", path = "../../srml/democracy", default-features = false } elections = { package = "srml-elections", path = "../../srml/elections", default-features = false } executive = { package = "srml-executive", path = "../../srml/executive", default-features = false } @@ -47,6 +48,7 @@ srml-staking-reward-curve = { path = "../../srml/staking/reward-curve"} sudo = { package = "srml-sudo", path = "../../srml/sudo", default-features = false } support = { package = "srml-support", path = "../../srml/support", default-features = false } system = { package = "srml-system", path = "../../srml/system", default-features = false } +system-rpc-runtime-api = { package = "srml-system-rpc-runtime-api", path = "../../srml/system/rpc/runtime-api/", default-features = false } timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default-features = false } treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } @@ -67,6 +69,7 @@ std = [ "codec/std", "collective/std", "contracts/std", + "contracts-rpc-runtime-api/std", "democracy/std", "elections/std", "executive/std", @@ -93,6 +96,7 @@ std = [ "sudo/std", "support/std", "system/std", + "system-rpc-runtime-api/std", "timestamp/std", "treasury/std", "utility/std", diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index d8fc9a1a5784a..fd31969efa02f 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -27,7 +27,7 @@ use support::{ use primitives::u32_trait::{_1, _2, _3, _4}; use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, - Moment, Signature, ContractExecResult, + Moment, Signature, }; use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; use grandpa::fg_primitives; @@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 175, + spec_version: 176, impl_version: 176, apis: RUNTIME_API_VERSIONS, }; @@ -660,20 +660,22 @@ impl_runtime_apis! { } } - impl node_primitives::AccountNonceApi for Runtime { + impl system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Index { System::account_nonce(account) } } - impl node_primitives::ContractsApi for Runtime { + impl contracts_rpc_runtime_api::ContractsApi for Runtime { fn call( origin: AccountId, dest: AccountId, value: Balance, gas_limit: u64, input_data: Vec, - ) -> ContractExecResult { + ) -> contracts_rpc_runtime_api::ContractExecResult { + use contracts_rpc_runtime_api::ContractExecResult; + let exec_result = Contracts::bare_call( origin, dest.into(), diff --git a/srml/contracts/rpc/Cargo.toml b/srml/contracts/rpc/Cargo.toml new file mode 100644 index 0000000000000..8ebb714e20539 --- /dev/null +++ b/srml/contracts/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "srml-contracts-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-contracts-rpc-runtime-api = { path = "./runtime-api" } + diff --git a/srml/contracts/rpc/runtime-api/Cargo.toml b/srml/contracts/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..fce82aed2a69a --- /dev/null +++ b/srml/contracts/rpc/runtime-api/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "srml-contracts-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } +serde = { version = "1.0.101", optional = true, features = ["derive"] } + +[features] +default = ["std"] +std = [ + "client/std", + "codec/std", + "rstd/std", + "serde", +] diff --git a/srml/contracts/rpc/runtime-api/src/lib.rs b/srml/contracts/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..a5b56888ce509 --- /dev/null +++ b/srml/contracts/rpc/runtime-api/src/lib.rs @@ -0,0 +1,64 @@ +// 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 . + +//! Runtime API definition required by Contracts RPC extensions. +//! +//! This API should be imported and implemented by the runtime, +//! of a node that wants to use the custom RPC extension +//! adding Contracts access methods. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::vec::Vec; +use codec::{Encode, Decode, Codec}; + +/// A result of execution of a contract. +#[derive(Eq, PartialEq, Encode, Decode)] +#[cfg_attr(feature = "std", derive(Debug, serde::Serialize, serde::Deserialize))] +pub enum ContractExecResult { + /// The contract returned successfully. + /// + /// There is a status code and, optionally, some data returned by the contract. + Success { + /// Status code returned by the contract. + status: u8, + /// Output data returned by the contract. + /// + /// Can be empty. + data: Vec, + }, + /// The contract execution either trapped or returned an error. + Error, +} + +client::decl_runtime_apis! { + /// The API to interact with contracts without using executive. + pub trait ContractsApi where + AccountId: Codec, + Balance: Codec, + { + /// Perform a call from a specified account to a given contract. + /// + /// See the contracts' `call` dispatchable function for more details. + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: u64, + input_data: Vec, + ) -> ContractExecResult; + } +} diff --git a/node/rpc/src/contracts.rs b/srml/contracts/rpc/src/lib.rs similarity index 74% rename from node/rpc/src/contracts.rs rename to srml/contracts/rpc/src/lib.rs index 3da2478dab8bf..7e17aaaf177cc 100644 --- a/node/rpc/src/contracts.rs +++ b/srml/contracts/rpc/src/lib.rs @@ -20,22 +20,23 @@ use std::sync::Arc; use serde::{Serialize, Deserialize}; use client::blockchain::HeaderBackend; +use codec::Codec; use jsonrpc_core::{Error, ErrorCode, Result}; use jsonrpc_derive::rpc; -use node_primitives::{ - AccountId, Balance, Block, BlockId, ContractExecResult, ContractsApi as ContractsRuntimeApi, -}; -use sr_primitives::traits::{ - self, - Block as BlockT, +use sr_primitives::{ + generic::BlockId, + traits::{Block as BlockT, ProvideRuntimeApi}, }; use rpc_primitives::number; +pub use srml_contracts_rpc_runtime_api::{ContractExecResult, ContractsApi as ContractsRuntimeApi}; +pub use self::gen_client::Client as ContractsClient; + /// A struct that encodes RPC parameters required for a call to a smart-contract. #[derive(Serialize, Deserialize)] #[serde(rename_all="camelCase")] #[serde(deny_unknown_fields)] -pub struct CallRequest { +pub struct CallRequest { origin: AccountId, dest: AccountId, value: Balance, @@ -45,7 +46,7 @@ pub struct CallRequest { /// Contracts RPC methods. #[rpc] -pub trait ContractsApi { +pub trait ContractsApi { /// Executes a call to a contract. /// /// This call is performed locally without submitting any transactions. Thus executing this @@ -55,33 +56,39 @@ pub trait ContractsApi { #[rpc(name = "contracts_call")] fn call( &self, - call_request: CallRequest, + call_request: CallRequest, at: Option, ) -> Result; } /// An implementation of contract specific RPC methods. -pub struct Contracts { +pub struct Contracts { client: Arc, + _marker: std::marker::PhantomData, } -impl Contracts { +impl Contracts { /// Create new `Contracts` with the given reference to the client. pub fn new(client: Arc) -> Self { - Contracts { client } + Contracts { client, _marker: Default::default() } } } -impl ContractsApi<::Hash> for Contracts +const RUNTIME_ERROR: i64 = 1; + +impl ContractsApi<::Hash, AccountId, Balance> for Contracts where + Block: BlockT, C: Send + Sync + 'static, - C: traits::ProvideRuntimeApi, + C: ProvideRuntimeApi, C: HeaderBackend, - C::Api: ContractsRuntimeApi, + C::Api: ContractsRuntimeApi, + AccountId: Codec, + Balance: Codec, { fn call( &self, - call_request: CallRequest, + call_request: CallRequest, at: Option<::Hash>, ) -> Result { let api = self.client.runtime_api(); @@ -106,7 +113,7 @@ where let exec_result = api .call(&at, origin, dest, value, gas_limit, input_data) .map_err(|e| Error { - code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR), + code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Runtime trapped while executing a contract.".into(), data: Some(format!("{:?}", e).into()), })?; diff --git a/srml/system/rpc/Cargo.toml b/srml/system/rpc/Cargo.toml new file mode 100644 index 0000000000000..04856a817f681 --- /dev/null +++ b/srml/system/rpc/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "srml-system-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +log = "0.4.8" +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-system-rpc-runtime-api = { path = "./runtime-api" } +substrate-primitives = { path = "../../../core/primitives" } +transaction_pool = { package = "substrate-transaction-pool", path = "../../../core/transaction-pool" } + +[dev-dependencies] +test-client = { package = "substrate-test-runtime-client", path = "../../../core/test-runtime/client" } +env_logger = "0.7.0" +futures03 = { package = "futures-preview", version = "=0.3.0-alpha.19" } diff --git a/srml/system/rpc/runtime-api/Cargo.toml b/srml/system/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..fc525d8fce2ad --- /dev/null +++ b/srml/system/rpc/runtime-api/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "srml-system-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false } + +[features] +default = ["std"] +std = [ + "client/std", + "codec/std", +] diff --git a/srml/system/rpc/runtime-api/src/lib.rs b/srml/system/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..45af0241e0836 --- /dev/null +++ b/srml/system/rpc/runtime-api/src/lib.rs @@ -0,0 +1,34 @@ +// 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 . + +//! Runtime API definition required by System RPC extensions. +//! +//! This API should be imported and implemented by the runtime, +//! of a node that wants to use the custom RPC extension +//! adding System access methods. + +#![cfg_attr(not(feature = "std"), no_std)] + +client::decl_runtime_apis! { + /// The API to query account nonce (aka transaction index). + pub trait AccountNonceApi where + AccountId: codec::Codec, + Index: codec::Codec, + { + /// Get current account nonce of given `AccountId`. + fn account_nonce(account: AccountId) -> Index; + } +} diff --git a/node/rpc/src/accounts.rs b/srml/system/rpc/src/lib.rs similarity index 64% rename from node/rpc/src/accounts.rs rename to srml/system/rpc/src/lib.rs index 6c8e60736ac53..c6c0a658fba53 100644 --- a/node/rpc/src/accounts.rs +++ b/srml/system/rpc/src/lib.rs @@ -14,58 +14,66 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Node-specific RPC methods for Accounts. +//! System SRML specific RPC methods. use std::sync::Arc; +use codec::{self, Codec, Encode}; use client::blockchain::HeaderBackend; use jsonrpc_core::{Result, Error, ErrorCode}; use jsonrpc_derive::rpc; -use node_primitives::{ - AccountId, Index, AccountNonceApi, Block, BlockId, +use sr_primitives::{ + generic::BlockId, + traits, }; -use codec::Encode; -use sr_primitives::traits; use substrate_primitives::hexdisplay::HexDisplay; use transaction_pool::txpool::{self, Pool}; -pub use self::gen_client::Client as AccountsClient; +pub use srml_system_rpc_runtime_api::AccountNonceApi; +pub use self::gen_client::Client as SystemClient; -/// Accounts RPC methods. +/// System RPC methods. #[rpc] -pub trait AccountsApi { +pub trait SystemApi { /// Returns the next valid index (aka nonce) for given account. /// /// This method takes into consideration all pending transactions /// currently in the pool and if no transactions are found in the pool /// it fallbacks to query the index from the runtime (aka. state nonce). - #[rpc(name = "account_nextIndex")] + #[rpc(name = "system_accountNextIndex", alias("account_nextIndex"))] fn nonce(&self, account: AccountId) -> Result; } -/// An implementation of Accounts specific RPC methods. -pub struct Accounts { +const RUNTIME_ERROR: i64 = 1; + +/// An implementation of System-specific RPC methods. +pub struct System { client: Arc, pool: Arc>, + _marker: std::marker::PhantomData, } -impl Accounts { - /// Create new `Accounts` given client and transaction pool. +impl System { + /// Create new `System` given client and transaction pool. pub fn new(client: Arc, pool: Arc>) -> Self { - Accounts { + System { client, - pool + pool, + _marker: Default::default(), } } } -impl AccountsApi for Accounts +impl SystemApi for System where C: traits::ProvideRuntimeApi, C: HeaderBackend, C: Send + Sync + 'static, - C::Api: AccountNonceApi, + C::Api: AccountNonceApi, P: txpool::ChainApi + Sync + Send + 'static, + Block: traits::Block, + AccountId: Clone + std::fmt::Display + Codec, + Index: Clone + std::fmt::Display + Codec + traits::SimpleArithmetic, { fn nonce(&self, account: AccountId) -> Result { let api = self.client.runtime_api(); @@ -73,7 +81,7 @@ where let at = BlockId::hash(best); let nonce = api.account_nonce(&at, account.clone()).map_err(|e| Error { - code: ErrorCode::ServerError(crate::constants::RUNTIME_ERROR), + code: ErrorCode::ServerError(RUNTIME_ERROR), message: "Unable to query nonce.".into(), data: Some(format!("{:?}", e).into()), })?; @@ -85,12 +93,12 @@ where // Since extrinsics are opaque to us, we look for them using // `provides` tag. And increment the nonce if we find a transaction // that matches the current one. - let mut current_nonce = nonce; - let mut current_tag = (account.clone(), nonce).encode(); + let mut current_nonce = nonce.clone(); + let mut current_tag = (account.clone(), nonce.clone()).encode(); for tx in self.pool.ready() { log::debug!( target: "rpc", - "Current nonce to {:?}, checking {} vs {:?}", + "Current nonce to {}, checking {} vs {:?}", current_nonce, HexDisplay::from(¤t_tag), tx.provides.iter().map(|x| format!("{}", HexDisplay::from(x))).collect::>(), @@ -98,8 +106,8 @@ where // since transactions in `ready()` need to be ordered by nonce // it's fine to continue with current iterator. if tx.provides.get(0) == Some(¤t_tag) { - current_nonce += 1; - current_tag = (account.clone(), current_nonce).encode(); + current_nonce += traits::One::one(); + current_tag = (account.clone(), current_nonce.clone()).encode(); } } @@ -112,42 +120,37 @@ mod tests { use super::*; use futures03::executor::block_on; - use node_runtime::{CheckedExtrinsic, Call, TimestampCall}; - use codec::Decode; - use node_testing::{ - client::{ClientExt, TestClientBuilder, TestClientBuilderExt}, - keyring::{self, alice, signed_extra}, + use test_client::{ + runtime::Transfer, + AccountKeyring, }; - const VERSION: u32 = node_runtime::VERSION.spec_version; - #[test] fn should_return_next_nonce_for_some_account() { // given let _ = env_logger::try_init(); - let client = Arc::new(TestClientBuilder::new().build()); + let client = Arc::new(test_client::new()); let pool = Arc::new(Pool::new(Default::default(), transaction_pool::FullChainApi::new(client.clone()))); - let new_transaction = |extra| { - let ex = CheckedExtrinsic { - signed: Some((alice().into(), extra)), - function: Call::Timestamp(TimestampCall::set(5)), + let new_transaction = |nonce: u64| { + let t = Transfer { + from: AccountKeyring::Alice.into(), + to: AccountKeyring::Bob.into(), + amount: 5, + nonce, }; - let xt = keyring::sign(ex, VERSION, client.genesis_hash().into()); - // Convert to OpaqueExtrinsic - let encoded = xt.encode(); - node_primitives::UncheckedExtrinsic::decode(&mut &*encoded).unwrap() + t.into_signed_tx() }; // Populate the pool - let ext0 = new_transaction(signed_extra(0, 0)); + let ext0 = new_transaction(0); block_on(pool.submit_one(&BlockId::number(0), ext0)).unwrap(); - let ext1 = new_transaction(signed_extra(1, 0)); + let ext1 = new_transaction(1); block_on(pool.submit_one(&BlockId::number(0), ext1)).unwrap(); - let accounts = Accounts::new(client, pool); + let accounts = System::new(client, pool); // when - let nonce = accounts.nonce(alice().into()); + let nonce = accounts.nonce(AccountKeyring::Alice.into()); // then assert_eq!(nonce.unwrap(), 2);