Skip to content
Snippets Groups Projects
Commit db78e5fb authored by Tomasz Drwięga's avatar Tomasz Drwięga Committed by asynchronous rob
Browse files

RPC & Client (#21)

* Initial version of http server.

* Refactor the structure.

* add unassigned ports info.

* Rename servers to match conventions.

* Add client crate and some proper RPC implementations.

* Style & docs.
parent 0ceebe66
No related merge requests found
Showing
with 804 additions and 17 deletions
This diff is collapsed.
[package]
name = "polkadot"
version = "0.1.0"
authors = ["Parity Team <admin@parity.io>"]
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.11"
polkadot-cli = { path = "cli", version = "0.1" }
[workspace]
members = [
"client",
"contracts",
"primitives",
"rpc",
"rpc_servers",
"serializer",
"state_machine",
"validator",
......
[package]
name = "polkadot-cli"
version = "0.1.0"
authors = ["Parity Team <admin@parity.io>"]
authors = ["Parity Technologies <admin@parity.io>"]
description = "Polkadot node implementation in Rust."
[dependencies]
clap = { version = "2.27", features = ["yaml"] }
env_logger = "0.4"
error-chain = "0.11"
log = "0.3"
polkadot-client = { path = "../client", version = "0.1" }
polkadot-contracts = { path = "../contracts", version = "0.1" }
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-rpc-servers = { path = "../rpc_servers", version = "0.1" }
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Initialization errors.
error_chain! {
foreign_links {
Io(::std::io::Error) #[doc="IO error"];
Cli(::clap::Error) #[doc="CLI error"];
}
}
......@@ -19,34 +19,65 @@
#![warn(missing_docs)]
extern crate env_logger;
extern crate polkadot_client as client;
extern crate polkadot_contracts as contracts;
extern crate polkadot_primitives as primitives;
extern crate polkadot_rpc_servers as rpc;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate log;
pub mod error;
/// Parse command line arguments and start the node.
pub fn main() {
///
/// IANA unassigned port ranges that we could use:
/// 6717-6766 Unassigned
/// 8504-8553 Unassigned
/// 9556-9591 Unassigned
/// 9803-9874 Unassigned
/// 9926-9949 Unassigned
pub fn run<I, T>(args: I) -> error::Result<()> where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
let yaml = load_yaml!("./cli.yml");
let matches = clap::App::from_yaml(yaml).get_matches();
let matches = clap::App::from_yaml(yaml).get_matches_from_safe(args)?;
// TODO [ToDr] Split paremeters parsing from actual execution.
let log_pattern = matches.value_of("log").unwrap_or("");
init_logger(log_pattern);
// Create client
let blockchain = DummyBlockchain;
let executor = contracts::executor();
let client = client::Client::new(blockchain, executor);
let address = "127.0.0.1:9933".parse().unwrap();
let handler = rpc::rpc_handler(client);
let server = rpc::start_http(&address, handler)?;
if let Some(_) = matches.subcommand_matches("collator") {
info!("Starting collator.");
return;
server.wait();
return Ok(());
}
if let Some(_) = matches.subcommand_matches("validator") {
info!("Starting validator.");
return;
server.wait();
return Ok(());
}
println!("No command given.\n");
let _ = clap::App::from_yaml(yaml).print_long_help();
}
Ok(())
}
fn init_logger(pattern: &str) {
let mut builder = env_logger::LogBuilder::new();
......@@ -64,3 +95,18 @@ fn init_logger(pattern: &str) {
builder.init().expect("Logger initialized only once.");
}
#[derive(Debug, Default)]
struct DummyBlockchain;
impl client::Blockchain for DummyBlockchain {
type Error = ();
fn latest_hash(&self) -> Result<primitives::block::HeaderHash, Self::Error> {
Ok(0.into())
}
fn header(&self, _hash: &primitives::block::HeaderHash) -> Result<Option<primitives::block::Header>, Self::Error> {
Ok(None)
}
}
[package]
name = "polkadot-client"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.11"
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-state-machine = { path = "../state_machine", version = "0.1" }
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot client possible errors.
use primitives::block;
use state_machine;
error_chain! {
errors {
/// Backend error.
Backend {
description("Unrecoverable backend error"),
display("Backend error"),
}
/// Unknown block.
UnknownBlock(h: block::HeaderHash) {
description("unknown block"),
display("UnknownBlock: {}", h),
}
/// Execution error.
Execution(e: Box<state_machine::Error>) {
description("execution error"),
display("Execution: {}", e),
}
}
}
// TODO [ToDr] Temporary, state_machine::Error should be a regular error not Box.
impl From<Box<state_machine::Error>> for Error {
fn from(e: Box<state_machine::Error>) -> Self {
ErrorKind::Execution(e).into()
}
}
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot Client
#![warn(missing_docs)]
extern crate polkadot_primitives as primitives;
extern crate polkadot_state_machine as state_machine;
#[macro_use]
extern crate error_chain;
pub mod error;
use primitives::{block, Address, H256};
use primitives::contract::{CallData, OutData, StorageData};
use state_machine::backend::Backend;
use self::error::ResultExt;
/// Blockchain access
pub trait Blockchain {
/// Error Type
type Error;
/// Returns the hash of latest block.
fn latest_hash(&self) -> Result<block::HeaderHash, Self::Error>;
/// Given a hash return a header
fn header(&self, hash: &block::HeaderHash) -> Result<Option<block::Header>, Self::Error>;
}
/// Polkadot Client
#[derive(Debug)]
pub struct Client<B, E> {
blockchain: B,
executor: E,
}
impl<B, E> Client<B, E> {
/// Creates new Polkadot Client with given blockchain and code executor.
pub fn new(blockchain: B, executor: E) -> Self {
Client {
blockchain,
executor,
}
}
}
impl<B, E> Client<B, E> where
B: Blockchain,
E: state_machine::CodeExecutor,
{
fn state_at(&self, _hash: &block::HeaderHash) -> error::Result<state_machine::backend::InMemory> {
// TODO [ToDr] Actually retrieve the state.
Ok(state_machine::backend::InMemory::default())
}
/// Return single storage entry of contract under given address in state in a block of given hash.
pub fn storage(&self, hash: &block::HeaderHash, address: &Address, key: &H256) -> error::Result<StorageData> {
self.state_at(hash)?
.storage(address, key)
.map(|x| StorageData(x.to_vec()))
.chain_err(|| error::ErrorKind::Backend)
}
/// Execute a call to a contract on top of state in a block of given hash.
pub fn call(&self, hash: &block::HeaderHash, address: &Address, method: &str, call_data: &CallData) -> error::Result<OutData> {
let state = self.state_at(hash)?;
let mut changes = state_machine::OverlayedChanges::default();
Ok(state_machine::execute(
&state,
&mut changes,
&self.executor,
address,
method,
call_data,
)?)
}
}
[package]
name = "polkadot-contracts"
version = "0.1.0"
authors = ["Parity Team <admin@parity.io>"]
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
assert_matches = "1.1"
error-chain = "0.11"
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-serializer = { path = "../serializer", version = "0.1" }
polkadot-state-machine = { path = "../state_machine" , version = "0.1" }
serde = "1.0"
serde_derive = "1.0"
[dev-dependencies]
assert_matches = "1.1"
......@@ -16,14 +16,12 @@
//! Rust executor possible errors.
#![allow(missing_docs)]
use serializer;
use state_machine;
error_chain! {
foreign_links {
InvalidData(serializer::Error);
InvalidData(serializer::Error) #[doc = "Unserializable Data"];
}
errors {
......
......@@ -18,7 +18,7 @@
use primitives::contract::{CallData, OutData};
use serializer::{from_slice as de, to_vec as ser};
use state_machine::{StaticExternalities, Externalities, Executor};
use state_machine::{StaticExternalities, Externalities, CodeExecutor};
use error::{Error, ErrorKind, Result};
use auth;
......@@ -42,7 +42,7 @@ impl RustExecutor {
const VALIDATOR_SET: u8 = 3;
}
impl Executor for RustExecutor {
impl CodeExecutor for RustExecutor {
type Error = Error;
fn call_static<E: StaticExternalities<Self>>(
......
......@@ -42,6 +42,6 @@ pub mod error;
pub mod executor;
/// Creates new RustExecutor for contracts.
pub fn new() -> executor::RustExecutor {
pub fn executor() -> executor::RustExecutor {
executor::RustExecutor::default()
}
[package]
name = "polkadot-primitives"
version = "0.1.0"
authors = ["Parity Team <admin@parity.io>"]
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
crunchy = "0.1"
......
......@@ -49,7 +49,6 @@ pub struct Body {
pub para_blocks: Vec<parachain::Proposal>,
}
#[cfg(test)]
mod tests {
use super::*;
......
......@@ -25,3 +25,7 @@ pub struct CallData(#[serde(with="bytes")] pub Vec<u8>);
/// Contract output data.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct OutData(#[serde(with="bytes")] pub Vec<u8>);
/// Contract storage entry data.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StorageData(#[serde(with="bytes")] pub Vec<u8>);
......@@ -49,6 +49,8 @@ pub mod validator;
/// Alias to 160-bit hash when used in the context of an account address.
pub type Address = hash::H160;
pub use self::hash::{H160, H256};
pub use self::uint::{U256, U512};
/// A hash function.
pub fn hash(data: &[u8]) -> hash::H256 {
......
[package]
name = "polkadot-rpc"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
error-chain = "0.11"
jsonrpc-core = { git="https://github.com/paritytech/jsonrpc.git" }
jsonrpc-macros = { git="https://github.com/paritytech/jsonrpc.git" }
polkadot-client = { path = "../client", version = "0.1" }
polkadot-primitives = { path = "../primitives", version = "0.1" }
polkadot-state-machine = { path = "../state_machine", version = "0.1" }
[dev-dependencies]
assert_matches = "1.1"
polkadot-contracts = { path = "../contracts", version = "0.1" }
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
use rpc;
error_chain! {
errors {
/// Not implemented yet
Unimplemented {
description("not yet implemented"),
display("Method Not Implemented"),
}
}
}
impl From<Error> 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(),
}
}
}
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Polkadot blockchain API.
use primitives::block;
use client;
mod error;
#[cfg(test)]
mod tests;
use self::error::{Result, ResultExt};
build_rpc_trait! {
/// Polkadot blockchain API
pub trait ChainApi {
/// Get header of a relay chain block.
#[rpc(name = "chain_getHeader")]
fn header(&self, block::HeaderHash) -> Result<Option<block::Header>>;
}
}
impl<B> ChainApi for B where
B: client::Blockchain + Send + Sync + 'static,
B::Error: ::std::error::Error + Send,
{
fn header(&self, hash: block::HeaderHash) -> Result<Option<block::Header>> {
self.header(&hash).chain_err(|| "Blockchain error")
}
}
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use test_helpers::Blockchain;
#[test]
fn should_return_header() {
let state = Blockchain::default();
assert_matches!(
ChainApi::header(&state, 0.into()),
Ok(Some(ref x)) if x == &block::Header {
parent_hash: 0.into(),
state_root: 0.into(),
timestamp: 0,
number: 0,
}
);
assert_matches!(
ChainApi::header(&state, 5.into()),
Ok(None)
);
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment