RPC server is moved to a new process (optionally) (#1874)
* Move RPC to new process * Readd reuse address * Formatting * Remove rpc dependency from node CMakeLists.txt file * Fix rpc.online_reps test * Only use boost process when using a boost version other than 1.69 * Formatting, add thread name to RPC thread * Call lock () on the lock itself not mutex * Allow RPC in-process as well * Formatting * Formatting * Revert filenames to have underscores again for readability * Use boost interprocess with node daemon as well. Move definitions to CMakeLists.txt * Delete unused options after migration. Don't migrate version so that an upgrade to the new rpc_config is performed filling in the rest of the options with appropriate defaults. * Change debug_ipc to debug_rpc * Removed unused ipc_path from new rpc_config * Change --daemon CLI help to state it is for the RPC * Remove rpc_path from load-tester * Fix global network_constants initialization issue * Fix session timer timing issue * Remove default_ipc_port from node_rpc_config::migrate () * Remove semi-colon from command line args preventing others below it from working. * Remove message about failing to migrate RPC path in rpc_config * Move cleanup_test_directories_on_exit to node to resolve link error with nano_rpc
This commit is contained in:
parent
ebcd2dd3c2
commit
c3046c11d5
73 changed files with 7551 additions and 5749 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -32,9 +32,15 @@ core_test
|
|||
rpc_test
|
||||
!rpc_test/
|
||||
qt_test
|
||||
!qt_test/
|
||||
nano_node
|
||||
!nano_node/
|
||||
nano_wallet
|
||||
!nano_wallet/
|
||||
slow_test
|
||||
!slow_test/
|
||||
nano_rpc
|
||||
!nano_rpc/
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
|
|
|
@ -157,6 +157,13 @@ endif ()
|
|||
|
||||
find_package (Boost 1.67.0 REQUIRED COMPONENTS filesystem log thread program_options system)
|
||||
|
||||
# There is a compile bug with boost 1.69 interprocess headers on Mac
|
||||
if (APPLE AND Boost_VERSION EQUAL 106900)
|
||||
set (BOOST_PROCESS_SUPPORTED 0)
|
||||
else ()
|
||||
set (BOOST_PROCESS_SUPPORTED 1)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(crypto/ed25519-donna)
|
||||
|
||||
set (UPNPC_BUILD_SHARED OFF CACHE BOOL "")
|
||||
|
@ -292,8 +299,9 @@ add_subdirectory(nano/crypto_lib)
|
|||
add_subdirectory(nano/secure)
|
||||
add_subdirectory(nano/lib)
|
||||
add_subdirectory(nano/node)
|
||||
add_subdirectory(nano/rpc)
|
||||
add_subdirectory(nano/nano_node)
|
||||
add_subdirectory(nano/rpc)
|
||||
add_subdirectory(nano/nano_rpc)
|
||||
|
||||
if (NANO_TEST OR RAIBLOCKS_TEST)
|
||||
if(WIN32)
|
||||
|
@ -369,9 +377,14 @@ if (NANO_GUI OR RAIBLOCKS_GUI)
|
|||
${RES})
|
||||
|
||||
target_link_libraries (nano_wallet
|
||||
rpc
|
||||
node
|
||||
qt)
|
||||
|
||||
target_compile_definitions(nano_wallet
|
||||
PRIVATE
|
||||
-DBOOST_PROCESS_SUPPORTED=${BOOST_PROCESS_SUPPORTED})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries (nano_wallet Qt5::WinExtras)
|
||||
# nano_wallet.com executable for Windows console
|
||||
|
|
|
@ -71,7 +71,7 @@ run_tests() {
|
|||
xvfb_run_ ./qt_test
|
||||
qt_test_res=${?}
|
||||
|
||||
${TIMEOUT_CMD} ${TIMEOUT_TIME_ARG} ${TIMEOUT_SEC-${TIMEOUT_DEFAULT}} ./load_test ./nano_node -s 150
|
||||
${TIMEOUT_CMD} ${TIMEOUT_TIME_ARG} ${TIMEOUT_SEC-${TIMEOUT_DEFAULT}} ./load_test ./nano_node ./nano_rpc -s 150
|
||||
load_test_res=${?}
|
||||
|
||||
echo "Core Test return code: ${core_test_res}"
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
use std::io;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use serde_json;
|
||||
|
||||
use futures::Future;
|
||||
use hyper::client::Connect;
|
||||
|
||||
use tokio_core::reactor::Handle;
|
||||
use tokio_process::{Child, CommandExt};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use errors::*;
|
||||
|
||||
use rpc::RpcClient;
|
||||
|
||||
const RPC_PORT_START: u64 = 55000;
|
||||
const PEERING_PORT_START: u64 = 54000;
|
||||
|
||||
pub fn launch_node(
|
||||
nano_node: &Path,
|
||||
tmp_dir: &Path,
|
||||
handle: Handle,
|
||||
i: u64,
|
||||
) -> Result<(Child, RpcClient)> {
|
||||
let data_dir = tmp_dir.join(format!("Nano_load_test_{}", i));
|
||||
match fs::create_dir(&data_dir) {
|
||||
Ok(_) => {}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
let _ = fs::remove_file(data_dir.join("data.ldb"));
|
||||
}
|
||||
r => r.chain_err(|| "failed to create nano_node data directory")?,
|
||||
}
|
||||
let rpc_port = RPC_PORT_START + i;
|
||||
let peering_port = PEERING_PORT_START + i;
|
||||
let config = json!({
|
||||
"version": "2",
|
||||
"rpc_enable": "true",
|
||||
"rpc": {
|
||||
"address": "::1",
|
||||
"port": rpc_port.to_string(),
|
||||
"enable_control": "true",
|
||||
"frontier_request_limit": "16384",
|
||||
"chain_request_limit": "16384",
|
||||
},
|
||||
"node": {
|
||||
"version": "8",
|
||||
"peering_port": peering_port.to_string(),
|
||||
"bootstrap_fraction_numerator": "1",
|
||||
"receive_minimum": "1000000000000000000000000",
|
||||
"logging": {
|
||||
"version": "2",
|
||||
"ledger": "false",
|
||||
"ledger_duplicate": "false",
|
||||
"vote": "false",
|
||||
"network": "true",
|
||||
"network_message": "false",
|
||||
"network_publish": "false",
|
||||
"network_packet": "false",
|
||||
"network_keepalive": "false",
|
||||
"node_lifetime_tracing": "false",
|
||||
"insufficient_work": "true",
|
||||
"log_rpc": "true",
|
||||
"bulk_pull": "false",
|
||||
"work_generation_time": "true",
|
||||
"log_to_cerr": "false",
|
||||
"max_size": "16777216",
|
||||
},
|
||||
"work_peers": "",
|
||||
"preconfigured_peers": "",
|
||||
"preconfigured_representatives": [
|
||||
"xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo"
|
||||
],
|
||||
"inactive_supply": "0",
|
||||
"password_fanout": "1024",
|
||||
"io_threads": "8",
|
||||
"work_threads": "8",
|
||||
"enable_voting": "true",
|
||||
"bootstrap_connections": "4",
|
||||
"callback_address": "",
|
||||
"callback_port": "0",
|
||||
"callback_target": "",
|
||||
"lmdb_max_dbs": "128",
|
||||
},
|
||||
"opencl_enable": "false",
|
||||
"opencl": {
|
||||
"platform": "0",
|
||||
"device": "0",
|
||||
"threads": "1048576",
|
||||
}
|
||||
});
|
||||
let config_writer =
|
||||
File::create(data_dir.join("config.json")).chain_err(|| "failed to create config.json")?;
|
||||
serde_json::to_writer_pretty(config_writer, &config)
|
||||
.chain_err(|| "failed to write config.json")?;
|
||||
let child = Command::new(nano_node)
|
||||
.arg("--data_path")
|
||||
.arg(&data_dir)
|
||||
.arg("--daemon")
|
||||
.spawn_async(&handle)
|
||||
.chain_err(|| "failed to spawn nano_node")?;
|
||||
let rpc_client = RpcClient::new(
|
||||
handle,
|
||||
format!("http://[::1]:{}/", rpc_port).parse().unwrap(),
|
||||
);
|
||||
Ok((child, rpc_client))
|
||||
}
|
||||
|
||||
pub fn connect_node<C: Connect>(
|
||||
node: &RpcClient<C>,
|
||||
i: u64,
|
||||
) -> Box<Future<Item = (), Error = Error>> {
|
||||
Box::new(
|
||||
node.call::<_, Value>(&json!({
|
||||
"action": "keepalive",
|
||||
"address": "::1",
|
||||
"port": PEERING_PORT_START + i,
|
||||
})).then(|x| x.chain_err(|| "failed to call nano_node RPC"))
|
||||
.map(|_| ()),
|
||||
) as _
|
||||
}
|
181
load-tester/src/launch_node_and_rpc.rs
Normal file
181
load-tester/src/launch_node_and_rpc.rs
Normal file
|
@ -0,0 +1,181 @@
|
|||
use std::io;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
use serde_json;
|
||||
|
||||
use futures::Future;
|
||||
use hyper::client::Connect;
|
||||
|
||||
use tokio_core::reactor::Handle;
|
||||
use tokio_process::{Child, CommandExt};
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use errors::*;
|
||||
|
||||
use rpc::RpcClient;
|
||||
|
||||
const RPC_PORT_START: u64 = 55000;
|
||||
const PEERING_PORT_START: u64 = 54000;
|
||||
const IPC_PORT_START: u64 = 56000;
|
||||
|
||||
pub fn launch_node_and_rpc(
|
||||
nano_node: &Path,
|
||||
nano_rpc: &Path,
|
||||
tmp_dir: &Path,
|
||||
handle: Handle,
|
||||
i: u64,
|
||||
) -> Result<(Child, Child, RpcClient)> {
|
||||
let data_dir = tmp_dir.join(format!("Nano_load_test_{}", i));
|
||||
match fs::create_dir(&data_dir) {
|
||||
Ok(_) => {}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
let _ = fs::remove_file(data_dir.join("data.ldb"));
|
||||
let _ = fs::remove_file(data_dir.join("wallets.ldb"));
|
||||
}
|
||||
r => r.chain_err(|| "failed to create nano_node data directory")?,
|
||||
}
|
||||
let peering_port = PEERING_PORT_START + i;
|
||||
let ipc_port = IPC_PORT_START + i;
|
||||
|
||||
let config = json!({
|
||||
"version": "2",
|
||||
"rpc_enable": "false",
|
||||
"rpc": {
|
||||
"version": "1",
|
||||
"enable_sign_hash": "false",
|
||||
"max_work_generate_difficulty": "ffffffffc0000000",
|
||||
"rpc_in_process": "false"
|
||||
},
|
||||
"node": {
|
||||
"version": "17",
|
||||
"peering_port": peering_port.to_string(),
|
||||
"bootstrap_fraction_numerator": "1",
|
||||
"receive_minimum": "1000000000000000000000000",
|
||||
"logging": {
|
||||
"version": "7",
|
||||
"ledger": "false",
|
||||
"ledger_duplicate": "false",
|
||||
"vote": "false",
|
||||
"network": "true",
|
||||
"network_message": "false",
|
||||
"network_publish": "false",
|
||||
"network_packet": "false",
|
||||
"network_keepalive": "false",
|
||||
"network_node_id_handshake": "false",
|
||||
"node_lifetime_tracing": "false",
|
||||
"insufficient_work": "true",
|
||||
"log_ipc": "true",
|
||||
"bulk_pull": "false",
|
||||
"work_generation_time": "true",
|
||||
"upnp_details": "false",
|
||||
"timing": "false",
|
||||
"log_to_cerr": "false",
|
||||
"max_size": "134217728",
|
||||
"rotation_size": "4194304",
|
||||
"flush": "true",
|
||||
"min_time_between_output": "5"
|
||||
},
|
||||
"work_peers": "",
|
||||
"preconfigured_peers": "",
|
||||
"preconfigured_representatives": [
|
||||
"xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo"
|
||||
],
|
||||
"online_weight_minimum": "60000000000000000000000000000000000000",
|
||||
"online_weight_quorum": "50",
|
||||
"password_fanout": "1024",
|
||||
"io_threads": "8",
|
||||
"network_threads": "8",
|
||||
"work_threads": "8",
|
||||
"signature_checker_threads": "7",
|
||||
"enable_voting": "true",
|
||||
"bootstrap_connections": "4",
|
||||
"bootstrap_connections_max": "64",
|
||||
"callback_address": "",
|
||||
"callback_port": "0",
|
||||
"callback_target": "",
|
||||
"lmdb_max_dbs": "128",
|
||||
"block_processor_batch_max_time": "5000",
|
||||
"allow_local_peers": "true",
|
||||
"vote_minimum": "1000000000000000000000000000000000",
|
||||
"unchecked_cutoff_time": "14400",
|
||||
"ipc": {
|
||||
"tcp": {
|
||||
"enable": "true",
|
||||
"port": ipc_port.to_string (),
|
||||
"io_timeout": "15"
|
||||
},
|
||||
"local": {
|
||||
"enable": "false",
|
||||
"path": "/tmp/nano",
|
||||
"io_timeout": "15"
|
||||
},
|
||||
},
|
||||
"tcp_client_timeout": "5",
|
||||
"tcp_server_timeout": "30"
|
||||
},
|
||||
"opencl_enable": "false",
|
||||
"opencl": {
|
||||
"platform": "0",
|
||||
"device": "0",
|
||||
"threads": "1048576"
|
||||
}
|
||||
});
|
||||
|
||||
let rpc_port = RPC_PORT_START + i;
|
||||
let rpc_config = json!({
|
||||
"address": "::1",
|
||||
"port": rpc_port.to_string(),
|
||||
"enable_control": "true",
|
||||
"max_json_depth": "20",
|
||||
"version": "1",
|
||||
"ipc_port": ipc_port.to_string (),
|
||||
"io_threads": "8",
|
||||
"num_ipc_connections" : "8"
|
||||
});
|
||||
|
||||
let config_writer =
|
||||
File::create(data_dir.join("config.json")).chain_err(|| "failed to create config.json")?;
|
||||
serde_json::to_writer_pretty(config_writer, &config)
|
||||
.chain_err(|| "failed to write config.json")?;
|
||||
let child = Command::new(nano_node)
|
||||
.arg("--data_path")
|
||||
.arg(&data_dir)
|
||||
.arg("--daemon")
|
||||
.spawn_async(&handle)
|
||||
.chain_err(|| "failed to spawn nano_node")?;
|
||||
|
||||
let rpc_config_writer =
|
||||
File::create(data_dir.join("rpc_config.json")).chain_err(|| "failed to create rpc_config.json")?;
|
||||
serde_json::to_writer_pretty(rpc_config_writer, &rpc_config)
|
||||
.chain_err(|| "failed to write rpc_config.json")?;
|
||||
let rpc_child = Command::new(nano_rpc)
|
||||
.arg("--data_path")
|
||||
.arg(&data_dir)
|
||||
.arg("--daemon")
|
||||
.spawn_async(&handle)
|
||||
.chain_err(|| "failed to spawn nano_rpc")?;
|
||||
|
||||
let rpc_client = RpcClient::new(
|
||||
handle,
|
||||
format!("http://[::1]:{}/", rpc_port).parse().unwrap(),
|
||||
);
|
||||
Ok((child, rpc_child, rpc_client))
|
||||
}
|
||||
|
||||
pub fn connect_node<C: Connect>(
|
||||
node: &RpcClient<C>,
|
||||
i: u64,
|
||||
) -> Box<Future<Item = (), Error = Error>> {
|
||||
Box::new(
|
||||
node.call::<_, Value>(&json!({
|
||||
"action": "keepalive",
|
||||
"address": "::1",
|
||||
"port": PEERING_PORT_START + i,
|
||||
})).then(|x| x.chain_err(|| "failed to call nano_rpc"))
|
||||
.map(|_| ()),
|
||||
) as _
|
||||
}
|
|
@ -46,11 +46,12 @@ use errors::*;
|
|||
mod rpc;
|
||||
use rpc::{RpcClient, RpcError};
|
||||
|
||||
mod launch_node;
|
||||
mod launch_node_and_rpc;
|
||||
|
||||
struct Parameters {
|
||||
node_count: u16,
|
||||
node_path: PathBuf,
|
||||
rpc_path: PathBuf,
|
||||
tmp_dir: PathBuf,
|
||||
send_count: usize,
|
||||
dest_count: usize,
|
||||
|
@ -82,15 +83,18 @@ fn run(params: Parameters) -> Result<()> {
|
|||
|
||||
let mut tokio_core = Core::new().chain_err(|| "failed to create tokio Core")?;
|
||||
let mut children = Vec::with_capacity(params.node_count as _);
|
||||
let mut rpc_children = Vec::with_capacity(params.node_count as _);
|
||||
let mut nodes: Vec<RpcClient<_>> = Vec::with_capacity(params.node_count as _);
|
||||
for i in 0..params.node_count {
|
||||
let (child, rpc_client) = launch_node::launch_node(
|
||||
let (child, rpc_child, rpc_client) = launch_node_and_rpc::launch_node_and_rpc(
|
||||
¶ms.node_path,
|
||||
¶ms.rpc_path,
|
||||
¶ms.tmp_dir,
|
||||
tokio_core.handle(),
|
||||
i as _,
|
||||
)?;
|
||||
children.push(child);
|
||||
rpc_children.push(rpc_child);
|
||||
nodes.push(rpc_client);
|
||||
}
|
||||
if nodes.is_empty() {
|
||||
|
@ -103,7 +107,7 @@ fn run(params: Parameters) -> Result<()> {
|
|||
for (a, node) in nodes.iter().enumerate() {
|
||||
for b in 0..nodes.len() {
|
||||
if a != b {
|
||||
tokio_core.run(launch_node::connect_node(node, b as _))?;
|
||||
tokio_core.run(launch_node_and_rpc::connect_node(node, b as _))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +144,7 @@ fn run(params: Parameters) -> Result<()> {
|
|||
"action": "key_create",
|
||||
}))
|
||||
})
|
||||
.buffer_unordered(10) // execute 10 `key_create`s simultaniously
|
||||
.buffer_unordered(10) // execute 10 `key_create`s simultaneously
|
||||
.inspect(|_| {
|
||||
tstat!("key_create,progress");
|
||||
})
|
||||
|
@ -460,6 +464,12 @@ fn main() {
|
|||
.required(true)
|
||||
.help("The path to the nano_node to test"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("rpc_path")
|
||||
.value_name("PATH")
|
||||
.required(true)
|
||||
.help("The path to the nano_rpc to test"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("send_count")
|
||||
.short("s")
|
||||
|
@ -520,6 +530,7 @@ fn main() {
|
|||
let params = Parameters {
|
||||
node_count: num_arg!("node_count"),
|
||||
node_path: matches.value_of("node_path").unwrap().into(),
|
||||
rpc_path: matches.value_of("rpc_path").unwrap().into(),
|
||||
tmp_dir: matches
|
||||
.value_of("tmp_dir")
|
||||
.or(env::var("TMPDIR").ok().as_ref().map(|x| x.as_str()))
|
||||
|
|
|
@ -3,11 +3,11 @@ add_executable (core_test
|
|||
testutil.hpp
|
||||
block.cpp
|
||||
block_store.cpp
|
||||
interface.cpp
|
||||
ipc.cpp
|
||||
conflicts.cpp
|
||||
entry.cpp
|
||||
gap_cache.cpp
|
||||
interface.cpp
|
||||
ipc.cpp
|
||||
ledger.cpp
|
||||
logger.cpp
|
||||
network.cpp
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include <nano/secure/utility.hpp>
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
void force_nano_test_network ();
|
||||
}
|
||||
GTEST_API_ int main (int argc, char ** argv)
|
||||
|
@ -10,6 +10,6 @@ GTEST_API_ int main (int argc, char ** argv)
|
|||
nano::force_nano_test_network ();
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanp_test_directories_on_exit ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
TEST (daemon, fork)
|
||||
{
|
||||
}
|
|
@ -15,10 +15,9 @@ using namespace std::chrono_literals;
|
|||
TEST (ipc, asynchronous)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
|
||||
system.nodes[0]->config.ipc_config.transport_tcp.enabled = true;
|
||||
system.nodes[0]->config.ipc_config.transport_tcp.port = 24077;
|
||||
nano::ipc::ipc_server ipc (*system.nodes[0], rpc);
|
||||
nano::ipc::ipc_server ipc (*system.nodes[0]);
|
||||
nano::ipc::ipc_client client (system.nodes[0]->io_ctx);
|
||||
|
||||
auto req (nano::ipc::prepare_request (nano::ipc::payload_encoding::json_legacy, std::string (R"({"action": "block_count"})")));
|
||||
|
@ -58,10 +57,9 @@ TEST (ipc, asynchronous)
|
|||
TEST (ipc, synchronous)
|
||||
{
|
||||
nano::system system (24000, 1);
|
||||
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
|
||||
system.nodes[0]->config.ipc_config.transport_tcp.enabled = true;
|
||||
system.nodes[0]->config.ipc_config.transport_tcp.port = 24077;
|
||||
nano::ipc::ipc_server ipc (*system.nodes[0], rpc);
|
||||
nano::ipc::ipc_server ipc (*system.nodes[0]);
|
||||
nano::ipc::ipc_client client (system.nodes[0]->io_ctx);
|
||||
|
||||
// Start blocking IPC client in a separate thread
|
||||
|
|
|
@ -22,7 +22,6 @@ TEST (logging, serialization)
|
|||
logging1.network_node_id_handshake_logging_value = !logging1.network_node_id_handshake_logging_value;
|
||||
logging1.node_lifetime_tracing_value = !logging1.node_lifetime_tracing_value;
|
||||
logging1.insufficient_work_logging_value = !logging1.insufficient_work_logging_value;
|
||||
logging1.log_rpc_value = !logging1.log_rpc_value;
|
||||
logging1.bulk_pull_logging_value = !logging1.bulk_pull_logging_value;
|
||||
logging1.work_generation_time_value = !logging1.work_generation_time_value;
|
||||
logging1.log_to_cerr_value = !logging1.log_to_cerr_value;
|
||||
|
@ -45,7 +44,6 @@ TEST (logging, serialization)
|
|||
ASSERT_EQ (logging1.network_node_id_handshake_logging_value, logging2.network_node_id_handshake_logging_value);
|
||||
ASSERT_EQ (logging1.node_lifetime_tracing_value, logging2.node_lifetime_tracing_value);
|
||||
ASSERT_EQ (logging1.insufficient_work_logging_value, logging2.insufficient_work_logging_value);
|
||||
ASSERT_EQ (logging1.log_rpc_value, logging2.log_rpc_value);
|
||||
ASSERT_EQ (logging1.bulk_pull_logging_value, logging2.bulk_pull_logging_value);
|
||||
ASSERT_EQ (logging1.work_generation_time_value, logging2.work_generation_time_value);
|
||||
ASSERT_EQ (logging1.log_to_cerr_value, logging2.log_to_cerr_value);
|
||||
|
|
|
@ -27,8 +27,10 @@ add_library (nano_lib
|
|||
ipc.cpp
|
||||
ipc_client.hpp
|
||||
ipc_client.cpp
|
||||
json_error_response.hpp
|
||||
jsonconfig.hpp
|
||||
logger_mt.hpp
|
||||
rpc_handler_interface.hpp
|
||||
rpcconfig.hpp
|
||||
rpcconfig.cpp
|
||||
numbers.hpp
|
||||
|
|
|
@ -132,6 +132,11 @@ inline boost::filesystem::path get_config_path (boost::filesystem::path const &
|
|||
return data_path / "config.json";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path get_rpc_config_path (boost::filesystem::path const & data_path)
|
||||
{
|
||||
return data_path / "rpc_config.json";
|
||||
}
|
||||
|
||||
/** Called by gtest_main to enforce test network */
|
||||
void force_nano_test_network ();
|
||||
}
|
||||
|
|
16
nano/lib/json_error_response.hpp
Normal file
16
nano/lib/json_error_response.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
inline void json_error_response (std::function<void(std::string const &)> response_a, std::string const & message_a)
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("error", message_a);
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, response_l);
|
||||
response_a (ostream.str ());
|
||||
}
|
||||
}
|
15
nano/lib/rpc_handler_interface.hpp
Normal file
15
nano/lib/rpc_handler_interface.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class rpc;
|
||||
|
||||
class rpc_handler_interface
|
||||
{
|
||||
public:
|
||||
virtual ~rpc_handler_interface () = default;
|
||||
virtual void process_request (std::string const & action, std::string const & body, std::function<void(std::string const &)> response) = 0;
|
||||
virtual void stop () = 0;
|
||||
virtual void rpc_instance (nano::rpc & rpc) = 0;
|
||||
};
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
#include <boost/dll/runtime_symbol_info.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
|
@ -31,9 +32,11 @@ address (boost::asio::ip::address_v6::loopback ()),
|
|||
port (network_constants.default_rpc_port),
|
||||
enable_control (enable_control_a),
|
||||
max_json_depth (20),
|
||||
enable_sign_hash (false),
|
||||
max_request_size (32 * 1024 * 1024),
|
||||
max_work_generate_difficulty (0xffffffffc0000000)
|
||||
io_threads (std::max<unsigned> (4, boost::thread::hardware_concurrency ())),
|
||||
ipc_port (network_constants.default_ipc_port),
|
||||
ipc_path ("/tmp/nano"),
|
||||
num_ipc_connections (network_constants.is_live_network () ? 8 : 1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,44 +47,79 @@ nano::error nano::rpc_config::serialize_json (nano::jsonconfig & json) const
|
|||
json.put ("port", port);
|
||||
json.put ("enable_control", enable_control);
|
||||
json.put ("max_json_depth", max_json_depth);
|
||||
json.put ("enable_sign_hash", enable_sign_hash);
|
||||
json.put ("max_request_size", max_request_size);
|
||||
json.put ("max_work_generate_difficulty", nano::to_string_hex (max_work_generate_difficulty));
|
||||
json.put ("io_threads", io_threads);
|
||||
json.put ("ipc_port", ipc_port);
|
||||
json.put ("num_ipc_connections", num_ipc_connections);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::error nano::rpc_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json)
|
||||
{
|
||||
auto version_l (json.get_optional<unsigned> ("version"));
|
||||
if (!version_l)
|
||||
if (!json.empty ())
|
||||
{
|
||||
version_l = 1;
|
||||
json.put ("version", *version_l);
|
||||
json.put ("max_request_size", max_request_size);
|
||||
json.put ("max_work_generate_difficulty", nano::to_string_hex (max_work_generate_difficulty));
|
||||
json.erase ("frontier_request_limit");
|
||||
json.erase ("chain_request_limit");
|
||||
auto version_l (json.get_optional<unsigned> ("version"));
|
||||
if (!version_l)
|
||||
{
|
||||
version_l = 1;
|
||||
json.put ("version", *version_l);
|
||||
json.put ("max_request_size", max_request_size);
|
||||
json.erase ("frontier_request_limit");
|
||||
json.erase ("chain_request_limit");
|
||||
json.put ("io_threads", io_threads);
|
||||
json.put ("ipc_port", ipc_port);
|
||||
json.put ("num_ipc_connections", num_ipc_connections);
|
||||
upgraded_a = true;
|
||||
}
|
||||
|
||||
auto rpc_secure_l (json.get_optional_child ("secure"));
|
||||
if (rpc_secure_l)
|
||||
{
|
||||
secure.deserialize_json (*rpc_secure_l);
|
||||
}
|
||||
|
||||
json.get_required<boost::asio::ip::address_v6> ("address", address);
|
||||
json.get_optional<uint16_t> ("port", port);
|
||||
json.get_optional<bool> ("enable_control", enable_control);
|
||||
json.get_optional<uint8_t> ("max_json_depth", max_json_depth);
|
||||
json.get_optional<uint64_t> ("max_request_size", max_request_size);
|
||||
json.get_optional<unsigned> ("io_threads", io_threads);
|
||||
json.get_optional<uint16_t> ("ipc_port", ipc_port);
|
||||
json.get_optional<unsigned> ("num_ipc_connections", num_ipc_connections);
|
||||
}
|
||||
else
|
||||
{
|
||||
upgraded_a = true;
|
||||
serialize_json (json);
|
||||
}
|
||||
|
||||
auto rpc_secure_l (json.get_optional_child ("secure"));
|
||||
if (rpc_secure_l)
|
||||
{
|
||||
secure.deserialize_json (*rpc_secure_l);
|
||||
}
|
||||
|
||||
json.get_required<boost::asio::ip::address_v6> ("address", address);
|
||||
json.get_optional<uint16_t> ("port", port);
|
||||
json.get_optional<bool> ("enable_control", enable_control);
|
||||
json.get_optional<uint8_t> ("max_json_depth", max_json_depth);
|
||||
json.get_optional<bool> ("enable_sign_hash", enable_sign_hash);
|
||||
json.get_optional<uint64_t> ("max_request_size", max_request_size);
|
||||
std::string max_work_generate_difficulty_text;
|
||||
json.get_optional<std::string> ("max_work_generate_difficulty", max_work_generate_difficulty_text);
|
||||
if (!max_work_generate_difficulty_text.empty ())
|
||||
{
|
||||
nano::from_string_hex (max_work_generate_difficulty_text, max_work_generate_difficulty);
|
||||
}
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
nano::error read_and_update_rpc_config (boost::filesystem::path const & data_path, nano::rpc_config & config_a)
|
||||
{
|
||||
boost::system::error_code error_chmod;
|
||||
nano::jsonconfig json;
|
||||
auto config_path = nano::get_rpc_config_path (data_path);
|
||||
auto error (json.read_and_update (config_a, config_path));
|
||||
nano::set_secure_perm_file (config_path, error_chmod);
|
||||
return error;
|
||||
}
|
||||
|
||||
std::string get_default_rpc_filepath ()
|
||||
{
|
||||
boost::system::error_code err;
|
||||
auto running_executable_filepath = boost::dll::program_location (err);
|
||||
|
||||
// Construct the nano_rpc excutable file path based on where the currently running executable is found.
|
||||
auto rpc_filepath = running_executable_filepath.parent_path () / "nano_rpc";
|
||||
if (running_executable_filepath.has_extension ())
|
||||
{
|
||||
rpc_filepath.replace_extension (running_executable_filepath.extension ());
|
||||
}
|
||||
|
||||
return rpc_filepath.string ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace nano
|
||||
|
@ -44,12 +45,18 @@ public:
|
|||
bool enable_control;
|
||||
rpc_secure_config secure;
|
||||
uint8_t max_json_depth;
|
||||
bool enable_sign_hash;
|
||||
uint64_t max_request_size;
|
||||
uint64_t max_work_generate_difficulty;
|
||||
unsigned io_threads;
|
||||
uint16_t ipc_port;
|
||||
std::string ipc_path;
|
||||
unsigned num_ipc_connections;
|
||||
static int json_version ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
nano::error read_and_update_rpc_config (boost::filesystem::path const & data_path, nano::rpc_config & config_a);
|
||||
|
||||
std::string get_default_rpc_filepath ();
|
||||
}
|
||||
|
|
|
@ -96,6 +96,12 @@ namespace thread_role
|
|||
case nano::thread_role::name::signature_checking:
|
||||
thread_role_name_string = "Signature check";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_request_processor:
|
||||
thread_role_name_string = "RPC processor";
|
||||
break;
|
||||
case nano::thread_role::name::rpc_process_container:
|
||||
thread_role_name_string = "RPC process";
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -85,7 +85,9 @@ namespace thread_role
|
|||
wallet_actions,
|
||||
bootstrap_initiator,
|
||||
voting,
|
||||
signature_checking
|
||||
signature_checking,
|
||||
rpc_request_processor,
|
||||
rpc_process_container
|
||||
};
|
||||
/*
|
||||
* Get/Set the identifier for the current thread
|
||||
|
|
|
@ -5,6 +5,7 @@ add_executable (nano_node
|
|||
|
||||
target_link_libraries (nano_node
|
||||
node
|
||||
rpc
|
||||
secure
|
||||
argon2
|
||||
Boost::boost
|
||||
|
@ -15,7 +16,8 @@ target_compile_definitions(nano_node
|
|||
PRIVATE
|
||||
-DNANO_VERSION_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
-DNANO_VERSION_MINOR=${CPACK_PACKAGE_VERSION_MINOR}
|
||||
-DNANO_VERSION_PATCH=${CPACK_PACKAGE_VERSION_PATCH})
|
||||
-DNANO_VERSION_PATCH=${CPACK_PACKAGE_VERSION_PATCH}
|
||||
-DBOOST_PROCESS_SUPPORTED=${BOOST_PROCESS_SUPPORTED})
|
||||
|
||||
set_target_properties (nano_node
|
||||
PROPERTIES
|
||||
|
|
|
@ -5,7 +5,19 @@
|
|||
#include <nano/nano_node/daemon.hpp>
|
||||
#include <nano/node/daemonconfig.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/json_handler.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/openclwork.hpp>
|
||||
#include <nano/node/working.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
|
||||
#ifndef BOOST_PROCESS_SUPPORTED
|
||||
#error BOOST_PROCESS_SUPPORTED must be set, check configuration
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
#include <boost/process.hpp>
|
||||
#endif
|
||||
|
||||
void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::node_flags const & flags)
|
||||
{
|
||||
|
@ -13,7 +25,7 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
|
|||
boost::system::error_code error_chmod;
|
||||
nano::set_secure_perm_directory (data_path, error_chmod);
|
||||
std::unique_ptr<nano::thread_runner> runner;
|
||||
nano::daemon_config config;
|
||||
nano::daemon_config config (data_path);
|
||||
auto error = nano::read_and_update_daemon_config (data_path, config);
|
||||
|
||||
if (!error)
|
||||
|
@ -33,14 +45,57 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
|
|||
if (!init.error ())
|
||||
{
|
||||
node->start ();
|
||||
std::unique_ptr<nano::rpc> rpc = get_rpc (io_ctx, *node, config.rpc);
|
||||
if (rpc)
|
||||
nano::ipc::ipc_server ipc_server (*node, config.rpc);
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
std::unique_ptr<boost::process::child> rpc_process;
|
||||
#endif
|
||||
std::unique_ptr<std::thread> rpc_process_thread;
|
||||
std::unique_ptr<nano::rpc> rpc;
|
||||
std::unique_ptr<nano::rpc_handler_interface> rpc_handler;
|
||||
if (config.rpc_enable)
|
||||
{
|
||||
rpc->start (config.rpc_enable);
|
||||
if (config.rpc.rpc_in_process)
|
||||
{
|
||||
nano::rpc_config rpc_config;
|
||||
auto error = nano::read_and_update_rpc_config (data_path, rpc_config);
|
||||
if (error)
|
||||
{
|
||||
throw std::runtime_error ("Could not deserialize rpc_config file");
|
||||
}
|
||||
rpc_handler = std::make_unique<nano::inprocess_rpc_handler> (*node, config.rpc, [&ipc_server]() {
|
||||
ipc_server.stop ();
|
||||
});
|
||||
rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler);
|
||||
rpc->start ();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
rpc_process = std::make_unique<boost::process::child> (config.rpc.rpc_path, "--daemon");
|
||||
#else
|
||||
auto rpc_exe_command = boost::str (boost::format ("%1% %2%") % config.rpc.rpc_path % "--daemon");
|
||||
rpc_process_thread = std::make_unique<std::thread> ([ rpc_exe_command, &logger = node->logger ]() {
|
||||
nano::thread_role::set (nano::thread_role::name::rpc_process_container);
|
||||
std::system (rpc_exe_command.c_str ());
|
||||
logger.always_log ("RPC server has stopped");
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
nano::ipc::ipc_server ipc (*node, *rpc);
|
||||
|
||||
runner = std::make_unique<nano::thread_runner> (io_ctx, node->config.io_threads);
|
||||
runner->join ();
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
if (rpc_process)
|
||||
{
|
||||
rpc_process->wait ();
|
||||
}
|
||||
#else
|
||||
if (rpc_process_thread)
|
||||
{
|
||||
rpc_process_thread->join ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_node/daemon.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/json_handler.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/payment_observer_processor.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#include <argon2.h>
|
||||
|
@ -95,9 +96,9 @@ int main (int argc, char * const * argv)
|
|||
("debug_profile_process", "Profile active blocks processing (only for nano_test_network)")
|
||||
("debug_profile_votes", "Profile votes processing (only for nano_test_network)")
|
||||
("debug_random_feed", "Generates output to RNG test suites")
|
||||
("debug_rpc", "Read an RPC command from stdin and invoke it. Network operations will have no effect.")
|
||||
("debug_validate_blocks", "Check all blocks for correct hash, signature, work value")
|
||||
("debug_peers", "Display peer IPv6:port connections")
|
||||
("debug_ipc", "Read an IPC command in JSON from stdin and invoke it. Network operations will have no effect")
|
||||
("platform", boost::program_options::value<std::string> (), "Defines the <platform> for OpenCL commands")
|
||||
("device", boost::program_options::value<std::string> (), "Defines <device> for OpenCL command")
|
||||
("threads", boost::program_options::value<std::string> (), "Defines <threads> count for OpenCL command")
|
||||
|
@ -725,18 +726,16 @@ int main (int argc, char * const * argv)
|
|||
command_l << rpc_input_l;
|
||||
}
|
||||
|
||||
auto response_handler_l ([](boost::property_tree::ptree const & tree_a) {
|
||||
boost::property_tree::write_json (std::cout, tree_a);
|
||||
auto response_handler_l ([](std::string const & response_a) {
|
||||
std::cout << response_a;
|
||||
// Terminate as soon as we have the result, even if background threads (like work generation) are running.
|
||||
std::exit (0);
|
||||
});
|
||||
|
||||
nano::inactive_node inactive_node_l (data_path);
|
||||
nano::rpc_config rpc_config_l;
|
||||
rpc_config_l.enable_control = true;
|
||||
std::unique_ptr<nano::rpc> rpc_l = get_rpc (inactive_node_l.node->io_ctx, *inactive_node_l.node, rpc_config_l);
|
||||
std::string req_id_l ("1");
|
||||
nano::rpc_handler handler_l (*inactive_node_l.node, *rpc_l, command_l.str (), req_id_l, response_handler_l);
|
||||
nano::node_rpc_config config;
|
||||
nano::ipc::ipc_server server (*inactive_node_l.node, config);
|
||||
nano::json_handler handler_l (*inactive_node_l.node, config, command_l.str (), response_handler_l);
|
||||
handler_l.process_request ();
|
||||
}
|
||||
else if (vm.count ("debug_validate_blocks"))
|
||||
|
|
21
nano/nano_rpc/CMakeLists.txt
Normal file
21
nano/nano_rpc/CMakeLists.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
add_executable (nano_rpc
|
||||
entry.cpp)
|
||||
|
||||
target_link_libraries (nano_rpc
|
||||
rpc
|
||||
secure
|
||||
Boost::filesystem
|
||||
Boost::log
|
||||
Boost::log_setup
|
||||
Boost::program_options
|
||||
Boost::system
|
||||
Boost::thread
|
||||
Boost::boost)
|
||||
|
||||
target_compile_definitions(nano_rpc
|
||||
PUBLIC
|
||||
-DACTIVE_NETWORK=${ACTIVE_NETWORK}
|
||||
PRIVATE
|
||||
-DNANO_VERSION_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
-DNANO_VERSION_MINOR=${CPACK_PACKAGE_VERSION_MINOR}
|
||||
-DNANO_VERSION_PATCH=${CPACK_PACKAGE_VERSION_PATCH})
|
139
nano/nano_rpc/entry.cpp
Normal file
139
nano/nano_rpc/entry.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/log/utility/setup/common_attributes.hpp>
|
||||
#include <boost/log/utility/setup/file.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_wallet/icon.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/working.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/rpc/rpc_request_processor.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
void logging_init (boost::filesystem::path const & application_path_a)
|
||||
{
|
||||
static std::atomic_flag logging_already_added = ATOMIC_FLAG_INIT;
|
||||
if (!logging_already_added.test_and_set ())
|
||||
{
|
||||
boost::log::add_common_attributes ();
|
||||
auto path = application_path_a / "log";
|
||||
|
||||
uintmax_t max_size{ 128 * 1024 * 1024 };
|
||||
uintmax_t rotation_size{ 4 * 1024 * 1024 };
|
||||
bool flush{ true };
|
||||
boost::log::add_file_log (boost::log::keywords::target = path, boost::log::keywords::file_name = path / "rpc_log_%Y-%m-%d_%H-%M-%S.%N.log", boost::log::keywords::rotation_size = rotation_size, boost::log::keywords::auto_flush = flush, boost::log::keywords::scan_method = boost::log::sinks::file::scan_method::scan_matching, boost::log::keywords::max_size = max_size, boost::log::keywords::format = "[%TimeStamp%]: %Message%");
|
||||
}
|
||||
}
|
||||
|
||||
void run (boost::filesystem::path const & data_path)
|
||||
{
|
||||
boost::filesystem::create_directories (data_path);
|
||||
boost::system::error_code error_chmod;
|
||||
nano::set_secure_perm_directory (data_path, error_chmod);
|
||||
std::unique_ptr<nano::thread_runner> runner;
|
||||
|
||||
nano::rpc_config rpc_config;
|
||||
auto error = nano::read_and_update_rpc_config (data_path, rpc_config);
|
||||
if (!error)
|
||||
{
|
||||
logging_init (data_path);
|
||||
boost::asio::io_context io_ctx;
|
||||
try
|
||||
{
|
||||
nano::ipc_rpc_processor ipc_rpc_processor (io_ctx, rpc_config);
|
||||
auto rpc = nano::get_rpc (io_ctx, rpc_config, ipc_rpc_processor);
|
||||
rpc->start ();
|
||||
runner = std::make_unique<nano::thread_runner> (io_ctx, rpc_config.io_threads);
|
||||
runner->join ();
|
||||
}
|
||||
catch (const std::runtime_error & e)
|
||||
{
|
||||
std::cerr << "Error while running rpc (" << e.what () << ")\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error deserializing config: " << error.get_message () << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char * const * argv)
|
||||
{
|
||||
nano::set_umask ();
|
||||
|
||||
boost::program_options::options_description description ("Command line options");
|
||||
|
||||
// clang-format off
|
||||
description.add_options ()
|
||||
("help", "Print out options")
|
||||
("version", "Prints out version")
|
||||
("daemon", "Start RPC daemon")
|
||||
("data_path", boost::program_options::value<std::string> (), "Use the supplied path as the data directory");
|
||||
// clang-format on
|
||||
|
||||
boost::program_options::variables_map vm;
|
||||
try
|
||||
{
|
||||
boost::program_options::store (boost::program_options::parse_command_line (argc, argv, description), vm);
|
||||
}
|
||||
catch (boost::program_options::error const & err)
|
||||
{
|
||||
std::cerr << err.what () << std::endl;
|
||||
return 1;
|
||||
}
|
||||
boost::program_options::notify (vm);
|
||||
int result (0);
|
||||
|
||||
auto network (vm.find ("network"));
|
||||
if (network != vm.end ())
|
||||
{
|
||||
auto err (nano::network_constants::set_active_network (network->second.as<std::string> ()));
|
||||
if (err)
|
||||
{
|
||||
std::cerr << err.get_message () << std::endl;
|
||||
std::exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
auto data_path_it = vm.find ("data_path");
|
||||
if (data_path_it == vm.end ())
|
||||
{
|
||||
std::string error_string;
|
||||
if (!nano::migrate_working_path (error_string))
|
||||
{
|
||||
std::cerr << error_string << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::path data_path ((data_path_it != vm.end ()) ? data_path_it->second.as<std::string> () : nano::working_path ());
|
||||
if (vm.count ("daemon") > 0)
|
||||
{
|
||||
run (data_path);
|
||||
}
|
||||
else if (vm.count ("version"))
|
||||
{
|
||||
if (NANO_VERSION_PATCH == 0)
|
||||
{
|
||||
std::cout << "Version " << NANO_MAJOR_MINOR_VERSION << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Version " << NANO_MAJOR_MINOR_RC_VERSION << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << description << std::endl;
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_wallet/icon.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/json_handler.hpp>
|
||||
#include <nano/node/node_rpc_config.hpp>
|
||||
#include <nano/node/working.hpp>
|
||||
#include <nano/qt/qt.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
|
@ -14,13 +17,18 @@
|
|||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#ifndef BOOST_PROCESS_SUPPORTED
|
||||
#error BOOST_PROCESS_SUPPORTED must be set, check configuration
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
#include <boost/process.hpp>
|
||||
#endif
|
||||
|
||||
class qt_wallet_config
|
||||
{
|
||||
public:
|
||||
qt_wallet_config (boost::filesystem::path const & application_path_a) :
|
||||
account (0),
|
||||
rpc_enable (false),
|
||||
opencl_enable (false)
|
||||
qt_wallet_config (boost::filesystem::path const & data_path_a)
|
||||
{
|
||||
nano::random_pool::generate_block (wallet.bytes.data (), wallet.bytes.size ());
|
||||
assert (!wallet.is_zero ());
|
||||
|
@ -84,12 +92,13 @@ public:
|
|||
json.put ("version", version_l.get ());
|
||||
upgraded_a = true;
|
||||
}
|
||||
|
||||
upgraded_a |= upgrade_json (version_l.get (), json);
|
||||
auto wallet_l (json.get<std::string> ("wallet"));
|
||||
auto account_l (json.get<std::string> ("account"));
|
||||
auto node_l (json.get_required_child ("node"));
|
||||
rpc_enable = json.get<bool> ("rpc_enable");
|
||||
auto rpc_l (json.get_required_child ("rpc"));
|
||||
rpc_enable = json.get<bool> ("rpc_enable");
|
||||
opencl_enable = json.get<bool> ("opencl_enable");
|
||||
auto opencl_l (json.get_required_child ("opencl"));
|
||||
|
||||
|
@ -107,7 +116,7 @@ public:
|
|||
}
|
||||
if (!rpc_l.get_error ())
|
||||
{
|
||||
rpc.deserialize_json (upgraded_a, rpc_l);
|
||||
rpc.deserialize_json (upgraded_a, rpc_l, data_path);
|
||||
}
|
||||
if (!opencl_l.get_error ())
|
||||
{
|
||||
|
@ -139,10 +148,10 @@ public:
|
|||
node.bootstrap_connections_max = 4;
|
||||
node.serialize_json (node_l);
|
||||
json.put_child ("node", node_l);
|
||||
json.put ("rpc_enable", rpc_enable);
|
||||
nano::jsonconfig rpc_l;
|
||||
rpc.serialize_json (rpc_l);
|
||||
json.put_child ("rpc", rpc_l);
|
||||
json.put ("rpc_enable", rpc_enable);
|
||||
json.put ("opencl_enable", opencl_enable);
|
||||
nano::jsonconfig opencl_l;
|
||||
opencl.serialize_json (opencl_l);
|
||||
|
@ -168,12 +177,13 @@ public:
|
|||
}
|
||||
|
||||
nano::uint256_union wallet;
|
||||
nano::account account;
|
||||
nano::account account{ 0 };
|
||||
nano::node_config node;
|
||||
bool rpc_enable;
|
||||
nano::rpc_config rpc;
|
||||
bool opencl_enable;
|
||||
bool rpc_enable{ false };
|
||||
nano::node_rpc_config rpc;
|
||||
bool opencl_enable{ false };
|
||||
nano::opencl_config opencl;
|
||||
boost::filesystem::path data_path;
|
||||
int json_version () const
|
||||
{
|
||||
return 4;
|
||||
|
@ -205,6 +215,8 @@ bool update_config (qt_wallet_config & config_a, boost::filesystem::path const &
|
|||
// Update json file with new account and/or wallet values
|
||||
std::fstream config_file;
|
||||
config_file.open (config_path_a.string (), std::ios_base::out | std::ios_base::trunc);
|
||||
boost::system::error_code error_chmod;
|
||||
nano::set_secure_perm_file (config_path_a, error_chmod);
|
||||
error = config_a.serialize_json_stream (config_file);
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +237,7 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
splash->showMessage (QSplashScreen::tr ("Remember - Back Up Your Wallet Seed"), Qt::AlignBottom | Qt::AlignHCenter, Qt::darkGray);
|
||||
application.processEvents ();
|
||||
qt_wallet_config config (data_path);
|
||||
auto config_path ((data_path / "config.json"));
|
||||
auto config_path (nano::get_config_path (data_path));
|
||||
int result (0);
|
||||
nano::jsonconfig json;
|
||||
auto error (json.read_and_update (config, config_path));
|
||||
|
@ -279,17 +291,51 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
|
|||
assert (wallet->exists (config.account));
|
||||
update_config (config, config_path);
|
||||
node->start ();
|
||||
std::unique_ptr<nano::rpc> rpc = get_rpc (io_ctx, *node, config.rpc);
|
||||
if (rpc)
|
||||
nano::ipc::ipc_server ipc (*node, config.rpc);
|
||||
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
std::unique_ptr<boost::process::child> rpc_process;
|
||||
#endif
|
||||
std::unique_ptr<nano::rpc> rpc;
|
||||
std::unique_ptr<nano::rpc_handler_interface> rpc_handler;
|
||||
if (config.rpc_enable)
|
||||
{
|
||||
rpc->start (config.rpc_enable);
|
||||
if (config.rpc.rpc_in_process)
|
||||
{
|
||||
nano::rpc_config rpc_config;
|
||||
auto error = nano::read_and_update_rpc_config (data_path, rpc_config);
|
||||
if (error)
|
||||
{
|
||||
throw std::runtime_error ("Could not deserialize rpc_config file");
|
||||
}
|
||||
rpc_handler = std::make_unique<nano::inprocess_rpc_handler> (*node, config.rpc);
|
||||
rpc = nano::get_rpc (io_ctx, rpc_config, *rpc_handler);
|
||||
rpc->start ();
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BOOST_PROCESS_SUPPORTED
|
||||
rpc_process = std::make_unique<boost::process::child> (config.rpc.rpc_path, "--daemon");
|
||||
#else
|
||||
show_error ("rpc_enable is set to true in the config. Set it to false and start the RPC server manually.");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
nano::ipc::ipc_server ipc (*node, *rpc);
|
||||
|
||||
nano::thread_runner runner (io_ctx, node->config.io_threads);
|
||||
QObject::connect (&application, &QApplication::aboutToQuit, [&]() {
|
||||
ipc.stop ();
|
||||
rpc->stop ();
|
||||
node->stop ();
|
||||
if (rpc)
|
||||
{
|
||||
rpc->stop ();
|
||||
}
|
||||
#if USE_BOOST_PROCESS
|
||||
if (rpc_process)
|
||||
{
|
||||
rpc_process->terminate ();
|
||||
}
|
||||
#endif
|
||||
});
|
||||
application.postEvent (&processor, new nano_qt::eventloop_event ([&]() {
|
||||
gui = std::make_shared<nano_qt::wallet> (application, processor, *node, wallet, config.account);
|
||||
|
|
|
@ -12,47 +12,58 @@ endif ()
|
|||
|
||||
add_library (node
|
||||
${platform_sources}
|
||||
${secure_rpc_sources}
|
||||
blockprocessor.cpp
|
||||
blockprocessor.hpp
|
||||
bootstrap.cpp
|
||||
blockprocessor.cpp
|
||||
bootstrap.hpp
|
||||
bootstrap.cpp
|
||||
cli.hpp
|
||||
cli.cpp
|
||||
common.cpp
|
||||
common.hpp
|
||||
daemonconfig.hpp
|
||||
common.cpp
|
||||
daemonconfig.cpp
|
||||
daemonconfig.hpp
|
||||
ipc.hpp
|
||||
ipc.cpp
|
||||
ipcconfig.hpp
|
||||
ipcconfig.cpp
|
||||
lmdb.cpp
|
||||
json_handler.hpp
|
||||
json_handler.cpp
|
||||
json_payment_observer.hpp
|
||||
json_payment_observer.cpp
|
||||
lmdb.hpp
|
||||
logging.cpp
|
||||
lmdb.cpp
|
||||
logging.hpp
|
||||
logging.cpp
|
||||
nodeconfig.hpp
|
||||
nodeconfig.cpp
|
||||
node_observers.hpp
|
||||
node_observers.cpp
|
||||
node_rpc_config.hpp
|
||||
node_rpc_config.cpp
|
||||
node.hpp
|
||||
node.cpp
|
||||
openclwork.cpp
|
||||
openclconfig.hpp
|
||||
openclconfig.cpp
|
||||
openclwork.hpp
|
||||
openclwork.cpp
|
||||
payment_observer_processor.hpp
|
||||
payment_observer_processor.cpp
|
||||
portmapping.hpp
|
||||
portmapping.cpp
|
||||
repcrawler.hpp
|
||||
repcrawler.cpp
|
||||
testing.hpp
|
||||
testing.cpp
|
||||
transport/tcp.cpp
|
||||
transport/tcp.hpp
|
||||
transport/transport.cpp
|
||||
transport/tcp.cpp
|
||||
transport/transport.hpp
|
||||
transport/udp.cpp
|
||||
transport/transport.cpp
|
||||
transport/udp.hpp
|
||||
signatures.cpp
|
||||
transport/udp.cpp
|
||||
signatures.hpp
|
||||
stats.cpp
|
||||
signatures.cpp
|
||||
stats.hpp
|
||||
stats.cpp
|
||||
voting.hpp
|
||||
voting.cpp
|
||||
wallet.hpp
|
||||
|
@ -65,13 +76,12 @@ add_library (node
|
|||
xorshift.hpp)
|
||||
|
||||
target_link_libraries (node
|
||||
rpc
|
||||
secure
|
||||
nano_lib
|
||||
rpc
|
||||
libminiupnpc-static
|
||||
argon2
|
||||
lmdb
|
||||
${OPENSSL_LIBRARIES}
|
||||
Boost::filesystem
|
||||
Boost::log
|
||||
Boost::log_setup
|
||||
|
|
|
@ -343,7 +343,7 @@ std::error_code nano::handle_node_options (boost::program_options::variables_map
|
|||
|
||||
// Check/upgrade the config.json file.
|
||||
{
|
||||
nano::daemon_config config;
|
||||
nano::daemon_config config (data_path);
|
||||
auto error = nano::read_and_update_daemon_config (data_path, config);
|
||||
if (error)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include <nano/lib/config.hpp>
|
||||
#include <nano/node/daemonconfig.hpp>
|
||||
|
||||
nano::daemon_config::daemon_config () :
|
||||
rpc_enable (false),
|
||||
opencl_enable (false)
|
||||
nano::daemon_config::daemon_config (boost::filesystem::path const & data_path_a) :
|
||||
data_path (data_path_a)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,14 @@ nano::error nano::daemon_config::deserialize_json (bool & upgraded_a, nano::json
|
|||
{
|
||||
int version_l;
|
||||
json.get_optional<int> ("version", version_l);
|
||||
|
||||
upgraded_a |= upgrade_json (version_l, json);
|
||||
|
||||
json.get_optional<bool> ("rpc_enable", rpc_enable);
|
||||
|
||||
auto rpc_l (json.get_required_child ("rpc"));
|
||||
|
||||
if (!rpc.deserialize_json (upgraded_a, rpc_l))
|
||||
if (!rpc.deserialize_json (upgraded_a, rpc_l, data_path))
|
||||
{
|
||||
auto node_l (json.get_required_child ("node"));
|
||||
if (!json.get_error ())
|
||||
|
@ -48,6 +50,7 @@ nano::error nano::daemon_config::deserialize_json (bool & upgraded_a, nano::json
|
|||
node.deserialize_json (upgraded_a, node_l);
|
||||
}
|
||||
}
|
||||
|
||||
if (!json.get_error ())
|
||||
{
|
||||
json.get_required<bool> ("opencl_enable", opencl_enable);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/node/node_rpc_config.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
#include <nano/node/openclconfig.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class daemon_config
|
||||
{
|
||||
public:
|
||||
daemon_config ();
|
||||
daemon_config (boost::filesystem::path const & data_path);
|
||||
nano::error deserialize_json (bool &, nano::jsonconfig &);
|
||||
nano::error serialize_json (nano::jsonconfig &);
|
||||
/**
|
||||
|
@ -18,11 +19,12 @@ public:
|
|||
* @param config Configuration to upgrade.
|
||||
*/
|
||||
bool upgrade_json (unsigned version, nano::jsonconfig & config);
|
||||
bool rpc_enable;
|
||||
nano::rpc_config rpc;
|
||||
bool rpc_enable{ false };
|
||||
nano::node_rpc_config rpc;
|
||||
nano::node_config node;
|
||||
bool opencl_enable;
|
||||
bool opencl_enable{ false };
|
||||
nano::opencl_config opencl;
|
||||
boost::filesystem::path data_path;
|
||||
int json_version () const
|
||||
{
|
||||
return 2;
|
||||
|
|
|
@ -16,9 +16,8 @@
|
|||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/json_handler.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
#include <thread>
|
||||
|
||||
using namespace boost::log;
|
||||
|
@ -84,8 +83,8 @@ public:
|
|||
});
|
||||
}
|
||||
|
||||
/** Handler for payload_encoding::json_legacy and payload_encoding::json_unsafe */
|
||||
void rpc_handle_query (bool allow_unsafe)
|
||||
/** Handler for payload_encoding::json_legacy */
|
||||
void handle_json_query (bool allow_unsafe)
|
||||
{
|
||||
session_timer.restart ();
|
||||
auto request_id_l (std::to_string (server.id_dispenser.fetch_add (1)));
|
||||
|
@ -93,18 +92,19 @@ public:
|
|||
// This is called when nano::rpc_handler#process_request is done. We convert to
|
||||
// json and write the response to the ipc socket with a length prefix.
|
||||
auto this_l (this->shared_from_this ());
|
||||
auto response_handler_l ([this_l, request_id_l](boost::property_tree::ptree const & tree_a) {
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, tree_a);
|
||||
ostream.flush ();
|
||||
this_l->response_body = ostream.str ();
|
||||
|
||||
auto response_handler_l ([this_l, request_id_l](std::string const & body) {
|
||||
this_l->response_body = body;
|
||||
this_l->size_response = boost::endian::native_to_big (static_cast<uint32_t> (this_l->response_body.size ()));
|
||||
std::vector<boost::asio::mutable_buffer> bufs = {
|
||||
boost::asio::buffer (&this_l->size_response, sizeof (this_l->size_response)),
|
||||
boost::asio::buffer (this_l->response_body)
|
||||
};
|
||||
|
||||
if (this_l->node.config.logging.log_ipc ())
|
||||
{
|
||||
this_l->node.logger.always_log (boost::str (boost::format ("IPC/RPC request %1% completed in: %2% %3%") % request_id_l % this_l->session_timer.stop ().count () % this_l->session_timer.unit ()));
|
||||
}
|
||||
|
||||
this_l->timer_start (std::chrono::seconds (this_l->config_transport.io_timeout));
|
||||
boost::asio::async_write (this_l->socket, bufs, [this_l](boost::system::error_code const & error_a, size_t size_a) {
|
||||
this_l->timer_cancel ();
|
||||
|
@ -118,17 +118,16 @@ public:
|
|||
}
|
||||
});
|
||||
|
||||
if (this_l->node.config.logging.log_ipc ())
|
||||
{
|
||||
this_l->node.logger.always_log (boost::str (boost::format ("IPC/RPC request %1% completed in: %2% %3%") % request_id_l % this_l->session_timer.stop ().count () % this_l->session_timer.unit ()));
|
||||
}
|
||||
// Do not call any member variables here (like session_timer) as it's possible that the next request may already be underway.
|
||||
});
|
||||
|
||||
node.stats.inc (nano::stat::type::ipc, nano::stat::detail::invocations);
|
||||
auto body (std::string (reinterpret_cast<char *> (buffer.data ()), buffer.size ()));
|
||||
|
||||
// Note that if the rpc action is async, the shared_ptr<rpc_handler> lifetime will be extended by the action handler
|
||||
auto handler (std::make_shared<nano::rpc_handler> (node, server.rpc, body, request_id_l, response_handler_l));
|
||||
// Note that if the rpc action is async, the shared_ptr<json_handler> lifetime will be extended by the action handler
|
||||
auto handler (std::make_shared<nano::json_handler> (node, server.node_rpc_config, body, response_handler_l, [& server = server]() {
|
||||
server.stop ();
|
||||
}));
|
||||
// For unsafe actions to be allowed, the unsafe encoding must be used AND the transport config must allow it
|
||||
handler->process_request (allow_unsafe && config_transport.allow_unsafe);
|
||||
}
|
||||
|
@ -157,7 +156,7 @@ public:
|
|||
this_l->buffer.resize (this_l->buffer_size);
|
||||
// Payload (ptree compliant JSON string)
|
||||
this_l->async_read_exactly (this_l->buffer.data (), this_l->buffer_size, [this_l, allow_unsafe]() {
|
||||
this_l->rpc_handle_query (allow_unsafe);
|
||||
this_l->handle_json_query (allow_unsafe);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -291,8 +290,9 @@ private:
|
|||
};
|
||||
}
|
||||
|
||||
nano::ipc::ipc_server::ipc_server (nano::node & node_a, nano::rpc & rpc_a) :
|
||||
node (node_a), rpc (rpc_a)
|
||||
nano::ipc::ipc_server::ipc_server (nano::node & node_a, nano::node_rpc_config const & node_rpc_config_a) :
|
||||
node (node_a),
|
||||
node_rpc_config (node_rpc_config_a)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <nano/lib/ipc.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <vector>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/node/node_rpc_config.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
class rpc;
|
||||
|
||||
namespace ipc
|
||||
{
|
||||
|
@ -16,12 +15,13 @@ namespace ipc
|
|||
class ipc_server
|
||||
{
|
||||
public:
|
||||
ipc_server (nano::node & node, nano::rpc & rpc);
|
||||
ipc_server (nano::node & node_a, nano::node_rpc_config const & node_rpc_config = nano::node_rpc_config{});
|
||||
|
||||
virtual ~ipc_server ();
|
||||
void stop ();
|
||||
|
||||
nano::node & node;
|
||||
nano::rpc & rpc;
|
||||
nano::node_rpc_config const & node_rpc_config;
|
||||
|
||||
/** Unique counter/id shared across sessions */
|
||||
std::atomic<uint64_t> id_dispenser{ 0 };
|
||||
|
|
4562
nano/node/json_handler.cpp
Normal file
4562
nano/node/json_handler.cpp
Normal file
File diff suppressed because it is too large
Load diff
195
nano/node/json_handler.hpp
Normal file
195
nano/node/json_handler.hpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <functional>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
class node_rpc_config;
|
||||
|
||||
class json_handler : public std::enable_shared_from_this<nano::json_handler>
|
||||
{
|
||||
public:
|
||||
json_handler (nano::node &, nano::node_rpc_config const &, std::string const &, std::function<void(std::string const &)> const &, std::function<void()> stop_callback = []() {});
|
||||
void process_request (bool unsafe = false);
|
||||
void account_balance ();
|
||||
void account_block_count ();
|
||||
void account_count ();
|
||||
void account_create ();
|
||||
void account_get ();
|
||||
void account_history ();
|
||||
void account_info ();
|
||||
void account_key ();
|
||||
void account_list ();
|
||||
void account_move ();
|
||||
void account_remove ();
|
||||
void account_representative ();
|
||||
void account_representative_set ();
|
||||
void account_weight ();
|
||||
void accounts_balances ();
|
||||
void accounts_create ();
|
||||
void accounts_frontiers ();
|
||||
void accounts_pending ();
|
||||
void active_difficulty ();
|
||||
void available_supply ();
|
||||
void block_info ();
|
||||
void block_confirm ();
|
||||
void blocks ();
|
||||
void blocks_info ();
|
||||
void block_account ();
|
||||
void block_count ();
|
||||
void block_count_type ();
|
||||
void block_create ();
|
||||
void block_hash ();
|
||||
void bootstrap ();
|
||||
void bootstrap_any ();
|
||||
void bootstrap_lazy ();
|
||||
void bootstrap_status ();
|
||||
void chain (bool = false);
|
||||
void confirmation_active ();
|
||||
void confirmation_history ();
|
||||
void confirmation_info ();
|
||||
void confirmation_quorum ();
|
||||
void delegators ();
|
||||
void delegators_count ();
|
||||
void deterministic_key ();
|
||||
void frontiers ();
|
||||
void keepalive ();
|
||||
void key_create ();
|
||||
void key_expand ();
|
||||
void ledger ();
|
||||
void mnano_to_raw (nano::uint128_t = nano::Mxrb_ratio);
|
||||
void mnano_from_raw (nano::uint128_t = nano::Mxrb_ratio);
|
||||
void node_id ();
|
||||
void node_id_delete ();
|
||||
void password_change ();
|
||||
void password_enter ();
|
||||
void password_valid (bool = false);
|
||||
void payment_begin ();
|
||||
void payment_init ();
|
||||
void payment_end ();
|
||||
void payment_wait ();
|
||||
void peers ();
|
||||
void pending ();
|
||||
void pending_exists ();
|
||||
void process ();
|
||||
void receive ();
|
||||
void receive_minimum ();
|
||||
void receive_minimum_set ();
|
||||
void representatives ();
|
||||
void representatives_online ();
|
||||
void republish ();
|
||||
void search_pending ();
|
||||
void search_pending_all ();
|
||||
void send ();
|
||||
void sign ();
|
||||
void stats ();
|
||||
void stats_clear ();
|
||||
void stop ();
|
||||
void unchecked ();
|
||||
void unchecked_clear ();
|
||||
void unchecked_get ();
|
||||
void unchecked_keys ();
|
||||
void unopened ();
|
||||
void uptime ();
|
||||
void validate_account_number ();
|
||||
void version ();
|
||||
void wallet_add ();
|
||||
void wallet_add_watch ();
|
||||
void wallet_balances ();
|
||||
void wallet_change_seed ();
|
||||
void wallet_contains ();
|
||||
void wallet_create ();
|
||||
void wallet_destroy ();
|
||||
void wallet_export ();
|
||||
void wallet_frontiers ();
|
||||
void wallet_history ();
|
||||
void wallet_info ();
|
||||
void wallet_key_valid ();
|
||||
void wallet_ledger ();
|
||||
void wallet_lock ();
|
||||
void wallet_pending ();
|
||||
void wallet_representative ();
|
||||
void wallet_representative_set ();
|
||||
void wallet_republish ();
|
||||
void wallet_seed ();
|
||||
void wallet_work_get ();
|
||||
void work_cancel ();
|
||||
void work_generate ();
|
||||
void work_get ();
|
||||
void work_peer_add ();
|
||||
void work_peers ();
|
||||
void work_peers_clear ();
|
||||
void work_set ();
|
||||
void work_validate ();
|
||||
std::string body;
|
||||
nano::node & node;
|
||||
boost::property_tree::ptree request;
|
||||
std::function<void(std::string const &)> response;
|
||||
void response_errors ();
|
||||
std::error_code ec;
|
||||
std::string action;
|
||||
boost::property_tree::ptree response_l;
|
||||
std::shared_ptr<nano::wallet> wallet_impl ();
|
||||
bool wallet_locked_impl (nano::transaction const &, std::shared_ptr<nano::wallet>);
|
||||
bool wallet_account_impl (nano::transaction const &, std::shared_ptr<nano::wallet>, nano::account const &);
|
||||
nano::account account_impl (std::string = "");
|
||||
nano::amount amount_impl ();
|
||||
std::shared_ptr<nano::block> block_impl (bool = true);
|
||||
std::shared_ptr<nano::block> block_json_impl (bool = true);
|
||||
nano::block_hash hash_impl (std::string = "hash");
|
||||
nano::amount threshold_optional_impl ();
|
||||
uint64_t work_optional_impl ();
|
||||
uint64_t count_impl ();
|
||||
uint64_t count_optional_impl (uint64_t = std::numeric_limits<uint64_t>::max ());
|
||||
uint64_t offset_optional_impl (uint64_t = 0);
|
||||
bool enable_sign_hash{ false };
|
||||
std::function<void()> stop_callback;
|
||||
nano::node_rpc_config const & node_rpc_config;
|
||||
};
|
||||
|
||||
class inprocess_rpc_handler final : public nano::rpc_handler_interface
|
||||
{
|
||||
public:
|
||||
inprocess_rpc_handler (nano::node & node_a, nano::node_rpc_config const & node_rpc_config_a, std::function<void()> stop_callback_a = []() {}) :
|
||||
node (node_a),
|
||||
stop_callback (stop_callback_a),
|
||||
node_rpc_config (node_rpc_config_a)
|
||||
{
|
||||
}
|
||||
|
||||
void process_request (std::string const &, std::string const & body_a, std::function<void(std::string const &)> response_a) override
|
||||
{
|
||||
// Note that if the rpc action is async, the shared_ptr<json_handler> lifetime will be extended by the action handler
|
||||
auto handler (std::make_shared<nano::json_handler> (node, node_rpc_config, body_a, response_a, [this]() {
|
||||
this->stop_callback ();
|
||||
this->stop ();
|
||||
}));
|
||||
handler->process_request ();
|
||||
}
|
||||
|
||||
void stop () override
|
||||
{
|
||||
if (rpc)
|
||||
{
|
||||
rpc->stop ();
|
||||
}
|
||||
}
|
||||
|
||||
void rpc_instance (nano::rpc & rpc_a) override
|
||||
{
|
||||
rpc = rpc_a;
|
||||
}
|
||||
|
||||
private:
|
||||
nano::node & node;
|
||||
boost::optional<nano::rpc &> rpc;
|
||||
std::function<void()> stop_callback;
|
||||
nano::node_rpc_config const & node_rpc_config;
|
||||
};
|
||||
}
|
72
nano/node/json_payment_observer.cpp
Normal file
72
nano/node/json_payment_observer.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include <nano/lib/json_error_response.hpp>
|
||||
#include <nano/node/ipc.hpp>
|
||||
#include <nano/node/json_handler.hpp>
|
||||
#include <nano/node/json_payment_observer.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/payment_observer_processor.hpp>
|
||||
|
||||
nano::json_payment_observer::json_payment_observer (nano::node & node_a, std::function<void(std::string const &)> const & response_a, nano::account const & account_a, nano::amount const & amount_a) :
|
||||
node (node_a),
|
||||
account (account_a),
|
||||
amount (amount_a),
|
||||
response (response_a)
|
||||
{
|
||||
completed.clear ();
|
||||
}
|
||||
|
||||
void nano::json_payment_observer::start (uint64_t timeout)
|
||||
{
|
||||
auto this_l (shared_from_this ());
|
||||
node.alarm.add (std::chrono::steady_clock::now () + std::chrono::milliseconds (timeout), [this_l]() {
|
||||
this_l->complete (nano::payment_status::nothing);
|
||||
});
|
||||
}
|
||||
|
||||
void nano::json_payment_observer::observe ()
|
||||
{
|
||||
if (node.balance (account) >= amount.number ())
|
||||
{
|
||||
complete (nano::payment_status::success);
|
||||
}
|
||||
}
|
||||
|
||||
void nano::json_payment_observer::complete (nano::payment_status status)
|
||||
{
|
||||
auto already (completed.test_and_set ());
|
||||
if (!already)
|
||||
{
|
||||
if (node.config.logging.log_ipc ())
|
||||
{
|
||||
node.logger.always_log (boost::str (boost::format ("Exiting json_payment_observer for account %1% status %2%") % account.to_account () % static_cast<unsigned> (status)));
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
case nano::payment_status::nothing:
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("deprecated", "1");
|
||||
response_l.put ("status", "nothing");
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, response_l);
|
||||
response (ostream.str ());
|
||||
break;
|
||||
}
|
||||
case nano::payment_status::success:
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("deprecated", "1");
|
||||
response_l.put ("status", "success");
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, response_l);
|
||||
response (ostream.str ());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
json_error_response (response, "Internal payment error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
node.payment_observer_processor.erase (account);
|
||||
}
|
||||
}
|
37
nano/node/json_payment_observer.hpp
Normal file
37
nano/node/json_payment_observer.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/node/node_observers.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
|
||||
enum class payment_status
|
||||
{
|
||||
not_a_status,
|
||||
unknown,
|
||||
nothing, // Timeout and nothing was received
|
||||
//insufficient, // Timeout and not enough was received
|
||||
//over, // More than requested received
|
||||
//success_fork, // Amount received but it involved a fork
|
||||
success // Amount received
|
||||
};
|
||||
class json_payment_observer final : public std::enable_shared_from_this<nano::json_payment_observer>
|
||||
{
|
||||
public:
|
||||
json_payment_observer (nano::node &, std::function<void(std::string const &)> const &, nano::account const &, nano::amount const &);
|
||||
void start (uint64_t);
|
||||
void observe ();
|
||||
void complete (nano::payment_status);
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
nano::node & node;
|
||||
nano::account account;
|
||||
nano::amount amount;
|
||||
std::function<void(std::string const &)> response;
|
||||
std::atomic_flag completed;
|
||||
};
|
||||
}
|
|
@ -45,7 +45,6 @@ nano::error nano::logging::serialize_json (nano::jsonconfig & json) const
|
|||
json.put ("network_node_id_handshake", network_node_id_handshake_logging_value);
|
||||
json.put ("node_lifetime_tracing", node_lifetime_tracing_value);
|
||||
json.put ("insufficient_work", insufficient_work_logging_value);
|
||||
json.put ("log_rpc", log_rpc_value);
|
||||
json.put ("log_ipc", log_ipc_value);
|
||||
json.put ("bulk_pull", bulk_pull_logging_value);
|
||||
json.put ("work_generation_time", work_generation_time_value);
|
||||
|
@ -88,6 +87,7 @@ bool nano::logging::upgrade_json (unsigned version_a, nano::jsonconfig & json)
|
|||
upgraded_l = true;
|
||||
case 6:
|
||||
json.put ("min_time_between_output", min_time_between_log_output.count ());
|
||||
json.erase ("log_rpc");
|
||||
upgraded_l = true;
|
||||
break;
|
||||
case 7:
|
||||
|
@ -132,7 +132,6 @@ nano::error nano::logging::deserialize_json (bool & upgraded_a, nano::jsonconfig
|
|||
json.get<bool> ("network_node_id_handshake", network_node_id_handshake_logging_value);
|
||||
json.get<bool> ("node_lifetime_tracing", node_lifetime_tracing_value);
|
||||
json.get<bool> ("insufficient_work", insufficient_work_logging_value);
|
||||
json.get<bool> ("log_rpc", log_rpc_value);
|
||||
json.get<bool> ("log_ipc", log_ipc_value);
|
||||
json.get<bool> ("bulk_pull", bulk_pull_logging_value);
|
||||
json.get<bool> ("work_generation_time", work_generation_time_value);
|
||||
|
@ -203,11 +202,6 @@ bool nano::logging::insufficient_work_logging () const
|
|||
return network_logging () && insufficient_work_logging_value;
|
||||
}
|
||||
|
||||
bool nano::logging::log_rpc () const
|
||||
{
|
||||
return network_logging () && log_rpc_value;
|
||||
}
|
||||
|
||||
bool nano::logging::log_ipc () const
|
||||
{
|
||||
return network_logging () && log_ipc_value;
|
||||
|
|
|
@ -34,7 +34,6 @@ public:
|
|||
bool insufficient_work_logging () const;
|
||||
bool upnp_details_logging () const;
|
||||
bool timing_logging () const;
|
||||
bool log_rpc () const;
|
||||
bool log_ipc () const;
|
||||
bool bulk_pull_logging () const;
|
||||
bool callback_logging () const;
|
||||
|
@ -53,7 +52,6 @@ public:
|
|||
bool network_node_id_handshake_logging_value{ false };
|
||||
bool node_lifetime_tracing_value{ false };
|
||||
bool insufficient_work_logging_value{ true };
|
||||
bool log_rpc_value{ true };
|
||||
bool log_ipc_value{ true };
|
||||
bool bulk_pull_logging_value{ false };
|
||||
bool work_generation_time_value{ true };
|
||||
|
|
|
@ -950,18 +950,6 @@ void nano::vote_processor::calculate_weights ()
|
|||
|
||||
namespace nano
|
||||
{
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (node_observers & node_observers, const std::string & name)
|
||||
{
|
||||
auto composite = std::make_unique<seq_con_info_composite> (name);
|
||||
composite->add_component (collect_seq_con_info (node_observers.blocks, "blocks"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.wallet, "wallet"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.vote, "vote"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.account_balance, "account_balance"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.endpoint, "endpoint"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.disconnect, "disconnect"));
|
||||
return composite;
|
||||
}
|
||||
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (vote_processor & vote_processor, const std::string & name)
|
||||
{
|
||||
size_t votes_count = 0;
|
||||
|
@ -1064,6 +1052,7 @@ online_reps (*this, config.online_weight_minimum.number ()),
|
|||
stats (config.stat_config),
|
||||
vote_uniquer (block_uniquer),
|
||||
active (*this, delay_frontier_confirmation_height_updating),
|
||||
payment_observer_processor (observers.blocks),
|
||||
startup_time (std::chrono::steady_clock::now ())
|
||||
{
|
||||
if (config.websocket_config.enabled)
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include <nano/node/blockprocessor.hpp>
|
||||
#include <nano/node/bootstrap.hpp>
|
||||
#include <nano/node/logging.hpp>
|
||||
#include <nano/node/node_observers.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
#include <nano/node/payment_observer_processor.hpp>
|
||||
#include <nano/node/portmapping.hpp>
|
||||
#include <nano/node/repcrawler.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
|
@ -371,18 +373,6 @@ public:
|
|||
bool wallets_store_init{ false };
|
||||
bool wallet_init{ false };
|
||||
};
|
||||
class node_observers final
|
||||
{
|
||||
public:
|
||||
nano::observer_set<std::shared_ptr<nano::block>, nano::account const &, nano::uint128_t const &, bool> blocks;
|
||||
nano::observer_set<bool> wallet;
|
||||
nano::observer_set<nano::transaction const &, std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>> vote;
|
||||
nano::observer_set<nano::account const &, bool> account_balance;
|
||||
nano::observer_set<std::shared_ptr<nano::transport::channel>> endpoint;
|
||||
nano::observer_set<> disconnect;
|
||||
};
|
||||
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (node_observers & node_observers, const std::string & name);
|
||||
|
||||
class vote_processor final
|
||||
{
|
||||
|
@ -506,6 +496,7 @@ public:
|
|||
nano::block_uniquer block_uniquer;
|
||||
nano::vote_uniquer vote_uniquer;
|
||||
nano::active_transactions active;
|
||||
nano::payment_observer_processor payment_observer_processor;
|
||||
const std::chrono::steady_clock::time_point startup_time;
|
||||
std::chrono::seconds unchecked_cutoff = std::chrono::seconds (7 * 24 * 60 * 60); // Week
|
||||
static double constexpr price_max = 16.0;
|
||||
|
|
13
nano/node/node_observers.cpp
Normal file
13
nano/node/node_observers.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include <nano/node/node_observers.hpp>
|
||||
|
||||
std::unique_ptr<nano::seq_con_info_component> nano::collect_seq_con_info (nano::node_observers & node_observers, const std::string & name)
|
||||
{
|
||||
auto composite = std::make_unique<nano::seq_con_info_composite> (name);
|
||||
composite->add_component (collect_seq_con_info (node_observers.blocks, "blocks"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.wallet, "wallet"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.vote, "vote"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.account_balance, "account_balance"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.endpoint, "endpoint"));
|
||||
composite->add_component (collect_seq_con_info (node_observers.disconnect, "disconnect"));
|
||||
return composite;
|
||||
}
|
24
nano/node/node_observers.hpp
Normal file
24
nano/node/node_observers.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/node/transport/transport.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node_observers final
|
||||
{
|
||||
public:
|
||||
using blocks_t = nano::observer_set<std::shared_ptr<nano::block>, nano::account const &, nano::uint128_t const &, bool>;
|
||||
blocks_t blocks;
|
||||
nano::observer_set<bool> wallet;
|
||||
nano::observer_set<nano::transaction const &, std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>> vote;
|
||||
nano::observer_set<nano::account const &, bool> account_balance;
|
||||
nano::observer_set<std::shared_ptr<nano::transport::channel>> endpoint;
|
||||
nano::observer_set<> disconnect;
|
||||
};
|
||||
|
||||
std::unique_ptr<seq_con_info_component> collect_seq_con_info (node_observers & node_observers, const std::string & name);
|
||||
}
|
78
nano/node/node_rpc_config.cpp
Normal file
78
nano/node/node_rpc_config.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <nano/node/node_rpc_config.hpp>
|
||||
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
|
||||
nano::error nano::node_rpc_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
json.put ("version", json_version ());
|
||||
json.put ("enable_sign_hash", enable_sign_hash);
|
||||
json.put ("max_work_generate_difficulty", nano::to_string_hex (max_work_generate_difficulty));
|
||||
json.put ("rpc_path", rpc_path);
|
||||
json.put ("rpc_in_process", rpc_in_process);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::error nano::node_rpc_config::deserialize_json (bool & upgraded_a, nano::jsonconfig & json, boost::filesystem::path const & data_path)
|
||||
{
|
||||
auto version_l (json.get_optional<unsigned> ("version"));
|
||||
if (!version_l)
|
||||
{
|
||||
json.erase ("frontier_request_limit");
|
||||
json.erase ("chain_request_limit");
|
||||
|
||||
// Don't migrate enable_sign_hash as this is not needed by the external rpc process, but first save it.
|
||||
json.get_optional ("enable_sign_hash", enable_sign_hash, false);
|
||||
|
||||
json.erase ("enable_sign_hash");
|
||||
json.erase ("max_work_generate_difficulty");
|
||||
|
||||
migrate (json, data_path);
|
||||
|
||||
json.put ("enable_sign_hash", enable_sign_hash);
|
||||
json.put ("max_work_generate_difficulty", nano::to_string_hex (max_work_generate_difficulty));
|
||||
|
||||
// Remove options no longer needed after migration
|
||||
json.erase ("enable_control");
|
||||
json.erase ("address");
|
||||
json.erase ("port");
|
||||
json.erase ("max_json_depth");
|
||||
json.erase ("max_request_size");
|
||||
|
||||
version_l = 1;
|
||||
json.put ("version", *version_l);
|
||||
json.put ("rpc_path", get_default_rpc_filepath ());
|
||||
auto rpc_in_process_l = json.get_optional<bool> ("rpc_in_process");
|
||||
if (!rpc_in_process_l)
|
||||
{
|
||||
json.put ("rpc_in_process", true);
|
||||
}
|
||||
|
||||
upgraded_a = true;
|
||||
}
|
||||
|
||||
json.get_optional<bool> ("enable_sign_hash", enable_sign_hash);
|
||||
std::string max_work_generate_difficulty_text;
|
||||
json.get_optional<std::string> ("max_work_generate_difficulty", max_work_generate_difficulty_text);
|
||||
if (!max_work_generate_difficulty_text.empty ())
|
||||
{
|
||||
nano::from_string_hex (max_work_generate_difficulty_text, max_work_generate_difficulty);
|
||||
}
|
||||
json.get_optional<std::string> ("rpc_path", rpc_path);
|
||||
json.get_optional<bool> ("rpc_in_process", rpc_in_process);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
void nano::node_rpc_config::migrate (nano::jsonconfig & json, boost::filesystem::path const & data_path)
|
||||
{
|
||||
nano::jsonconfig rpc_json;
|
||||
auto rpc_config_path = nano::get_rpc_config_path (data_path);
|
||||
auto rpc_error (rpc_json.read<nano::rpc_config> (rpc_config_path));
|
||||
if (rpc_error || rpc_json.empty ())
|
||||
{
|
||||
// Migrate RPC info across
|
||||
json.write (rpc_config_path);
|
||||
}
|
||||
}
|
26
nano/node/node_rpc_config.hpp
Normal file
26
nano/node/node_rpc_config.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node_rpc_config final
|
||||
{
|
||||
public:
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (bool & upgraded_a, nano::jsonconfig &, boost::filesystem::path const & data_path);
|
||||
bool enable_sign_hash{ false };
|
||||
uint64_t max_work_generate_difficulty{ 0xffffffffc0000000 };
|
||||
std::string rpc_path{ get_default_rpc_filepath () };
|
||||
bool rpc_in_process{ true };
|
||||
static int json_version ()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
void migrate (nano::jsonconfig & json, boost::filesystem::path const & data_path);
|
||||
};
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
// NOTE: to reduce compile times, this include can be replaced by more narrow includes
|
||||
// once nano::network is factored out of node.{c|h}pp
|
||||
|
|
24
nano/node/openclconfig.cpp
Normal file
24
nano/node/openclconfig.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include <nano/node/openclconfig.hpp>
|
||||
|
||||
nano::opencl_config::opencl_config (unsigned platform_a, unsigned device_a, unsigned threads_a) :
|
||||
platform (platform_a),
|
||||
device (device_a),
|
||||
threads (threads_a)
|
||||
{
|
||||
}
|
||||
|
||||
nano::error nano::opencl_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
json.put ("platform", platform);
|
||||
json.put ("device", device);
|
||||
json.put ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::error nano::opencl_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
json.get_optional<unsigned> ("platform", platform);
|
||||
json.get_optional<unsigned> ("device", device);
|
||||
json.get_optional<unsigned> ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
19
nano/node/openclconfig.hpp
Normal file
19
nano/node/openclconfig.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class opencl_config
|
||||
{
|
||||
public:
|
||||
opencl_config () = default;
|
||||
opencl_config (unsigned, unsigned, unsigned);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (nano::jsonconfig &);
|
||||
unsigned platform{ 0 };
|
||||
unsigned device{ 0 };
|
||||
unsigned threads{ 1024 * 1024 };
|
||||
};
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#include <nano/node/openclwork.hpp>
|
||||
|
||||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/openclconfig.hpp>
|
||||
#include <nano/node/openclwork.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
|
||||
#include <array>
|
||||
|
@ -484,36 +484,6 @@ void nano::opencl_environment::dump (std::ostream & stream)
|
|||
}
|
||||
}
|
||||
|
||||
nano::opencl_config::opencl_config () :
|
||||
platform (0),
|
||||
device (0),
|
||||
threads (1024 * 1024)
|
||||
{
|
||||
}
|
||||
|
||||
nano::opencl_config::opencl_config (unsigned platform_a, unsigned device_a, unsigned threads_a) :
|
||||
platform (platform_a),
|
||||
device (device_a),
|
||||
threads (threads_a)
|
||||
{
|
||||
}
|
||||
|
||||
nano::error nano::opencl_config::serialize_json (nano::jsonconfig & json) const
|
||||
{
|
||||
json.put ("platform", platform);
|
||||
json.put ("device", device);
|
||||
json.put ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::error nano::opencl_config::deserialize_json (nano::jsonconfig & json)
|
||||
{
|
||||
json.get_optional<unsigned> ("platform", platform);
|
||||
json.get_optional<unsigned> ("device", device);
|
||||
json.get_optional<unsigned> ("threads", threads);
|
||||
return json.get_error ();
|
||||
}
|
||||
|
||||
nano::opencl_work::opencl_work (bool & error_a, nano::opencl_config const & config_a, nano::opencl_environment & environment_a, nano::logging & logging_a) :
|
||||
config (config_a),
|
||||
context (0),
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/node/openclconfig.hpp>
|
||||
#include <nano/node/xorshift.hpp>
|
||||
|
||||
#include <map>
|
||||
|
@ -36,17 +37,6 @@ public:
|
|||
};
|
||||
union uint256_union;
|
||||
class work_pool;
|
||||
class opencl_config
|
||||
{
|
||||
public:
|
||||
opencl_config ();
|
||||
opencl_config (unsigned, unsigned, unsigned);
|
||||
nano::error serialize_json (nano::jsonconfig &) const;
|
||||
nano::error deserialize_json (nano::jsonconfig &);
|
||||
unsigned platform;
|
||||
unsigned device;
|
||||
unsigned threads;
|
||||
};
|
||||
class opencl_work
|
||||
{
|
||||
public:
|
||||
|
|
41
nano/node/payment_observer_processor.cpp
Normal file
41
nano/node/payment_observer_processor.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <nano/node/payment_observer_processor.hpp>
|
||||
|
||||
#include <nano/node/json_payment_observer.hpp>
|
||||
|
||||
nano::payment_observer_processor::payment_observer_processor (nano::node_observers::blocks_t & blocks)
|
||||
{
|
||||
blocks.add ([this](std::shared_ptr<nano::block> block_a, nano::account const & account_a, nano::uint128_t const &, bool) {
|
||||
observer_action (account_a);
|
||||
});
|
||||
}
|
||||
|
||||
void nano::payment_observer_processor::observer_action (nano::account const & account_a)
|
||||
{
|
||||
std::shared_ptr<nano::json_payment_observer> observer;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
auto existing (payment_observers.find (account_a));
|
||||
if (existing != payment_observers.end ())
|
||||
{
|
||||
observer = existing->second;
|
||||
}
|
||||
}
|
||||
if (observer != nullptr)
|
||||
{
|
||||
observer->observe ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::payment_observer_processor::add (nano::account const & account_a, std::shared_ptr<nano::json_payment_observer> payment_observer_a)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
assert (payment_observers.find (account_a) == payment_observers.end ());
|
||||
payment_observers[account_a] = payment_observer_a;
|
||||
}
|
||||
|
||||
void nano::payment_observer_processor::erase (nano::account & account_a)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
assert (payment_observers.find (account_a) != payment_observers.end ());
|
||||
payment_observers.erase (account_a);
|
||||
}
|
21
nano/node/payment_observer_processor.hpp
Normal file
21
nano/node/payment_observer_processor.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/node/node_observers.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class json_payment_observer;
|
||||
|
||||
class payment_observer_processor final
|
||||
{
|
||||
public:
|
||||
explicit payment_observer_processor (nano::node_observers::blocks_t & blocks);
|
||||
void observer_action (nano::account const & account_a);
|
||||
void add (nano::account const & account_a, std::shared_ptr<nano::json_payment_observer> payment_observer_a);
|
||||
void erase (nano::account & account_a);
|
||||
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::unordered_map<nano::account, std::shared_ptr<nano::json_payment_observer>> payment_observers;
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
#include <miniupnpc.h>
|
||||
#include <miniupnp/miniupnpc/miniupnpc.h>
|
||||
#include <mutex>
|
||||
#include <nano/lib/config.hpp>
|
||||
|
||||
|
|
|
@ -532,3 +532,19 @@ void nano::landing::distribute_ongoing ()
|
|||
|
||||
std::chrono::seconds constexpr nano::landing::distribution_interval;
|
||||
std::chrono::seconds constexpr nano::landing::sleep_seconds;
|
||||
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ()
|
||||
{
|
||||
// Makes sure everything is cleaned up
|
||||
nano::logging::release_file_sink ();
|
||||
// Clean up tmp directories created by the tests. Since it's sometimes useful to
|
||||
// see log files after test failures, an environment variable is supported to
|
||||
// retain the files.
|
||||
if (std::getenv ("TEST_KEEP_TMPDIRS") == nullptr)
|
||||
{
|
||||
nano::remove_temporary_directories ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
||||
#include <nano/node/common.hpp>
|
||||
#include <nano/node/stats.hpp>
|
||||
|
||||
namespace nano
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include <QApplication>
|
||||
#include <gtest/gtest.h>
|
||||
#include <nano/secure/utility.hpp>
|
||||
QApplication * test_application = nullptr;
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
void force_nano_test_network ();
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,6 @@ int main (int argc, char ** argv)
|
|||
test_application = &application;
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanp_test_directories_on_exit ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -9,16 +9,11 @@ add_library (rpc
|
|||
rpc_connection.hpp
|
||||
rpc_connection.cpp
|
||||
rpc_handler.hpp
|
||||
rpc_handler.cpp)
|
||||
rpc_handler.cpp
|
||||
rpc_request_processor.hpp
|
||||
rpc_request_processor.cpp)
|
||||
|
||||
target_link_libraries (rpc
|
||||
node
|
||||
nano_lib
|
||||
${OPENSSL_LIBRARIES}
|
||||
Boost::boost)
|
||||
|
||||
target_compile_definitions(rpc
|
||||
PRIVATE
|
||||
-DNANO_VERSION_MAJOR=${CPACK_PACKAGE_VERSION_MAJOR}
|
||||
-DNANO_VERSION_MINOR=${CPACK_PACKAGE_VERSION_MINOR}
|
||||
-DNANO_VERSION_PATCH=${CPACK_PACKAGE_VERSION_PATCH})
|
158
nano/rpc/rpc.cpp
158
nano/rpc/rpc.cpp
|
@ -1,62 +1,50 @@
|
|||
#include <boost/algorithm/string.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/interface.h>
|
||||
#include <nano/node/node.hpp>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <nano/lib/rpc_handler_interface.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/rpc/rpc_connection.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
|
||||
#ifdef NANO_SECURE_RPC
|
||||
#include <nano/rpc/rpc_secure.hpp>
|
||||
#endif
|
||||
|
||||
#include <nano/lib/errors.hpp>
|
||||
|
||||
nano::rpc::rpc (boost::asio::io_context & io_ctx_a, nano::node & node_a, nano::rpc_config const & config_a) :
|
||||
acceptor (io_ctx_a),
|
||||
nano::rpc::rpc (boost::asio::io_context & io_ctx_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a) :
|
||||
config (config_a),
|
||||
node (node_a)
|
||||
acceptor (io_ctx_a),
|
||||
logger (std::chrono::milliseconds (0)),
|
||||
io_ctx (io_ctx_a),
|
||||
rpc_handler_interface (rpc_handler_interface_a)
|
||||
{
|
||||
rpc_handler_interface.rpc_instance (*this);
|
||||
}
|
||||
|
||||
void nano::rpc::add_block_observer ()
|
||||
nano::rpc::~rpc ()
|
||||
{
|
||||
node.observers.blocks.add ([this](std::shared_ptr<nano::block> block_a, nano::account const & account_a, nano::uint128_t const &, bool) {
|
||||
observer_action (account_a);
|
||||
});
|
||||
if (!stopped)
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::rpc::start (bool rpc_enabled_a)
|
||||
void nano::rpc::start ()
|
||||
{
|
||||
if (rpc_enabled_a)
|
||||
auto endpoint (boost::asio::ip::tcp::endpoint (config.address, config.port));
|
||||
acceptor.open (endpoint.protocol ());
|
||||
acceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
|
||||
|
||||
boost::system::error_code ec;
|
||||
acceptor.bind (endpoint, ec);
|
||||
if (ec)
|
||||
{
|
||||
auto endpoint (nano::tcp_endpoint (config.address, config.port));
|
||||
acceptor.open (endpoint.protocol ());
|
||||
acceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
|
||||
|
||||
boost::system::error_code ec;
|
||||
acceptor.bind (endpoint, ec);
|
||||
if (ec)
|
||||
{
|
||||
node.logger.always_log (boost::str (boost::format ("Error while binding for RPC on port %1%: %2%") % endpoint.port () % ec.message ()));
|
||||
throw std::runtime_error (ec.message ());
|
||||
}
|
||||
|
||||
acceptor.listen ();
|
||||
}
|
||||
|
||||
add_block_observer ();
|
||||
|
||||
if (rpc_enabled_a)
|
||||
{
|
||||
accept ();
|
||||
logger.always_log (boost::str (boost::format ("Error while binding for RPC on port %1%: %2%") % endpoint.port () % ec.message ()));
|
||||
throw std::runtime_error (ec.message ());
|
||||
}
|
||||
acceptor.listen ();
|
||||
accept ();
|
||||
}
|
||||
|
||||
void nano::rpc::accept ()
|
||||
{
|
||||
auto connection (std::make_shared<nano::rpc_connection> (node, *this));
|
||||
auto connection (std::make_shared<nano::rpc_connection> (config, network_constants, io_ctx, logger, rpc_handler_interface));
|
||||
acceptor.async_accept (connection->socket, [this, connection](boost::system::error_code const & ec) {
|
||||
if (ec != boost::asio::error::operation_aborted && acceptor.is_open ())
|
||||
{
|
||||
|
@ -68,116 +56,32 @@ void nano::rpc::accept ()
|
|||
}
|
||||
else
|
||||
{
|
||||
this->node.logger.always_log (boost::str (boost::format ("Error accepting RPC connections: %1% (%2%)") % ec.message () % ec.value ()));
|
||||
logger.always_log (boost::str (boost::format ("Error accepting RPC connections: %1% (%2%)") % ec.message () % ec.value ()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nano::rpc::stop ()
|
||||
{
|
||||
stopped = true;
|
||||
acceptor.close ();
|
||||
}
|
||||
|
||||
void nano::rpc::observer_action (nano::account const & account_a)
|
||||
{
|
||||
std::shared_ptr<nano::payment_observer> observer;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (mutex);
|
||||
auto existing (payment_observers.find (account_a));
|
||||
if (existing != payment_observers.end ())
|
||||
{
|
||||
observer = existing->second;
|
||||
}
|
||||
}
|
||||
if (observer != nullptr)
|
||||
{
|
||||
observer->observe ();
|
||||
}
|
||||
}
|
||||
|
||||
nano::payment_observer::payment_observer (std::function<void(boost::property_tree::ptree const &)> const & response_a, nano::rpc & rpc_a, nano::account const & account_a, nano::amount const & amount_a) :
|
||||
rpc (rpc_a),
|
||||
account (account_a),
|
||||
amount (amount_a),
|
||||
response (response_a)
|
||||
{
|
||||
completed.clear ();
|
||||
}
|
||||
|
||||
void nano::payment_observer::start (uint64_t timeout)
|
||||
{
|
||||
auto this_l (shared_from_this ());
|
||||
rpc.node.alarm.add (std::chrono::steady_clock::now () + std::chrono::milliseconds (timeout), [this_l]() {
|
||||
this_l->complete (nano::payment_status::nothing);
|
||||
});
|
||||
}
|
||||
|
||||
nano::payment_observer::~payment_observer ()
|
||||
{
|
||||
}
|
||||
|
||||
void nano::payment_observer::observe ()
|
||||
{
|
||||
if (rpc.node.balance (account) >= amount.number ())
|
||||
{
|
||||
complete (nano::payment_status::success);
|
||||
}
|
||||
}
|
||||
|
||||
void nano::payment_observer::complete (nano::payment_status status)
|
||||
{
|
||||
auto already (completed.test_and_set ());
|
||||
if (!already)
|
||||
{
|
||||
if (rpc.node.config.logging.log_rpc ())
|
||||
{
|
||||
rpc.node.logger.always_log (boost::str (boost::format ("Exiting payment_observer for account %1% status %2%") % account.to_account () % static_cast<unsigned> (status)));
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
case nano::payment_status::nothing:
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("deprecated", "1");
|
||||
response_l.put ("status", "nothing");
|
||||
response (response_l);
|
||||
break;
|
||||
}
|
||||
case nano::payment_status::success:
|
||||
{
|
||||
boost::property_tree::ptree response_l;
|
||||
response_l.put ("deprecated", "1");
|
||||
response_l.put ("status", "success");
|
||||
response (response_l);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
error_response (response, "Internal payment error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::lock_guard<std::mutex> lock (rpc.mutex);
|
||||
assert (rpc.payment_observers.find (account) != rpc.payment_observers.end ());
|
||||
rpc.payment_observers.erase (account);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::rpc> nano::get_rpc (boost::asio::io_context & io_ctx_a, nano::node & node_a, nano::rpc_config const & config_a)
|
||||
std::unique_ptr<nano::rpc> nano::get_rpc (boost::asio::io_context & io_ctx_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a)
|
||||
{
|
||||
std::unique_ptr<rpc> impl;
|
||||
|
||||
if (config_a.secure.enable)
|
||||
{
|
||||
#ifdef NANO_SECURE_RPC
|
||||
impl.reset (new rpc_secure (io_ctx_a, node_a, config_a));
|
||||
impl = std::make_unique<rpc_secure> (io_ctx_a, config_a, rpc_handler_interface_a);
|
||||
#else
|
||||
std::cerr << "RPC configured for TLS, but the node is not compiled with TLS support" << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
impl.reset (new rpc (io_ctx_a, node_a, config_a));
|
||||
impl = std::make_unique<rpc> (io_ctx_a, config_a, rpc_handler_interface_a);
|
||||
}
|
||||
|
||||
return impl;
|
||||
|
|
|
@ -1,74 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/beast.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/jsonconfig.hpp>
|
||||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/lib/rpc_handler_interface.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <nano/secure/blockstore.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
enum class payment_status
|
||||
{
|
||||
not_a_status,
|
||||
unknown,
|
||||
nothing, // Timeout and nothing was received
|
||||
//insufficient, // Timeout and not enough was received
|
||||
//over, // More than requested received
|
||||
//success_fork, // Amount received but it involved a fork
|
||||
success // Amount received
|
||||
};
|
||||
class wallet;
|
||||
class payment_observer;
|
||||
class rpc_handler_interface;
|
||||
|
||||
class rpc
|
||||
{
|
||||
public:
|
||||
rpc (boost::asio::io_context &, nano::node &, nano::rpc_config const &);
|
||||
virtual ~rpc () = default;
|
||||
|
||||
/**
|
||||
* Start serving RPC requests if \p rpc_enabled_a, otherwise this will only
|
||||
* add a block observer since requests may still arrive via IPC.
|
||||
*/
|
||||
void start (bool rpc_enabled_a = true);
|
||||
void add_block_observer ();
|
||||
rpc (boost::asio::io_context & io_ctx_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a);
|
||||
virtual ~rpc ();
|
||||
void start ();
|
||||
virtual void accept ();
|
||||
void stop ();
|
||||
void observer_action (nano::account const &);
|
||||
boost::asio::ip::tcp::acceptor acceptor;
|
||||
std::mutex mutex;
|
||||
std::unordered_map<nano::account, std::shared_ptr<nano::payment_observer>> payment_observers;
|
||||
nano::rpc_config config;
|
||||
nano::node & node;
|
||||
bool on;
|
||||
};
|
||||
|
||||
class payment_observer : public std::enable_shared_from_this<nano::payment_observer>
|
||||
{
|
||||
public:
|
||||
payment_observer (std::function<void(boost::property_tree::ptree const &)> const &, nano::rpc &, nano::account const &, nano::amount const &);
|
||||
~payment_observer ();
|
||||
void start (uint64_t);
|
||||
void observe ();
|
||||
void complete (nano::payment_status);
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
nano::rpc & rpc;
|
||||
nano::account account;
|
||||
nano::amount amount;
|
||||
std::function<void(boost::property_tree::ptree const &)> response;
|
||||
std::atomic_flag completed;
|
||||
nano::rpc_config config;
|
||||
boost::asio::ip::tcp::acceptor acceptor;
|
||||
nano::logger_mt logger;
|
||||
boost::asio::io_context & io_ctx;
|
||||
nano::network_constants network_constants;
|
||||
nano::rpc_handler_interface & rpc_handler_interface;
|
||||
bool stopped{ false };
|
||||
};
|
||||
|
||||
/** Returns the correct RPC implementation based on TLS configuration */
|
||||
std::unique_ptr<nano::rpc> get_rpc (boost::asio::io_context & io_ctx_a, nano::node & node_a, nano::rpc_config const & config_a);
|
||||
std::unique_ptr<nano::rpc> get_rpc (boost::asio::io_context & io_ctx_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/lib/json_error_response.hpp>
|
||||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/lib/rpc_handler_interface.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <nano/rpc/rpc_connection.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
|
||||
nano::rpc_connection::rpc_connection (nano::node & node_a, nano::rpc & rpc_a) :
|
||||
node (node_a.shared ()),
|
||||
rpc (rpc_a),
|
||||
socket (node_a.io_ctx)
|
||||
nano::rpc_connection::rpc_connection (nano::rpc_config const & rpc_config, nano::network_constants const & network_constants, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface) :
|
||||
socket (io_ctx),
|
||||
io_ctx (io_ctx),
|
||||
logger (logger),
|
||||
rpc_config (rpc_config),
|
||||
network_constants (network_constants),
|
||||
rpc_handler_interface (rpc_handler_interface)
|
||||
{
|
||||
responded.clear ();
|
||||
}
|
||||
|
@ -52,8 +58,8 @@ void nano::rpc_connection::read ()
|
|||
auto header_parser (std::make_shared<boost::beast::http::request_parser<boost::beast::http::empty_body>> ());
|
||||
std::promise<size_t> header_available_promise;
|
||||
std::future<size_t> header_available = header_available_promise.get_future ();
|
||||
header_parser->body_limit (rpc.config.max_request_size);
|
||||
if (!node->network_params.network.is_test_network ())
|
||||
header_parser->body_limit (rpc_config.max_request_size);
|
||||
if (!network_constants.is_test_network ())
|
||||
{
|
||||
boost::beast::http::async_read_header (socket, buffer, *header_parser, [this_l, header_parser, &header_available_promise, &header_error](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
size_t header_response_bytes_written = 0;
|
||||
|
@ -72,13 +78,13 @@ void nano::rpc_connection::read ()
|
|||
else
|
||||
{
|
||||
header_error = ec;
|
||||
this_l->node->logger.always_log ("RPC header error: ", ec.message ());
|
||||
this_l->logger.always_log ("RPC header error: ", ec.message ());
|
||||
}
|
||||
|
||||
header_available_promise.set_value (header_response_bytes_written);
|
||||
});
|
||||
|
||||
// Avait header
|
||||
// Await header
|
||||
header_available.get ();
|
||||
}
|
||||
|
||||
|
@ -88,32 +94,27 @@ void nano::rpc_connection::read ()
|
|||
boost::beast::http::async_read (socket, buffer, *body_parser, [this_l, body_parser](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
if (!ec)
|
||||
{
|
||||
this_l->node->background ([this_l, body_parser]() {
|
||||
// equivalent to background
|
||||
this_l->io_ctx.post ([this_l, body_parser]() {
|
||||
auto & req (body_parser->get ());
|
||||
auto start (std::chrono::steady_clock::now ());
|
||||
auto version (req.version ());
|
||||
std::string request_id (boost::str (boost::format ("%1%") % boost::io::group (std::hex, std::showbase, reinterpret_cast<uintptr_t> (this_l.get ()))));
|
||||
auto response_handler ([this_l, version, start, request_id](boost::property_tree::ptree const & tree_a) {
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, tree_a);
|
||||
ostream.flush ();
|
||||
auto body (ostream.str ());
|
||||
auto response_handler ([this_l, version, start, request_id](std::string const & tree_a) {
|
||||
auto body = tree_a;
|
||||
this_l->write_result (body, version);
|
||||
boost::beast::http::async_write (this_l->socket, this_l->res, [this_l](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
this_l->write_completion_handler (this_l);
|
||||
});
|
||||
|
||||
if (this_l->node->config.logging.log_rpc ())
|
||||
{
|
||||
this_l->node->logger.always_log (boost::str (boost::format ("RPC request %2% completed in: %1% microseconds") % std::chrono::duration_cast<std::chrono::microseconds> (std::chrono::steady_clock::now () - start).count () % request_id));
|
||||
}
|
||||
this_l->logger.always_log (boost::str (boost::format ("RPC request %2% completed in: %1% microseconds") % std::chrono::duration_cast<std::chrono::microseconds> (std::chrono::steady_clock::now () - start).count () % request_id));
|
||||
});
|
||||
auto method = req.method ();
|
||||
switch (method)
|
||||
{
|
||||
case boost::beast::http::verb::post:
|
||||
{
|
||||
auto handler (std::make_shared<nano::rpc_handler> (*this_l->node, this_l->rpc, req.body (), request_id, response_handler));
|
||||
auto handler (std::make_shared<nano::rpc_handler> (this_l->rpc_config, req.body (), request_id, response_handler, this_l->rpc_handler_interface, this_l->logger));
|
||||
handler->process_request ();
|
||||
break;
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ void nano::rpc_connection::read ()
|
|||
}
|
||||
default:
|
||||
{
|
||||
error_response (response_handler, "Can only POST requests");
|
||||
json_error_response (response_handler, "Can only POST requests");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -136,28 +137,24 @@ void nano::rpc_connection::read ()
|
|||
}
|
||||
else
|
||||
{
|
||||
this_l->node->logger.always_log ("RPC read error: ", ec.message ());
|
||||
this_l->logger.always_log ("RPC read error: ", ec.message ());
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Respond with the reason for the invalid header
|
||||
auto response_handler ([this_l](boost::property_tree::ptree const & tree_a) {
|
||||
std::stringstream ostream;
|
||||
boost::property_tree::write_json (ostream, tree_a);
|
||||
ostream.flush ();
|
||||
auto body (ostream.str ());
|
||||
this_l->write_result (body, 11);
|
||||
auto response_handler ([this_l](std::string const & tree_a) {
|
||||
this_l->write_result (tree_a, 11);
|
||||
boost::beast::http::async_write (this_l->socket, this_l->res, [this_l](boost::system::error_code const & ec, size_t bytes_transferred) {
|
||||
this_l->write_completion_handler (this_l);
|
||||
});
|
||||
});
|
||||
error_response (response_handler, std::string ("Invalid header: ") + header_error.message ());
|
||||
json_error_response (response_handler, std::string ("Invalid header: ") + header_error.message ());
|
||||
}
|
||||
}
|
||||
|
||||
void nano::rpc_connection::write_completion_handler (std::shared_ptr<nano::rpc_connection> rpc_connection)
|
||||
{
|
||||
// Intentional no-op
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,26 +2,34 @@
|
|||
|
||||
#include <atomic>
|
||||
#include <boost/beast.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class rpc;
|
||||
class logger_mt;
|
||||
class rpc_config;
|
||||
class rpc_handler_interface;
|
||||
class network_constants;
|
||||
|
||||
class rpc_connection : public std::enable_shared_from_this<nano::rpc_connection>
|
||||
{
|
||||
public:
|
||||
rpc_connection (nano::node &, nano::rpc &);
|
||||
rpc_connection (nano::rpc_config const & rpc_config, nano::network_constants const & network_constants, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface_a);
|
||||
virtual ~rpc_connection () = default;
|
||||
virtual void parse_connection ();
|
||||
virtual void write_completion_handler (std::shared_ptr<nano::rpc_connection> rpc_connection);
|
||||
virtual void prepare_head (unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
virtual void write_result (std::string body, unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
void prepare_head (unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
void write_result (std::string body, unsigned version, boost::beast::http::status status = boost::beast::http::status::ok);
|
||||
void read ();
|
||||
std::shared_ptr<nano::node> node;
|
||||
nano::rpc & rpc;
|
||||
|
||||
boost::asio::ip::tcp::socket socket;
|
||||
boost::beast::flat_buffer buffer;
|
||||
boost::beast::http::response<boost::beast::http::string_body> res;
|
||||
std::atomic_flag responded;
|
||||
boost::asio::io_context & io_ctx;
|
||||
nano::logger_mt & logger;
|
||||
nano::rpc_config const & rpc_config;
|
||||
nano::network_constants const & network_constants;
|
||||
nano::rpc_handler_interface & rpc_handler_interface;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include <boost/polymorphic_pointer_cast.hpp>
|
||||
|
||||
nano::rpc_connection_secure::rpc_connection_secure (nano::node & node_a, nano::rpc_secure & rpc_a) :
|
||||
nano::rpc_connection (node_a, rpc_a),
|
||||
stream (socket, rpc_a.ssl_context)
|
||||
nano::rpc_connection_secure::rpc_connection_secure (nano::rpc_config const & rpc_config, nano::network_constants const & network_constants, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface, boost::asio::ssl::context & ssl_context) :
|
||||
nano::rpc_connection (rpc_config, network_constants, io_ctx, logger, rpc_handler_interface),
|
||||
stream (socket, ssl_context)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ void nano::rpc_connection_secure::handle_handshake (const boost::system::error_c
|
|||
}
|
||||
else
|
||||
{
|
||||
node->logger.always_log ("TLS: Handshake error: ", error.message ());
|
||||
logger.always_log ("TLS: Handshake error: ", error.message ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
namespace nano
|
||||
{
|
||||
class rpc_secure;
|
||||
/**
|
||||
* Specialization of nano::rpc_connection for establishing TLS connections.
|
||||
* Handshakes with client certificates are supported.
|
||||
|
@ -13,7 +12,7 @@ class rpc_secure;
|
|||
class rpc_connection_secure : public rpc_connection
|
||||
{
|
||||
public:
|
||||
rpc_connection_secure (nano::node &, nano::rpc_secure &);
|
||||
rpc_connection_secure (nano::rpc_config const & rpc_config, nano::network_constants const & network_constants, boost::asio::io_context & io_ctx, nano::logger_mt & logger, nano::rpc_handler_interface & rpc_handler_interface_a, boost::asio::ssl::context & ssl_context);
|
||||
void parse_connection () override;
|
||||
void write_completion_handler (std::shared_ptr<nano::rpc_connection> rpc) override;
|
||||
/** The TLS handshake callback */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,158 +2,28 @@
|
|||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <functional>
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/node/wallet.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
class rpc;
|
||||
void error_response (std::function<void(boost::property_tree::ptree const &)> response_a, std::string const & message_a);
|
||||
class rpc_config;
|
||||
class rpc_handler_interface;
|
||||
class logger_mt;
|
||||
|
||||
class rpc_handler : public std::enable_shared_from_this<nano::rpc_handler>
|
||||
{
|
||||
public:
|
||||
rpc_handler (nano::node &, nano::rpc &, std::string const &, std::string const &, std::function<void(boost::property_tree::ptree const &)> const &);
|
||||
rpc_handler (nano::rpc_config const & rpc_config, std::string const & body_a, std::string const & request_id_a, std::function<void(std::string const &)> const & response_a, nano::rpc_handler_interface & rpc_handler_interface_a, nano::logger_mt & logger);
|
||||
void process_request ();
|
||||
void read (std::shared_ptr<std::vector<uint8_t>> req, std::shared_ptr<std::vector<uint8_t>> res, const std::string & action);
|
||||
|
||||
/**
|
||||
* Process http request
|
||||
* @param unsafe If true, the caller requests an unsafe action. This will be granted only if the config allows it.
|
||||
*/
|
||||
void process_request (bool unsafe = false);
|
||||
void account_balance ();
|
||||
void account_block_count ();
|
||||
void account_count ();
|
||||
void account_create ();
|
||||
void account_get ();
|
||||
void account_history ();
|
||||
void account_info ();
|
||||
void account_key ();
|
||||
void account_list ();
|
||||
void account_move ();
|
||||
void account_remove ();
|
||||
void account_representative ();
|
||||
void account_representative_set ();
|
||||
void account_weight ();
|
||||
void accounts_balances ();
|
||||
void accounts_create ();
|
||||
void accounts_frontiers ();
|
||||
void accounts_pending ();
|
||||
void active_difficulty ();
|
||||
void available_supply ();
|
||||
void block_info ();
|
||||
void block_confirm ();
|
||||
void blocks ();
|
||||
void blocks_info ();
|
||||
void block_account ();
|
||||
void block_count ();
|
||||
void block_count_type ();
|
||||
void block_create ();
|
||||
void block_hash ();
|
||||
void bootstrap ();
|
||||
void bootstrap_any ();
|
||||
void bootstrap_lazy ();
|
||||
void bootstrap_status ();
|
||||
void chain (bool = false);
|
||||
void confirmation_active ();
|
||||
void confirmation_history ();
|
||||
void confirmation_info ();
|
||||
void confirmation_quorum ();
|
||||
void delegators ();
|
||||
void delegators_count ();
|
||||
void deterministic_key ();
|
||||
void frontiers ();
|
||||
void keepalive ();
|
||||
void key_create ();
|
||||
void key_expand ();
|
||||
void ledger ();
|
||||
void mnano_to_raw (nano::uint128_t = nano::Mxrb_ratio);
|
||||
void mnano_from_raw (nano::uint128_t = nano::Mxrb_ratio);
|
||||
void node_id ();
|
||||
void node_id_delete ();
|
||||
void password_change ();
|
||||
void password_enter ();
|
||||
void password_valid (bool = false);
|
||||
void payment_begin ();
|
||||
void payment_init ();
|
||||
void payment_end ();
|
||||
void payment_wait ();
|
||||
void peers ();
|
||||
void pending ();
|
||||
void pending_exists ();
|
||||
void process ();
|
||||
void receive ();
|
||||
void receive_minimum ();
|
||||
void receive_minimum_set ();
|
||||
void representatives ();
|
||||
void representatives_online ();
|
||||
void republish ();
|
||||
void search_pending ();
|
||||
void search_pending_all ();
|
||||
void send ();
|
||||
void sign ();
|
||||
void stats ();
|
||||
void stats_clear ();
|
||||
void stop ();
|
||||
void unchecked ();
|
||||
void unchecked_clear ();
|
||||
void unchecked_get ();
|
||||
void unchecked_keys ();
|
||||
void unopened ();
|
||||
void uptime ();
|
||||
void validate_account_number ();
|
||||
void version ();
|
||||
void wallet_add ();
|
||||
void wallet_add_watch ();
|
||||
void wallet_balances ();
|
||||
void wallet_change_seed ();
|
||||
void wallet_contains ();
|
||||
void wallet_create ();
|
||||
void wallet_destroy ();
|
||||
void wallet_export ();
|
||||
void wallet_frontiers ();
|
||||
void wallet_history ();
|
||||
void wallet_info ();
|
||||
void wallet_key_valid ();
|
||||
void wallet_ledger ();
|
||||
void wallet_lock ();
|
||||
void wallet_pending ();
|
||||
void wallet_representative ();
|
||||
void wallet_representative_set ();
|
||||
void wallet_republish ();
|
||||
void wallet_seed ();
|
||||
void wallet_work_get ();
|
||||
void work_generate ();
|
||||
void work_cancel ();
|
||||
void work_get ();
|
||||
void work_set ();
|
||||
void work_validate ();
|
||||
void work_peer_add ();
|
||||
void work_peers ();
|
||||
void work_peers_clear ();
|
||||
private:
|
||||
std::string body;
|
||||
std::string request_id;
|
||||
nano::node & node;
|
||||
nano::rpc & rpc;
|
||||
boost::property_tree::ptree request;
|
||||
std::function<void(boost::property_tree::ptree const &)> response;
|
||||
void response_errors ();
|
||||
std::error_code ec;
|
||||
boost::property_tree::ptree response_l;
|
||||
std::shared_ptr<nano::wallet> wallet_impl ();
|
||||
bool wallet_locked_impl (nano::transaction const &, std::shared_ptr<nano::wallet>);
|
||||
bool wallet_account_impl (nano::transaction const &, std::shared_ptr<nano::wallet>, nano::account const &);
|
||||
nano::account account_impl (std::string = "");
|
||||
nano::amount amount_impl ();
|
||||
std::shared_ptr<nano::block> block_impl (bool = true);
|
||||
std::shared_ptr<nano::block> block_json_impl (bool = true);
|
||||
nano::block_hash hash_impl (std::string = "hash");
|
||||
nano::amount threshold_optional_impl ();
|
||||
uint64_t work_optional_impl ();
|
||||
uint64_t count_impl ();
|
||||
uint64_t count_optional_impl (uint64_t = std::numeric_limits<uint64_t>::max ());
|
||||
uint64_t offset_optional_impl (uint64_t = 0);
|
||||
bool rpc_control_impl ();
|
||||
std::function<void(std::string const &)> response;
|
||||
nano::rpc_config const & rpc_config;
|
||||
nano::rpc_handler_interface & rpc_handler_interface;
|
||||
nano::logger_mt & logger;
|
||||
};
|
||||
}
|
||||
|
|
178
nano/rpc/rpc_request_processor.cpp
Normal file
178
nano/rpc/rpc_request_processor.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
#include <nano/lib/json_error_response.hpp>
|
||||
#include <nano/rpc/rpc_request_processor.hpp>
|
||||
|
||||
nano::rpc_request_processor::rpc_request_processor (boost::asio::io_context & io_ctx, nano::rpc_config & rpc_config) :
|
||||
ipc_address (rpc_config.address.to_string ()),
|
||||
ipc_port (rpc_config.ipc_port),
|
||||
thread ([this]() {
|
||||
nano::thread_role::set (nano::thread_role::name::rpc_request_processor);
|
||||
this->run ();
|
||||
})
|
||||
{
|
||||
std::lock_guard<std::mutex> lk (this->request_mutex);
|
||||
this->connections.reserve (rpc_config.num_ipc_connections);
|
||||
for (auto i = 0u; i < rpc_config.num_ipc_connections; ++i)
|
||||
{
|
||||
connections.push_back (std::make_shared<nano::ipc_connection> (nano::ipc::ipc_client (io_ctx), false));
|
||||
auto connection = this->connections.back ();
|
||||
// clang-format off
|
||||
connection->client.async_connect (ipc_address, ipc_port, [ connection, &connections_mutex = this->connections_mutex ](nano::error err) {
|
||||
// Even if there is an error this needs to be set so that another attempt can be made to connect with the ipc connection
|
||||
std::lock_guard<std::mutex> lk (connections_mutex);
|
||||
connection->is_available = true;
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
nano::rpc_request_processor::~rpc_request_processor ()
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
void nano::rpc_request_processor::stop ()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock (request_mutex);
|
||||
stopped = true;
|
||||
}
|
||||
condition.notify_one ();
|
||||
if (thread.joinable ())
|
||||
{
|
||||
thread.join ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::rpc_request_processor::add (std::shared_ptr<rpc_request> request)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lk (request_mutex);
|
||||
requests.push_back (request);
|
||||
}
|
||||
condition.notify_one ();
|
||||
}
|
||||
|
||||
void nano::rpc_request_processor::read_payload (std::shared_ptr<nano::ipc_connection> connection, std::shared_ptr<std::vector<uint8_t>> res, std::shared_ptr<nano::rpc_request> rpc_request)
|
||||
{
|
||||
uint32_t payload_size_l = boost::endian::big_to_native (*reinterpret_cast<uint32_t *> (res->data ()));
|
||||
res->resize (payload_size_l);
|
||||
// Read JSON payload
|
||||
connection->client.async_read (res, payload_size_l, [this, connection, res, rpc_request](nano::error err_read_a, size_t size_read_a) {
|
||||
// We need 2 sequential reads to get both the header and payload, so only allow other writes
|
||||
// when they have both been read.
|
||||
make_available (*connection);
|
||||
if (!err_read_a && size_read_a != 0)
|
||||
{
|
||||
rpc_request->response (std::string (res->begin (), res->end ()));
|
||||
if (rpc_request->action == "stop")
|
||||
{
|
||||
this->stop_callback ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_error_response (rpc_request->response, "Failed to read payload");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nano::rpc_request_processor::make_available (nano::ipc_connection & connection)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk (connections_mutex);
|
||||
connection.is_available = true; // Allow people to use it now
|
||||
}
|
||||
|
||||
// Connection does not exist or has been closed, try to connect to it again and then resend IPC request
|
||||
void nano::rpc_request_processor::try_reconnect_and_execute_request (std::shared_ptr<nano::ipc_connection> connection, std::shared_ptr<std::vector<uint8_t>> req, std::shared_ptr<std::vector<uint8_t>> res, std::shared_ptr<nano::rpc_request> rpc_request)
|
||||
{
|
||||
connection->client.async_connect (ipc_address, ipc_port, [this, connection, req, res, rpc_request](nano::error err) {
|
||||
if (!err)
|
||||
{
|
||||
connection->client.async_write (req, [this, connection, res, rpc_request](nano::error err_a, size_t size_a) {
|
||||
if (size_a != 0 && !err_a)
|
||||
{
|
||||
// Read length
|
||||
connection->client.async_read (res, sizeof (uint32_t), [this, connection, res, rpc_request](nano::error err_read_a, size_t size_read_a) {
|
||||
if (size_read_a != 0 && !err_read_a)
|
||||
{
|
||||
this->read_payload (connection, res, rpc_request);
|
||||
}
|
||||
else
|
||||
{
|
||||
json_error_response (rpc_request->response, "Connection to node has failed");
|
||||
make_available (*connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
json_error_response (rpc_request->response, "Cannot write to the node");
|
||||
make_available (*connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
json_error_response (rpc_request->response, "There is a problem connecting to the node. Make sure ipc->tcp is enabled in node config and ports match");
|
||||
make_available (*connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void nano::rpc_request_processor::run ()
|
||||
{
|
||||
// This should be a conditioned wait
|
||||
std::unique_lock<std::mutex> lk (request_mutex);
|
||||
while (!stopped)
|
||||
{
|
||||
if (!requests.empty ())
|
||||
{
|
||||
lk.unlock ();
|
||||
std::unique_lock<std::mutex> conditions_lk (connections_mutex);
|
||||
// Find the first free ipc_client
|
||||
auto it = std::find_if (connections.begin (), connections.end (), [](auto connection) -> bool {
|
||||
return connection->is_available;
|
||||
});
|
||||
|
||||
if (it != connections.cend ())
|
||||
{
|
||||
// Successfully found one
|
||||
lk.lock ();
|
||||
auto rpc_request = requests.front ();
|
||||
requests.pop_front ();
|
||||
lk.unlock ();
|
||||
auto connection = *it;
|
||||
connection->is_available = false; // Make sure no one else can take it
|
||||
conditions_lk.unlock ();
|
||||
auto req (nano::ipc::prepare_request (nano::ipc::payload_encoding::json_legacy, rpc_request->body));
|
||||
auto res (std::make_shared<std::vector<uint8_t>> ());
|
||||
|
||||
// Have we tried to connect yet?
|
||||
connection->client.async_write (req, [this, connection, req, res, rpc_request](nano::error err_a, size_t size_a) {
|
||||
if (!err_a)
|
||||
{
|
||||
connection->client.async_read (res, sizeof (uint32_t), [this, connection, req, res, rpc_request](nano::error err_read_a, size_t size_read_a) {
|
||||
if (size_read_a != 0 && !err_read_a)
|
||||
{
|
||||
this->read_payload (connection, res, rpc_request);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->try_reconnect_and_execute_request (connection, req, res, rpc_request);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
try_reconnect_and_execute_request (connection, req, res, rpc_request);
|
||||
}
|
||||
});
|
||||
}
|
||||
lk.lock ();
|
||||
}
|
||||
else
|
||||
{
|
||||
condition.wait (lk);
|
||||
}
|
||||
}
|
||||
}
|
92
nano/rpc/rpc_request_processor.hpp
Normal file
92
nano/rpc/rpc_request_processor.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/ipc_client.hpp>
|
||||
#include <nano/lib/rpc_handler_interface.hpp>
|
||||
#include <nano/lib/rpcconfig.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/rpc/rpc.hpp>
|
||||
#include <nano/rpc/rpc_handler.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
struct ipc_connection
|
||||
{
|
||||
ipc_connection (nano::ipc::ipc_client && client_a, bool is_available_a) :
|
||||
client (std::move (client_a)), is_available (is_available_a)
|
||||
{
|
||||
}
|
||||
|
||||
nano::ipc::ipc_client client;
|
||||
bool is_available{ false };
|
||||
};
|
||||
|
||||
struct rpc_request
|
||||
{
|
||||
rpc_request (const std::string & action_a, const std::string & body_a, std::function<void(std::string const &)> response_a) :
|
||||
action (action_a), body (body_a), response (response_a)
|
||||
{
|
||||
}
|
||||
|
||||
std::string action;
|
||||
std::string body;
|
||||
std::function<void(std::string const &)> response;
|
||||
};
|
||||
|
||||
class rpc_request_processor
|
||||
{
|
||||
public:
|
||||
rpc_request_processor (boost::asio::io_context & io_ctx, nano::rpc_config & rpc_config);
|
||||
~rpc_request_processor ();
|
||||
void stop ();
|
||||
void add (std::shared_ptr<rpc_request> request);
|
||||
std::function<void()> stop_callback;
|
||||
|
||||
private:
|
||||
void run ();
|
||||
void read_payload (std::shared_ptr<nano::ipc_connection> connection, std::shared_ptr<std::vector<uint8_t>> res, std::shared_ptr<nano::rpc_request> rpc_request);
|
||||
void try_reconnect_and_execute_request (std::shared_ptr<nano::ipc_connection> connection, std::shared_ptr<std::vector<uint8_t>> req, std::shared_ptr<std::vector<uint8_t>> res, std::shared_ptr<nano::rpc_request> rpc_request);
|
||||
void make_available (nano::ipc_connection & connection);
|
||||
|
||||
std::vector<std::shared_ptr<nano::ipc_connection>> connections;
|
||||
std::mutex request_mutex;
|
||||
std::mutex connections_mutex;
|
||||
bool stopped{ false };
|
||||
std::deque<std::shared_ptr<nano::rpc_request>> requests;
|
||||
std::condition_variable condition;
|
||||
const std::string ipc_address;
|
||||
const uint16_t ipc_port;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
class ipc_rpc_processor final : public nano::rpc_handler_interface
|
||||
{
|
||||
public:
|
||||
ipc_rpc_processor (boost::asio::io_context & io_ctx, nano::rpc_config & rpc_config) :
|
||||
rpc_request_processor (io_ctx, rpc_config)
|
||||
{
|
||||
}
|
||||
|
||||
void process_request (std::string const & action_a, std::string const & body_a, std::function<void(std::string const &)> response_a) override
|
||||
{
|
||||
rpc_request_processor.add (std::make_shared<nano::rpc_request> (action_a, body_a, response_a));
|
||||
}
|
||||
|
||||
void stop () override
|
||||
{
|
||||
rpc_request_processor.stop ();
|
||||
}
|
||||
|
||||
void rpc_instance (nano::rpc & rpc) override
|
||||
{
|
||||
rpc_request_processor.stop_callback = [&rpc]() {
|
||||
rpc.stop ();
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
nano::rpc_request_processor rpc_request_processor;
|
||||
};
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <nano/node/node.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/polymorphic_pointer_cast.hpp>
|
||||
#include <nano/rpc/rpc_connection_secure.hpp>
|
||||
#include <nano/rpc/rpc_secure.hpp>
|
||||
|
||||
|
@ -9,27 +10,27 @@ bool nano::rpc_secure::on_verify_certificate (bool preverified, boost::asio::ssl
|
|||
switch (error)
|
||||
{
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
node.logger.always_log ("TLS: Unable to get issuer");
|
||||
logger.always_log ("TLS: Unable to get issuer");
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
node.logger.always_log ("TLS: Certificate not yet valid");
|
||||
logger.always_log ("TLS: Certificate not yet valid");
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
node.logger.always_log ("TLS: Certificate expired");
|
||||
logger.always_log ("TLS: Certificate expired");
|
||||
break;
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
if (config.secure.verbose_logging)
|
||||
{
|
||||
node.logger.always_log ("TLS: self signed certificate in chain");
|
||||
logger.always_log ("TLS: self signed certificate in chain");
|
||||
}
|
||||
|
||||
// Allow self-signed certificates
|
||||
preverified = true;
|
||||
break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
node.logger.always_log ("TLS: Self signed certificate not in the list of trusted certs (forgot to subject-hash certificate filename?)");
|
||||
logger.always_log ("TLS: Self signed certificate not in the list of trusted certs (forgot to subject-hash certificate filename?)");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -39,19 +40,19 @@ bool nano::rpc_secure::on_verify_certificate (bool preverified, boost::asio::ssl
|
|||
{
|
||||
if (error != 0)
|
||||
{
|
||||
node.logger.always_log ("TLS: Error: ", X509_verify_cert_error_string (error));
|
||||
node.logger.always_log ("TLS: Error chain depth : ", X509_STORE_CTX_get_error_depth (cts));
|
||||
logger.always_log ("TLS: Error: ", X509_verify_cert_error_string (error));
|
||||
logger.always_log ("TLS: Error chain depth : ", X509_STORE_CTX_get_error_depth (cts));
|
||||
}
|
||||
|
||||
X509 * cert = X509_STORE_CTX_get_current_cert (cts);
|
||||
char subject_name[512];
|
||||
X509_NAME_oneline (X509_get_subject_name (cert), subject_name, sizeof (subject_name) - 1);
|
||||
node.logger.always_log ("TLS: Verifying: ", subject_name);
|
||||
node.logger.always_log ("TLS: Verification: ", preverified);
|
||||
logger.always_log ("TLS: Verifying: ", subject_name);
|
||||
logger.always_log ("TLS: Verification: ", preverified);
|
||||
}
|
||||
else if (!preverified)
|
||||
{
|
||||
node.logger.always_log ("TLS: Pre-verification failed. Turn on verbose logging for more information.");
|
||||
logger.always_log ("TLS: Pre-verification failed. Turn on verbose logging for more information.");
|
||||
}
|
||||
|
||||
return preverified;
|
||||
|
@ -89,8 +90,8 @@ void nano::rpc_secure::load_certs (boost::asio::ssl::context & context_a)
|
|||
}
|
||||
}
|
||||
|
||||
nano::rpc_secure::rpc_secure (boost::asio::io_service & service_a, nano::node & node_a, nano::rpc_config const & config_a) :
|
||||
rpc (service_a, node_a, config_a),
|
||||
nano::rpc_secure::rpc_secure (boost::asio::io_service & service_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a) :
|
||||
rpc (service_a, config_a, rpc_handler_interface_a),
|
||||
ssl_context (boost::asio::ssl::context::tlsv12_server)
|
||||
{
|
||||
load_certs (ssl_context);
|
||||
|
@ -98,7 +99,7 @@ ssl_context (boost::asio::ssl::context::tlsv12_server)
|
|||
|
||||
void nano::rpc_secure::accept ()
|
||||
{
|
||||
auto connection (std::make_shared<nano::rpc_connection_secure> (node, *this));
|
||||
auto connection (std::make_shared<nano::rpc_connection_secure> (config, network_constants, io_ctx, logger, rpc_handler_interface, this->ssl_context));
|
||||
acceptor.async_accept (connection->socket, [this, connection](boost::system::error_code const & ec) {
|
||||
if (acceptor.is_open ())
|
||||
{
|
||||
|
@ -110,7 +111,7 @@ void nano::rpc_secure::accept ()
|
|||
}
|
||||
else
|
||||
{
|
||||
this->node.logger.always_log (boost::str (boost::format ("Error accepting RPC connections: %1%") % ec));
|
||||
logger.always_log (boost::str (boost::format ("Error accepting RPC connections: %1%") % ec));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace nano
|
|||
class rpc_secure : public rpc
|
||||
{
|
||||
public:
|
||||
rpc_secure (boost::asio::io_service & service_a, nano::node & node_a, nano::rpc_config const & config_a);
|
||||
rpc_secure (boost::asio::io_service & service_a, nano::rpc_config const & config_a, nano::rpc_handler_interface & rpc_handler_interface_a);
|
||||
|
||||
/** Starts accepting connections */
|
||||
void accept () override;
|
||||
|
|
|
@ -2,7 +2,7 @@ add_executable (rpc_test
|
|||
entry.cpp
|
||||
rpc.cpp)
|
||||
|
||||
target_link_libraries(rpc_test gtest rpc)
|
||||
target_link_libraries(rpc_test gtest rpc node)
|
||||
|
||||
target_compile_definitions(rpc_test
|
||||
PUBLIC
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <nano/secure/utility.hpp>
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
void force_nano_test_network ();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,6 @@ int main (int argc, char ** argv)
|
|||
nano::force_nano_test_network ();
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanp_test_directories_on_exit ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
return res;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -110,16 +110,3 @@ void nano::remove_temporary_directories ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nano::cleanp_test_directories_on_exit ()
|
||||
{
|
||||
// Makes sure everything is cleaned up
|
||||
nano::logging::release_file_sink ();
|
||||
// Clean up tmp directories created by the tests. Since it's sometimes useful to
|
||||
// see log files after test failures, an environment variable is supported to
|
||||
// retain the files.
|
||||
if (std::getenv ("TEST_KEEP_TMPDIRS") == nullptr)
|
||||
{
|
||||
nano::remove_temporary_directories ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,5 +29,4 @@ bool migrate_working_path (std::string &);
|
|||
boost::filesystem::path unique_path ();
|
||||
// Remove all unique tmp directories created by the process
|
||||
void remove_temporary_directories ();
|
||||
void cleanp_test_directories_on_exit ();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <nano/secure/utility.hpp>
|
||||
namespace nano
|
||||
{
|
||||
void cleanup_test_directories_on_exit ();
|
||||
void force_nano_test_network ();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,6 @@ int main (int argc, char ** argv)
|
|||
nano::force_nano_test_network ();
|
||||
testing::InitGoogleTest (&argc, argv);
|
||||
auto res = RUN_ALL_TESTS ();
|
||||
nano::cleanp_test_directories_on_exit ();
|
||||
nano::cleanup_test_directories_on_exit ();
|
||||
return res;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue