diff --git a/codechain/rpc.rs b/codechain/rpc.rs
index f642c42005..a9daa7d7a4 100644
--- a/codechain/rpc.rs
+++ b/codechain/rpc.rs
@@ -15,8 +15,8 @@
// along with this program. If not, see .
use std::io;
-use std::net::SocketAddr;
+use crate::config::Config;
use crate::rpc_apis;
use crpc::{
jsonrpc_core, start_http, start_ipc, start_ws, HttpServer, IpcServer, MetaIoHandler, Middleware, WsError, WsServer,
@@ -33,38 +33,27 @@ pub struct RpcHttpConfig {
}
pub fn rpc_http_start(
- cfg: RpcHttpConfig,
- enable_devel_api: bool,
- deps: &rpc_apis::ApiDependencies,
+ server: MetaIoHandler<(), impl Middleware<()>>,
+ config: RpcHttpConfig,
) -> Result {
- let url = format!("{}:{}", cfg.interface, cfg.port);
+ let url = format!("{}:{}", config.interface, config.port);
let addr = url.parse().map_err(|_| format!("Invalid JSONRPC listen host/port given: {}", url))?;
- let server = setup_http_rpc_server(&addr, cfg.cors.clone(), cfg.hosts.clone(), enable_devel_api, deps)?;
- cinfo!(RPC, "RPC Listening on {}", url);
- if let Some(hosts) = cfg.hosts {
- cinfo!(RPC, "Allowed hosts are {:?}", hosts);
- }
- if let Some(cors) = cfg.cors {
- cinfo!(RPC, "CORS domains are {:?}", cors);
- }
- Ok(server)
-}
-
-fn setup_http_rpc_server(
- url: &SocketAddr,
- cors_domains: Option>,
- allowed_hosts: Option>,
- enable_devel_api: bool,
- deps: &rpc_apis::ApiDependencies,
-) -> Result {
- let server = setup_rpc_server(enable_devel_api, deps);
- let start_result = start_http(url, cors_domains, allowed_hosts, server);
+ let start_result = start_http(&addr, config.cors.clone(), config.hosts.clone(), server);
match start_result {
Err(ref err) if err.kind() == io::ErrorKind::AddrInUse => {
Err(format!("RPC address {} is already in use, make sure that another instance of a CodeChain node is not running or change the address using the --jsonrpc-port option.", url))
},
Err(e) => Err(format!("RPC error: {:?}", e)),
- Ok(server) => Ok(server),
+ Ok(server) => {
+ cinfo!(RPC, "RPC Listening on {}", url);
+ if let Some(hosts) = config.hosts {
+ cinfo!(RPC, "Allowed hosts are {:?}", hosts);
+ }
+ if let Some(cors) = config.cors {
+ cinfo!(RPC, "CORS domains are {:?}", cors);
+ }
+ Ok(server)
+ },
}
}
@@ -74,19 +63,17 @@ pub struct RpcIpcConfig {
}
pub fn rpc_ipc_start(
- cfg: &RpcIpcConfig,
- enable_devel_api: bool,
- deps: &rpc_apis::ApiDependencies,
+ server: MetaIoHandler<(), impl Middleware<()>>,
+ config: RpcIpcConfig,
) -> Result {
- let server = setup_rpc_server(enable_devel_api, deps);
- let start_result = start_ipc(&cfg.socket_addr, server);
+ let start_result = start_ipc(&config.socket_addr, server);
match start_result {
Err(ref err) if err.kind() == io::ErrorKind::AddrInUse => {
- Err(format!("IPC address {} is already in use, make sure that another instance of a Codechain node is not running or change the address using the --ipc-path options.", cfg.socket_addr))
+ Err(format!("IPC address {} is already in use, make sure that another instance of a Codechain node is not running or change the address using the --ipc-path options.", config.socket_addr))
},
Err(e) => Err(format!("IPC error: {:?}", e)),
Ok(server) => {
- cinfo!(RPC, "IPC Listening on {}", cfg.socket_addr);
+ cinfo!(RPC, "IPC Listening on {}", config.socket_addr);
Ok(server)
},
}
@@ -99,15 +86,10 @@ pub struct RpcWsConfig {
pub max_connections: usize,
}
-pub fn rpc_ws_start(
- cfg: &RpcWsConfig,
- enable_devel_api: bool,
- deps: &rpc_apis::ApiDependencies,
-) -> Result {
- let server = setup_rpc_server(enable_devel_api, deps);
- let url = format!("{}:{}", cfg.interface, cfg.port);
+pub fn rpc_ws_start(server: MetaIoHandler<(), impl Middleware<()>>, config: RpcWsConfig) -> Result {
+ let url = format!("{}:{}", config.interface, config.port);
let addr = url.parse().map_err(|_| format!("Invalid WebSockets listen host/port given: {}", url))?;
- let start_result = start_ws(&addr, server, cfg.max_connections);
+ let start_result = start_ws(&addr, server, config.max_connections);
match start_result {
Err(WsError::Io(ref err)) if err.kind() == io::ErrorKind::AddrInUse => {
Err(format!("WebSockets address {} is already in use, make sure that another instance of a Codechain node is not running or change the address using the --ws-port options.", addr))
@@ -120,12 +102,9 @@ pub fn rpc_ws_start(
}
}
-fn setup_rpc_server(
- enable_devel_api: bool,
- deps: &rpc_apis::ApiDependencies,
-) -> MetaIoHandler<(), impl Middleware<()>> {
+pub fn setup_rpc_server(config: &Config, deps: &rpc_apis::ApiDependencies) -> MetaIoHandler<(), impl Middleware<()>> {
let mut handler = MetaIoHandler::with_middleware(LogMiddleware::new());
- deps.extend_api(enable_devel_api, &mut handler);
+ deps.extend_api(config, &mut handler);
rpc_apis::setup_rpc(handler)
}
diff --git a/codechain/rpc_apis.rs b/codechain/rpc_apis.rs
index 3f4d3c016a..bc701275df 100644
--- a/codechain/rpc_apis.rs
+++ b/codechain/rpc_apis.rs
@@ -22,6 +22,8 @@ use cnetwork::{EventSender, NetworkControl};
use crpc::{MetaIoHandler, Middleware, Params, Value};
use csync::BlockSyncEvent;
+use crate::config::Config;
+
pub struct ApiDependencies {
pub client: Arc,
pub miner: Arc,
@@ -31,11 +33,12 @@ pub struct ApiDependencies {
}
impl ApiDependencies {
- pub fn extend_api(&self, enable_devel_api: bool, handler: &mut MetaIoHandler<(), impl Middleware<()>>) {
+ pub fn extend_api(&self, config: &Config, handler: &mut MetaIoHandler<(), impl Middleware<()>>) {
use crpc::v1::*;
handler.extend_with(ChainClient::new(Arc::clone(&self.client)).to_delegate());
handler.extend_with(MempoolClient::new(Arc::clone(&self.client)).to_delegate());
- if enable_devel_api {
+ handler.extend_with(SnapshotClient::new(Arc::clone(&self.client), config.snapshot.path.clone()).to_delegate());
+ if config.rpc.enable_devel_api {
handler.extend_with(
DevelClient::new(Arc::clone(&self.client), Arc::clone(&self.miner), self.block_sync.clone())
.to_delegate(),
diff --git a/codechain/run_node.rs b/codechain/run_node.rs
index a2fe31670f..837589f070 100644
--- a/codechain/run_node.rs
+++ b/codechain/run_node.rs
@@ -44,7 +44,7 @@ use crate::config::{self, load_config};
use crate::constants::{DEFAULT_DB_PATH, DEFAULT_KEYS_PATH};
use crate::dummy_network_service::DummyNetworkService;
use crate::json::PasswordFile;
-use crate::rpc::{rpc_http_start, rpc_ipc_start, rpc_ws_start};
+use crate::rpc::{rpc_http_start, rpc_ipc_start, rpc_ws_start, setup_rpc_server};
use crate::rpc_apis::ApiDependencies;
fn network_start(
@@ -326,36 +326,44 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> {
}
};
- let rpc_apis_deps = Arc::new(ApiDependencies {
- client: client.client(),
- miner: Arc::clone(&miner),
- network_control: Arc::clone(&network_service),
- account_provider: ap,
- block_sync: maybe_sync_sender,
- });
+ let (rpc_server, ipc_server, ws_server) = {
+ let rpc_apis_deps = ApiDependencies {
+ client: client.client(),
+ miner: Arc::clone(&miner),
+ network_control: Arc::clone(&network_service),
+ account_provider: ap,
+ block_sync: maybe_sync_sender,
+ };
- let rpc_server = {
- if !config.rpc.disable.unwrap() {
- Some(rpc_http_start(config.rpc_http_config(), config.rpc.enable_devel_api, &*rpc_apis_deps)?)
- } else {
- None
- }
- };
- let ipc_server = {
- if !config.ipc.disable.unwrap() {
- Some(rpc_ipc_start(&config.rpc_ipc_config(), config.rpc.enable_devel_api, &*rpc_apis_deps)?)
- } else {
- None
- }
- };
+ let rpc_server = {
+ if !config.rpc.disable.unwrap() {
+ let server = setup_rpc_server(&config, &rpc_apis_deps);
+ Some(rpc_http_start(server, config.rpc_http_config())?)
+ } else {
+ None
+ }
+ };
- let ws_server = {
- if !config.ws.disable.unwrap() {
- Some(rpc_ws_start(&config.rpc_ws_config(), config.rpc.enable_devel_api, &*rpc_apis_deps)?)
- } else {
- None
- }
+ let ipc_server = {
+ if !config.ipc.disable.unwrap() {
+ let server = setup_rpc_server(&config, &rpc_apis_deps);
+ Some(rpc_ipc_start(server, config.rpc_ipc_config())?)
+ } else {
+ None
+ }
+ };
+
+ let ws_server = {
+ if !config.ws.disable.unwrap() {
+ let server = setup_rpc_server(&config, &rpc_apis_deps);
+ Some(rpc_ws_start(server, config.rpc_ws_config())?)
+ } else {
+ None
+ }
+ };
+
+ (rpc_server, ipc_server, ws_server)
};
if (!config.stratum.disable.unwrap()) && (miner.engine_type() == EngineType::PoW) {
diff --git a/rpc/src/v1/errors.rs b/rpc/src/v1/errors.rs
index 6af198ee29..8f15a45cb7 100644
--- a/rpc/src/v1/errors.rs
+++ b/rpc/src/v1/errors.rs
@@ -304,6 +304,14 @@ pub fn invalid_custom_action(err: String) -> Error {
}
}
+pub fn io(error: std::io::Error) -> Error {
+ Error {
+ code: ErrorCode::InternalError,
+ message: format!("{}", error),
+ data: None,
+ }
+}
+
/// Internal error signifying a logic error in code.
/// Should not be used when function can just fail
/// because of invalid parameters or incomplete node state.
diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs
index 45e7678459..3360f5682e 100644
--- a/rpc/src/v1/impls/mod.rs
+++ b/rpc/src/v1/impls/mod.rs
@@ -21,6 +21,7 @@ mod engine;
mod mempool;
mod miner;
mod net;
+mod snapshot;
pub use self::account::AccountClient;
pub use self::chain::ChainClient;
@@ -29,3 +30,4 @@ pub use self::engine::EngineClient;
pub use self::mempool::MempoolClient;
pub use self::miner::MinerClient;
pub use self::net::NetClient;
+pub use self::snapshot::SnapshotClient;
diff --git a/rpc/src/v1/impls/snapshot.rs b/rpc/src/v1/impls/snapshot.rs
new file mode 100644
index 0000000000..f030c9bbd3
--- /dev/null
+++ b/rpc/src/v1/impls/snapshot.rs
@@ -0,0 +1,88 @@
+// Copyright 2018-2019 Kodebox, Inc.
+// This file is part of CodeChain.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use std::fs;
+use std::str::FromStr;
+use std::sync::Arc;
+
+use ccore::{BlockChainClient, BlockId};
+use ctypes::BlockHash;
+use primitives::H256;
+
+use jsonrpc_core::Result;
+
+use super::super::errors;
+use super::super::traits::Snapshot;
+use super::super::types::BlockNumberAndHash;
+
+pub struct SnapshotClient
+where
+ C: BlockChainClient, {
+ client: Arc,
+ snapshot_path: Option,
+}
+
+impl SnapshotClient
+where
+ C: BlockChainClient,
+{
+ pub fn new(client: Arc, snapshot_path: Option) -> Self {
+ SnapshotClient {
+ client,
+ snapshot_path,
+ }
+ }
+}
+
+impl Snapshot for SnapshotClient
+where
+ C: BlockChainClient + 'static,
+{
+ fn get_snapshot_list(&self) -> Result> {
+ if let Some(snapshot_path) = &self.snapshot_path {
+ let mut result = Vec::new();
+ for entry in fs::read_dir(snapshot_path).map_err(errors::io)? {
+ let entry = entry.map_err(errors::io)?;
+
+ // Check if the entry is a directory
+ let file_type = entry.file_type().map_err(errors::io)?;
+ if !file_type.is_dir() {
+ continue
+ }
+
+ let path = entry.path();
+ let name = match path.file_name().expect("Directories always have file name").to_str() {
+ Some(n) => n,
+ None => continue,
+ };
+ let hash = match H256::from_str(name) {
+ Ok(h) => BlockHash::from(h),
+ Err(_) => continue,
+ };
+ if let Some(number) = self.client.block_number(&BlockId::Hash(hash)) {
+ result.push(BlockNumberAndHash {
+ number,
+ hash,
+ });
+ }
+ }
+ result.sort_unstable_by(|a, b| b.number.cmp(&a.number));
+ Ok(result)
+ } else {
+ Ok(Vec::new())
+ }
+ }
+}
diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs
index 719f186e49..7f2bd04599 100644
--- a/rpc/src/v1/traits/mod.rs
+++ b/rpc/src/v1/traits/mod.rs
@@ -21,6 +21,7 @@ mod engine;
mod mempool;
mod miner;
mod net;
+mod snapshot;
pub use self::account::Account;
pub use self::chain::Chain;
@@ -29,3 +30,4 @@ pub use self::engine::Engine;
pub use self::mempool::Mempool;
pub use self::miner::Miner;
pub use self::net::Net;
+pub use self::snapshot::Snapshot;
diff --git a/rpc/src/v1/traits/snapshot.rs b/rpc/src/v1/traits/snapshot.rs
new file mode 100644
index 0000000000..0fd9c18366
--- /dev/null
+++ b/rpc/src/v1/traits/snapshot.rs
@@ -0,0 +1,26 @@
+// Copyright 2018-2019 Kodebox, Inc.
+// This file is part of CodeChain.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+use jsonrpc_core::Result;
+
+use super::super::types::BlockNumberAndHash;
+
+#[rpc(server)]
+pub trait Snapshot {
+ /// Gets list of block numbers and block hashes of the snapshots.
+ #[rpc(name = "snapshot_getList")]
+ fn get_snapshot_list(&self) -> Result>;
+}