rpc: WIP network transports, and darkfid skeleton for further integration.

This commit is contained in:
parazyd
2022-04-11 18:43:54 +02:00
parent ab7eb937ad
commit a3ed95ab79
11 changed files with 420 additions and 2 deletions

1
.gitignore vendored
View File

@@ -9,6 +9,7 @@
/dao-cli
/daod
/darkfid
/darkfid2
/dnetview
/drk
/gatewayd

156
Cargo.lock generated
View File

@@ -773,6 +773,12 @@ dependencies = [
"syn 1.0.91",
]
[[package]]
name = "bytecount"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
[[package]]
name = "bytemuck"
version = "1.9.1"
@@ -832,6 +838,15 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]]
name = "camino"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f3132262930b0522068049f5870a856ab8affc80c70d08b6ecb785771a6fc23"
dependencies = [
"serde",
]
[[package]]
name = "caps"
version = "0.5.3"
@@ -843,6 +858,28 @@ dependencies = [
"thiserror",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
dependencies = [
"camino",
"cargo-platform",
"semver 1.0.7",
"serde",
"serde_json",
]
[[package]]
name = "cashierd"
version = "0.3.0"
@@ -1669,6 +1706,27 @@ dependencies = [
"url",
]
[[package]]
name = "darkfid2"
version = "0.3.0"
dependencies = [
"async-channel",
"async-executor",
"async-std",
"async-trait",
"darkfi",
"easy-parallel",
"futures-lite",
"log",
"serde",
"serde_derive",
"serde_json",
"simplelog",
"structopt",
"structopt-toml",
"url",
]
[[package]]
name = "darling"
version = "0.10.2"
@@ -2189,6 +2247,15 @@ dependencies = [
"libc",
]
[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"version_check",
]
[[package]]
name = "event-listener"
version = "2.5.2"
@@ -4100,6 +4167,17 @@ dependencies = [
"syn 1.0.91",
]
[[package]]
name = "pulldown-cmark"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
dependencies = [
"bitflags",
"memchr",
"unicase",
]
[[package]]
name = "qstring"
version = "0.7.2"
@@ -4884,6 +4962,9 @@ name = "semver"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
dependencies = [
"serde",
]
[[package]]
name = "semver-parser"
@@ -5111,6 +5192,21 @@ dependencies = [
"typenum",
]
[[package]]
name = "skeptic"
version = "0.13.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
dependencies = [
"bytecount",
"cargo_metadata",
"error-chain",
"glob",
"pulldown-cmark",
"tempfile",
"walkdir",
]
[[package]]
name = "slab"
version = "0.4.6"
@@ -6045,6 +6141,57 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap 2.34.0",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck 0.3.3",
"proc-macro-error",
"proc-macro2 1.0.37",
"quote 1.0.17",
"syn 1.0.91",
]
[[package]]
name = "structopt-toml"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27d68c57e6cc3fb03041c49534e50a6ccef677c511effc1c5bf12a4bc865a62"
dependencies = [
"anyhow",
"clap 2.34.0",
"serde",
"serde_derive",
"skeptic",
"structopt",
"structopt-toml-derive",
"toml",
]
[[package]]
name = "structopt-toml-derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "316302a563af68baf93e5e77b8355a8bfe168c67c4424623365ca5bf521d013e"
dependencies = [
"proc-macro2 1.0.37",
"quote 1.0.17",
"syn 1.0.91",
]
[[package]]
name = "subtle"
version = "2.4.1"
@@ -6537,6 +6684,15 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-bidi"
version = "0.3.7"

View File

@@ -16,6 +16,7 @@ members = [
"bin/zkas",
"bin/cashierd",
"bin/darkfid",
"bin/darkfid2",
"bin/drk",
"bin/gatewayd",
"bin/ircd",

28
bin/darkfid2/Cargo.toml Normal file
View File

@@ -0,0 +1,28 @@
[package]
name = "darkfid2"
version = "0.3.0"
homepage = "https://dark.fi"
description = "DarkFi node daemon"
authors = ["darkfi <dev@dark.fi>"]
repository = "https://github.com/darkrenaissance/darkfi"
license = "AGPL-3.0-only"
edition = "2021"
[dependencies]
async-channel = "1.6.1"
async-executor = "1.4.1"
async-std = "1.11.0"
async-trait = "0.1.53"
darkfi = {path = "../../", features = ["crypto", "rpc", "net"]}
easy-parallel = "3.2.0"
futures-lite = "1.12.0"
log = "0.4.16"
serde_json = "1.0.79"
simplelog = "0.12.0-alpha1"
url = "2.2.2"
# Argument parsing
serde = "1.0.136"
serde_derive = "1.0.136"
structopt = "0.3.26"
structopt-toml = "0.5.0"

View File

@@ -0,0 +1,14 @@
## darkfid configuration file
##
## Please make sure you go through all the settings so you can configure
## your daemon properly.
# Path to the client database
#database_path = "~/.config/darkfi/darkfid_client.db"
# Path to the wallet database
#wallet_path = "~/.config/darkfi/darkfid_wallet.db"
# JSON-RPC listening url
#rpc_listen = "tcp://127.0.0.1:5397"
#rpc_listen = "tls://127.0.0.1:5397"

111
bin/darkfid2/src/main.rs Normal file
View File

@@ -0,0 +1,111 @@
use async_executor::Executor;
use async_std::sync::Arc;
use async_trait::async_trait;
use easy_parallel::Parallel;
use futures_lite::future;
use serde_derive::Deserialize;
use serde_json::{json, Value};
use simplelog::{ColorChoice, TermLogger, TerminalMode};
use structopt::StructOpt;
use structopt_toml::StructOptToml;
use url::Url;
use darkfi::{
cli_desc,
net::transport::{TcpTransport, TlsTransport},
rpc::{
jsonrpc,
jsonrpc::{ErrorCode, JsonRequest, JsonResult},
rpcserver2::{listen_and_serve, RequestHandler},
},
util::{
cli::{log_config, spawn_config},
path::get_config_path,
},
Error, Result,
};
const CONFIG_FILE: &str = "darkfid_config.toml";
const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml");
#[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
#[serde(default)]
#[structopt(name = "darkfid", about = cli_desc!())]
struct Args {
#[structopt(short, long)]
/// Configuration file to use
config: Option<String>,
#[structopt(long, default_value = "~/.config/darkfi/darkfid_client.db")]
/// Path to the client database
database_path: String,
#[structopt(long, default_value = "~/.config/darkfi/darkfid_wallet.db")]
/// Path to the wallet database
wallet_path: String,
#[structopt(long, default_value = "tcp://127.0.0.1:5397")]
/// JSON-RPC listen URL
rpc_listen: String,
#[structopt(short, parse(from_occurrences))]
/// Increase verbosity (-vvv supported)
verbose: u8,
}
pub struct Darkfid;
#[async_trait]
impl RequestHandler for Darkfid {
async fn handle_request(&self, req: JsonRequest) -> JsonResult {
if req.params.as_array().is_none() {
return jsonrpc::error(ErrorCode::InvalidParams, None, req.id).into()
}
match req.method.as_str() {
Some("ping") => return self.pong(req.id, req.params).await,
Some(_) | None => return jsonrpc::error(ErrorCode::MethodNotFound, None, req.id).into(),
}
}
}
impl Darkfid {
// RPCAPI:
// Returns a `pong` to the `ping` request.
// --> {"jsonrpc":"2.0","method":"ping","params":[],"id":1}
// <-- {"jsonrpc":"2.0","result":"pong","id":1}
async fn pong(&self, id: Value, _params: Value) -> JsonResult {
jsonrpc::response(json!("pong"), id).into()
}
}
fn main() -> Result<()> {
let args = Args::from_args_with_toml("").unwrap();
let cfg_path = get_config_path(args.config.clone(), CONFIG_FILE)?;
spawn_config(&cfg_path, CONFIG_FILE_CONTENTS.as_bytes())?;
let args = Args::from_args_with_toml(&std::fs::read_to_string(cfg_path)?).unwrap();
let (lvl, conf) = log_config(args.verbose.into())?;
TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
// Validate args
let ex = Executor::new();
let (signal, shutdown) = async_channel::unbounded::<()>();
// // https://docs.rs/smol/latest/smol/struct.Executor.html#examples
// let (_, result) = Parallel::new()
// // Run four executor threads
// .each(0..4, |_| future::block_on(ex.run(shutdown.recv())))
// // Run the main future on the current thread.
// .finish(|| {
// future::block_on(async {
// realmain(args).await?;
// drop(signal);
// Ok::<(), darkfi::Error>(())
// })
// });
// result
Ok(())
}

View File

@@ -12,7 +12,7 @@ use serde::{
ser::Serializer,
Deserialize, Serialize,
};
use subtle::{ConstantTimeEq, CtOption};
use subtle::CtOption;
use crate::{
crypto::{

View File

@@ -222,6 +222,9 @@ pub enum Error {
#[cfg(any(feature = "blockchain2", feature = "raft"))]
#[error(transparent)]
SledError(#[from] sled::Error),
#[error("Unsupported network transport")]
UnsupportedTransport,
}
#[cfg(feature = "node")]

View File

@@ -1,3 +1,5 @@
pub mod jsonrpc;
pub mod rpcserver;
// TODO: Replace rpcserver with this
pub mod rpcserver2;
pub mod websockets;

102
src/rpc/rpcserver2.rs Normal file
View File

@@ -0,0 +1,102 @@
use async_std::{
io::{ReadExt, WriteExt},
stream::StreamExt,
sync::Arc,
};
use async_trait::async_trait;
use log::{debug, error, info};
use url::Url;
use super::jsonrpc::{JsonRequest, JsonResult};
use crate::{
net::transport::{TcpTransport, TlsTransport, Transport},
Error, Result,
};
#[async_trait]
pub trait RequestHandler: Sync + Send {
async fn handle_request(&self, req: JsonRequest) -> JsonResult;
}
pub async fn listen_and_serve(url: Url, rh: Arc<impl RequestHandler + 'static>) -> Result<()> {
debug!(target: "JSON-RPC SERVER", "Trying to start listener on {}", url);
macro_rules! handle_stream {
($stream:expr) => {
let mut buf = vec![0; 8192];
loop {
let n = match $stream.read(&mut buf).await {
Ok(n) if n == 0 => {
info!(target: "JSON-RPC SERVER", "Closed connection");
break;
}
Ok(n) => n,
Err(e) => {
error!(target: "JSON-RPC SERVER", "Failed reading from socket: {}", e);
info!(target: "JSON-RPC SERVER", "Closed connection");
break;
}
};
let r: JsonRequest = match serde_json::from_slice(&buf[0..n]) {
Ok(r) => {
debug!(target: "JSON-RPC SERVER", "--> {}", String::from_utf8_lossy(&buf));
r
}
Err(e) => {
error!(target: "JSON-RPC SERVER", "Received invalid JSON: {:?}", e);
info!(target: "JSON-RPC SERVER", "Closed connection");
break;
}
};
let reply = rh.handle_request(r).await;
let j = serde_json::to_string(&reply)?;
debug!(target: "JSON-RPC SERVER", "<-- {}", j);
if let Err(e) = $stream.write_all(j.as_bytes()).await {
error!(target: "JSON-RPC SERVER", "Failed writing to socket: {}", e);
info!(target: "JSON-RPC SERVER", "Closed connection");
break;
}
}
}
}
match url.scheme() {
"tcp" => {
let transport = TcpTransport::new(None, 1024);
let listener = transport.listen_on(url).unwrap().await.unwrap();
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
info!(target: "JSON-RPC SERVER", "Accepted TCP connection");
let mut stream = stream.unwrap();
handle_stream!(stream);
}
unreachable!()
}
"tls" => {
let transport = TlsTransport::new(None, 1024);
let (acceptor, listener) = transport.listen_on(url).unwrap().await.unwrap();
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
info!(target: "JSON-RPC SERVER", "Accepted TLS connection");
let stream = stream.unwrap();
let mut stream = acceptor.accept(stream).await.unwrap();
handle_stream!(stream);
}
unreachable!()
}
"tor" => {
todo!()
}
x => {
error!(target: "JSON-RPC SERVER", "Transport protocol '{}' isn't implemented", x);
Err(Error::UnsupportedTransport)
}
}
}

View File

@@ -45,7 +45,7 @@ pub fn spawn_config(path: &Path, contents: &[u8]) -> Result<()> {
let mut file = fs::File::create(path)?;
file.write_all(contents)?;
println!("Config file created in `{:?}`. Please review it and try again.", path);
println!("Config file created in '{:?}'. Please review it and try again.", path);
std::process::exit(2);
}