Просмотр исходного кода

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

parazyd 4 лет назад
Родитель
Сommit
a3ed95ab79
11 измененных файлов с 420 добавлено и 2 удалено
  1. 1 0
      .gitignore
  2. 156 0
      Cargo.lock
  3. 1 0
      Cargo.toml
  4. 28 0
      bin/darkfid2/Cargo.toml
  5. 14 0
      bin/darkfid2/darkfid_config.toml
  6. 111 0
      bin/darkfid2/src/main.rs
  7. 1 1
      src/crypto/merkle_node.rs
  8. 3 0
      src/error.rs
  9. 2 0
      src/rpc/mod.rs
  10. 102 0
      src/rpc/rpcserver2.rs
  11. 1 1
      src/util/cli.rs

+ 1 - 0
.gitignore

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

+ 156 - 0
Cargo.lock

@@ -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"

+ 1 - 0
Cargo.toml

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

+ 28 - 0
bin/darkfid2/Cargo.toml

@@ -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"

+ 14 - 0
bin/darkfid2/darkfid_config.toml

@@ -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 - 0
bin/darkfid2/src/main.rs

@@ -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(())
+}

+ 1 - 1
src/crypto/merkle_node.rs

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

+ 3 - 0
src/error.rs

@@ -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")]

+ 2 - 0
src/rpc/mod.rs

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

+ 102 - 0
src/rpc/rpcserver2.rs

@@ -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)
+        }
+    }
+}

+ 1 - 1
src/util/cli.rs

@@ -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);
     }