diff --git a/Cargo.lock b/Cargo.lock index c0f64efb0c327..d017ed75944ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,7 @@ dependencies = [ "substrate-codec 0.1.0", "substrate-executor 0.1.0", "substrate-primitives 0.1.0", + "substrate-rpc 0.1.0", "substrate-rpc-servers 0.1.0", "substrate-runtime-io 0.1.0", "substrate-state-machine 0.1.0", @@ -1289,7 +1290,6 @@ dependencies = [ "ed25519 0.1.0", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-api 0.1.0", @@ -1327,8 +1327,10 @@ dependencies = [ "polkadot-api 0.1.0", "polkadot-primitives 0.1.0", "polkadot-runtime 0.1.0", + "substrate-client 0.1.0", "substrate-codec 0.1.0", "substrate-primitives 0.1.0", + "substrate-rpc 0.1.0", "substrate-runtime-primitives 0.1.0", "transaction-pool 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1828,6 +1830,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-client 0.1.0", "substrate-executor 0.1.0", "substrate-primitives 0.1.0", diff --git a/demo/cli/Cargo.toml b/demo/cli/Cargo.toml index f2910d99af194..7e024afb19c49 100644 --- a/demo/cli/Cargo.toml +++ b/demo/cli/Cargo.toml @@ -19,6 +19,7 @@ substrate-state-machine = { path = "../../substrate/state-machine" } substrate-executor = { path = "../../substrate/executor" } substrate-primitives = { path = "../../substrate/primitives" } substrate-rpc-servers = { path = "../../substrate/rpc-servers" } +substrate-rpc = { path = "../../substrate/rpc" } demo-primitives = { path = "../primitives" } demo-executor = { path = "../executor" } demo-runtime = { path = "../runtime" } diff --git a/demo/cli/src/lib.rs b/demo/cli/src/lib.rs index 7aa948f1a0485..298f7228f3d59 100644 --- a/demo/cli/src/lib.rs +++ b/demo/cli/src/lib.rs @@ -26,6 +26,7 @@ extern crate substrate_runtime_io as runtime_io; extern crate substrate_state_machine as state_machine; extern crate substrate_client as client; extern crate substrate_primitives as primitives; +extern crate substrate_rpc; extern crate substrate_rpc_servers as rpc; extern crate demo_primitives; extern crate demo_executor; @@ -49,6 +50,13 @@ use demo_runtime::{GenesisConfig, ConsensusConfig, CouncilConfig, DemocracyConfi SessionConfig, StakingConfig, BuildExternalities}; use client::genesis; +struct DummyPool; +impl substrate_rpc::author::AuthorApi for DummyPool { + fn submit_extrinsic(&self, _: primitives::block::Extrinsic) -> substrate_rpc::author::error::Result<()> { + Err(substrate_rpc::author::error::ErrorKind::Unimplemented.into()) + } +} + /// Parse command line arguments and start the node. /// /// IANA unassigned port ranges that we could use: @@ -126,7 +134,7 @@ pub fn run(args: I) -> error::Result<()> where let client = Arc::new(client::new_in_mem(executor, prepare_genesis)?); let address = "127.0.0.1:9933".parse().unwrap(); - let handler = rpc::rpc_handler(client); + let handler = rpc::rpc_handler(client, DummyPool); let server = rpc::start_http(&address, handler)?; if let Some(_) = matches.subcommand_matches("validator") { diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 84040bcf06792..f650ddc85fdf2 100644 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 031e96bdb0ee6..8f03da6b6570e 100755 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ diff --git a/polkadot/cli/src/lib.rs b/polkadot/cli/src/lib.rs index 27ebc867d989d..9a7edd7431a97 100644 --- a/polkadot/cli/src/lib.rs +++ b/polkadot/cli/src/lib.rs @@ -116,7 +116,7 @@ pub fn run(args: I, exit: mpsc::Receiver<()>) -> error::Result<()> where let rpc_port: u16 = port.parse().expect("Invalid RPC port value specified."); address.set_port(rpc_port); } - let handler = rpc::rpc_handler(service.client()); + let handler = rpc::rpc_handler(service.client(), service.transaction_pool()); let _server = rpc::start_http(&address, handler)?; exit.recv().ok(); @@ -148,6 +148,7 @@ fn default_base_path() -> PathBuf { &app_info, ).expect("app directories exist on all supported platforms; qed") } + fn init_logger(pattern: &str) { let mut builder = env_logger::LogBuilder::new(); // Disable info logging by default for some modules: diff --git a/polkadot/consensus/src/lib.rs b/polkadot/consensus/src/lib.rs index d6f9398486141..53cf39b6c8f23 100644 --- a/polkadot/consensus/src/lib.rs +++ b/polkadot/consensus/src/lib.rs @@ -570,9 +570,13 @@ impl bft::Proposer for Proposer { } let polkadot_block = block_builder.bake(); + info!("Proposing block [number: {}; extrinsics: [{}], parent_hash: {}]", polkadot_block.header.number, polkadot_block.extrinsics.len(), polkadot_block.header.parent_hash); + let substrate_block = Slicable::decode(&mut polkadot_block.encode().as_slice()) .expect("polkadot blocks defined to serialize to substrate blocks correctly; qed"); + assert!(evaluate_proposal(&substrate_block, &*self.client, current_timestamp(), &self.parent_hash, &self.parent_id).is_ok()); + Ok(substrate_block) } diff --git a/polkadot/runtime/wasm/genesis.wasm b/polkadot/runtime/wasm/genesis.wasm index e5393d0d09674..b7adff2d53861 100644 Binary files a/polkadot/runtime/wasm/genesis.wasm and b/polkadot/runtime/wasm/genesis.wasm differ diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index e5393d0d09674..b7adff2d53861 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 08b69ae04f0a2..d4e3dd6dd34f3 100755 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ diff --git a/polkadot/transaction-pool/Cargo.toml b/polkadot/transaction-pool/Cargo.toml index 6efc3cc3fe659..d80384c23c9c3 100644 --- a/polkadot/transaction-pool/Cargo.toml +++ b/polkadot/transaction-pool/Cargo.toml @@ -9,6 +9,8 @@ error-chain = "0.11" polkadot-api = { path = "../api" } polkadot-primitives = { path = "../primitives" } polkadot-runtime = { path = "../runtime" } +substrate-client = { path = "../../substrate/client" } +substrate-rpc = { path = "../../substrate/rpc" } substrate-primitives = { path = "../../substrate/primitives" } substrate-runtime-primitives = { path = "../../substrate/runtime/primitives" } substrate-codec = { path = "../../substrate/codec" } diff --git a/polkadot/transaction-pool/src/lib.rs b/polkadot/transaction-pool/src/lib.rs index f2473053dcac0..47fc7c99bd128 100644 --- a/polkadot/transaction-pool/src/lib.rs +++ b/polkadot/transaction-pool/src/lib.rs @@ -17,6 +17,7 @@ extern crate ed25519; extern crate ethereum_types; extern crate substrate_codec as codec; +extern crate substrate_rpc; extern crate substrate_primitives as substrate_primitives; extern crate substrate_runtime_primitives as substrate_runtime_primitives; extern crate polkadot_runtime as runtime; @@ -31,8 +32,10 @@ use std::collections::HashMap; use std::cmp::Ordering; use std::sync::Arc; +use codec::Slicable; use polkadot_api::PolkadotApi; use primitives::{AccountId, Timestamp}; +use substrate_primitives::block::Extrinsic; use runtime::{Block, UncheckedExtrinsic, TimestampCall, Call}; use substrate_runtime_primitives::traits::Checkable; use transaction_pool::{Pool, Readiness}; @@ -371,6 +374,16 @@ impl TransactionPool { } } +impl substrate_rpc::author::AsyncAuthorApi for TransactionPool { + fn submit_extrinsic(&mut self, xt: Extrinsic) -> substrate_rpc::author::error::Result<()> { + self.import(xt + .using_encoded(|ref mut s| UncheckedExtrinsic::decode(s)) + .ok_or(substrate_rpc::author::error::ErrorKind::InvalidFormat)?) + .map(|_| ()) + .map_err(|_| substrate_rpc::author::error::ErrorKind::PoolError.into()) + } +} + #[cfg(test)] mod tests { } diff --git a/substrate/primitives/src/block.rs b/substrate/primitives/src/block.rs index eb909c93fa069..29ea4afac1fa2 100644 --- a/substrate/primitives/src/block.rs +++ b/substrate/primitives/src/block.rs @@ -47,6 +47,21 @@ impl Slicable for Transaction { } } +/// Simple generic extrinsic type. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub struct Extrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec); + +impl Slicable for Extrinsic { + fn decode(input: &mut I) -> Option { + Vec::::decode(input).map(Extrinsic) + } + + fn using_encoded R>(&self, f: F) -> R { + self.0.using_encoded(f) + } +} + /// Execution log (event) #[derive(PartialEq, Eq, Clone, Default)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] diff --git a/substrate/rpc-servers/src/lib.rs b/substrate/rpc-servers/src/lib.rs index cf2f6f2dc1677..08a8c6e1eb247 100644 --- a/substrate/rpc-servers/src/lib.rs +++ b/substrate/rpc-servers/src/lib.rs @@ -26,11 +26,13 @@ extern crate jsonrpc_http_server as http; use std::io; /// Construct rpc `IoHandler` -pub fn rpc_handler(state: S) -> rpc::IoHandler where +pub fn rpc_handler(state: S, transaction_pool: T) -> rpc::IoHandler where S: apis::state::StateApi, + T: apis::author::AuthorApi, { let mut io = rpc::IoHandler::new(); io.extend_with(state.to_delegate()); + io.extend_with(transaction_pool.to_delegate()); io } diff --git a/substrate/rpc/Cargo.toml b/substrate/rpc/Cargo.toml index 485e08708c79d..56e0e4117c51a 100644 --- a/substrate/rpc/Cargo.toml +++ b/substrate/rpc/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] +parking_lot = "0.4" error-chain = "0.11" jsonrpc-core = { git="https://github.com/paritytech/jsonrpc.git" } jsonrpc-macros = { git="https://github.com/paritytech/jsonrpc.git" } diff --git a/substrate/rpc/src/author/error.rs b/substrate/rpc/src/author/error.rs new file mode 100644 index 0000000000000..05c2da37ac5d8 --- /dev/null +++ b/substrate/rpc/src/author/error.rs @@ -0,0 +1,54 @@ +// Copyright 2017 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 . + +use client; +use rpc; + +error_chain! { + links { + Client(client::error::Error, client::error::ErrorKind) #[doc = "Client error"]; + } + errors { + /// Not implemented yet + Unimplemented { + description("not yet implemented"), + display("Method Not Implemented"), + } + /// Invalid format + InvalidFormat { + description("invalid format"), + display("Invalid format for the extrinsic data"), + } + /// Some error with the pool since the import failed. + PoolError { + description("pool import failed"), + display("Pool import failed"), + } + } +} + +impl From for rpc::Error { + fn from(e: Error) -> Self { + match e { + Error(ErrorKind::Unimplemented, _) => rpc::Error { + code: rpc::ErrorCode::ServerError(-1), + message: "Not implemented yet".into(), + data: None, + }, + _ => rpc::Error::internal_error(), + } + } +} diff --git a/substrate/rpc/src/author/mod.rs b/substrate/rpc/src/author/mod.rs new file mode 100644 index 0000000000000..61683e77b18b3 --- /dev/null +++ b/substrate/rpc/src/author/mod.rs @@ -0,0 +1,49 @@ +// Copyright 2017 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 . + +//! Substrate block-author/full-node API. + +use std::sync::Arc; +use parking_lot::Mutex; +use primitives::block::Extrinsic; + +pub mod error; + +#[cfg(test)] +mod tests; + +use self::error::Result; + +build_rpc_trait! { + /// Substrate authoring RPC API + pub trait AuthorApi { + /// Submit extrinsic for inclusion in block. + #[rpc(name = "author_submitExtrinsic")] + fn submit_extrinsic(&self, Extrinsic) -> Result<()>; + } +} + +/// Variant of the AuthorApi that doesn't need to be Sync + Send + 'static. +pub trait AsyncAuthorApi: Send + 'static { + /// Submit extrinsic for inclusion in block. + fn submit_extrinsic(&mut self, Extrinsic) -> Result<()>; +} + +impl AuthorApi for Arc> { + fn submit_extrinsic(&self, xt: Extrinsic) -> Result<()> { + self.as_ref().lock().submit_extrinsic(xt) + } +} diff --git a/substrate/rpc/src/author/tests.rs b/substrate/rpc/src/author/tests.rs new file mode 100644 index 0000000000000..fd9b9062e6464 --- /dev/null +++ b/substrate/rpc/src/author/tests.rs @@ -0,0 +1,50 @@ +// Copyright 2017 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 . + +use primitives::block; +use substrate_executor as executor; +use super::*; +use super::error::*; + +#[derive(Default)] +struct DummyTxPool { + submitted: Vec, +} + +impl AsyncAuthorApi for DummyTxPool { + /// Submit extrinsic for inclusion in block. + fn submit_extrinsic(&mut self, xt: Extrinsic) -> Result<()> { + if self.submitted.len() < 1 { + self.submitted.push(xt); + Ok(()) + } else { + Err(ErrorKind::PoolError.into()) + } + } +} + +#[test] +fn submit_transaction_should_not_cause_error() { + let mut p = Arc::new(Mutex::new(DummyTxPool::default())); + + assert_matches!( + AuthorApi::submit_extrinsic(&p, block::Extrinsic(vec![])), + Ok(()) + ); + assert!( + AuthorApi::submit_extrinsic(&p, block::Extrinsic(vec![])).is_err() + ); +} diff --git a/substrate/rpc/src/lib.rs b/substrate/rpc/src/lib.rs index 513bc42d873f8..3c9a46e4d4a3c 100644 --- a/substrate/rpc/src/lib.rs +++ b/substrate/rpc/src/lib.rs @@ -18,6 +18,7 @@ #![warn(missing_docs)] +extern crate parking_lot; extern crate jsonrpc_core as rpc; extern crate substrate_client as client; extern crate substrate_primitives as primitives; @@ -38,3 +39,4 @@ extern crate substrate_runtime_support as runtime_support; pub mod chain; pub mod state; +pub mod author;