aggstam 4 лет назад
Родитель
Сommit
68697ce3a4

+ 2 - 0
Cargo.lock

@@ -2464,6 +2464,7 @@ dependencies = [
  "async-channel",
  "async-channel",
  "async-executor",
  "async-executor",
  "async-std",
  "async-std",
+ "async-trait",
  "ctrlc",
  "ctrlc",
  "darkfi",
  "darkfi",
  "easy-parallel",
  "easy-parallel",
@@ -2472,6 +2473,7 @@ dependencies = [
  "log",
  "log",
  "serde",
  "serde",
  "serde_derive",
  "serde_derive",
+ "serde_json",
  "simplelog",
  "simplelog",
  "structopt",
  "structopt",
  "structopt-toml",
  "structopt-toml",

+ 2 - 0
bin/lilith/Cargo.toml

@@ -17,6 +17,7 @@ darkfi = {path = "../../", features = ["net"]}
 async-channel = "1.6.1"
 async-channel = "1.6.1"
 async-executor = "1.4.1"
 async-executor = "1.4.1"
 async-std = "1.12.0"
 async-std = "1.12.0"
+async-trait = "0.1.57"
 ctrlc = { version = "3.2.3", features = ["termination"] }
 ctrlc = { version = "3.2.3", features = ["termination"] }
 easy-parallel = "3.2.0"
 easy-parallel = "3.2.0"
 futures-lite = "1.12.0"
 futures-lite = "1.12.0"
@@ -24,6 +25,7 @@ futures-lite = "1.12.0"
 # Misc
 # Misc
 fxhash = "0.2.1"
 fxhash = "0.2.1"
 log = "0.4.17"
 log = "0.4.17"
+serde_json = "1.0.83"
 simplelog = "0.12.0"
 simplelog = "0.12.0"
 url = "2.2.2"
 url = "2.2.2"
 
 

+ 21 - 17
bin/lilith/README.md

@@ -18,8 +18,9 @@ FLAGS:
     -v               Increase verbosity (-vvv supported)
     -v               Increase verbosity (-vvv supported)
 
 
 OPTIONS:
 OPTIONS:
-    -c, --config <config>    Configuration file to use
-        --url <url>          Daemon published url, common for all enabled networks [default: tcp://127.0.0.1]
+    -c, --config <config>            Configuration file to use
+        --rpc-listen <rpc-listen>    JSON-RPC listen URL [default: tcp://127.0.0.1:18927]
+        --urls <urls>...             Daemon published urls, common for all enabled networks (repeatable flag)
 ```
 ```
 
 
 On first execution, daemon will create default config file ~/.config/darkfi/lilith_config.toml.
 On first execution, daemon will create default config file ~/.config/darkfi/lilith_config.toml.
@@ -29,19 +30,22 @@ Run lilith as follows:
 
 
 ```
 ```
 % lilith
 % lilith
-13:02:30 [INFO] Found configuration for network: darkfid
-13:02:30 [INFO] Found configuration for network: ircd
-13:02:30 [INFO] Found configuration for network: taud
-13:02:30 [INFO] Starting seed network node for darkfid at: tcp://127.0.0.1:7650
-13:02:30 [WARN] Skipping seed sync process since no seeds are configured.
-13:02:30 [INFO] Starting seed network node for ircd at: tcp://127.0.0.1:8760
-13:02:30 [INFO] Starting inbound session on tcp://127.0.0.1:7650
-13:02:30 [WARN] Skipping seed sync process since no seeds are configured.
-13:02:30 [INFO] Starting inbound session on tcp://127.0.0.1:8760
-13:02:30 [INFO] Starting seed network node for taud at: tcp://127.0.0.1:9870
-13:02:30 [INFO] Starting 0 outbound connection slots.
-13:02:30 [WARN] Skipping seed sync process since no seeds are configured.
-13:02:30 [INFO] Starting 0 outbound connection slots.
-13:02:30 [INFO] Starting inbound session on tcp://127.0.0.1:9870
-13:02:30 [INFO] Starting 0 outbound connection slots.
+17:22:12 [INFO] Found configuration for network: darkfid_consensus
+17:22:12 [INFO] Found configuration for network: darkfid_sync
+17:22:12 [INFO] Found configuration for network: ircd
+17:22:12 [INFO] Urls are not provided, will use: tcp://127.0.0.1
+17:22:12 [INFO] Starting seed network node for darkfid_sync at: ["tcp://127.0.0.1:33032"]
+17:22:12 [WARN] Skipping seed sync process since no seeds are configured.
+17:22:12 [INFO] Starting seed network node for darkfid_consensus at: ["tcp://127.0.0.1:33033"]
+17:22:12 [INFO] #0 starting inbound session on tcp://127.0.0.1:33032
+17:22:12 [WARN] Skipping seed sync process since no seeds are configured.
+17:22:12 [INFO] Starting seed network node for ircd at: ["tcp://127.0.0.1:25551"]
+17:22:12 [INFO] #0 starting inbound session on tcp://127.0.0.1:33033
+17:22:12 [WARN] Skipping seed sync process since no seeds are configured.
+17:22:12 [INFO] Starting JSON-RPC server
+17:22:12 [INFO] #0 starting inbound session on tcp://127.0.0.1:25551
+17:22:12 [INFO] Starting 0 outbound connection slots.
+17:22:12 [INFO] Starting 0 outbound connection slots.
+17:22:12 [INFO] JSON-RPC listener bound to tcp://127.0.0.1:18927
+17:22:12 [INFO] Starting 0 outbound connection slots.
 ```
 ```

+ 3 - 0
bin/lilith/lilith_config.toml

@@ -6,6 +6,9 @@
 ## The default values are left commented. They can be overridden either by
 ## The default values are left commented. They can be overridden either by
 ## uncommenting, or by using the command-line.
 ## uncommenting, or by using the command-line.
 
 
+# JSON-RPC listen URL
+#rpc_listen = "tcp://127.0.0.1:18927"
+
 # Daemon published urls, common for all enabled networks
 # Daemon published urls, common for all enabled networks
 #urls = ["tcp://127.0.0.1"]
 #urls = ["tcp://127.0.0.1"]
 
 

+ 4 - 0
bin/lilith/src/config.rs

@@ -12,6 +12,10 @@ use darkfi::{cli_desc, Result};
 #[serde(default)]
 #[serde(default)]
 #[structopt(name = "lilith", about = cli_desc!())]
 #[structopt(name = "lilith", about = cli_desc!())]
 pub struct Args {
 pub struct Args {
+    #[structopt(long, default_value = "tcp://127.0.0.1:18927")]
+    /// JSON-RPC listen URL
+    pub rpc_listen: Url,
+
     #[structopt(short, long)]
     #[structopt(short, long)]
     /// Configuration file to use
     /// Configuration file to use
     pub config: Option<String>,
     pub config: Option<String>,

+ 85 - 5
bin/lilith/src/main.rs

@@ -1,12 +1,23 @@
 use async_executor::Executor;
 use async_executor::Executor;
 use async_std::sync::Arc;
 use async_std::sync::Arc;
+use async_trait::async_trait;
 use futures_lite::future;
 use futures_lite::future;
 use log::{error, info};
 use log::{error, info};
+use serde_json::{json, Value};
+use std::collections::HashMap;
 use structopt_toml::StructOptToml;
 use structopt_toml::StructOptToml;
 use url::Url;
 use url::Url;
 
 
 use darkfi::{
 use darkfi::{
     async_daemonize, net,
     async_daemonize, net,
+    net::P2pPtr,
+    rpc::{
+        jsonrpc::{
+            ErrorCode::{InvalidParams, MethodNotFound},
+            JsonError, JsonRequest, JsonResponse, JsonResult,
+        },
+        server::{listen_and_serve, RequestHandler},
+    },
     util::{
     util::{
         cli::{get_log_config, get_log_level, spawn_config},
         cli::{get_log_config, get_log_level, spawn_config},
         expand_path,
         expand_path,
@@ -21,12 +32,69 @@ use config::{parse_configured_networks, Args, NetInfo};
 const CONFIG_FILE: &str = "lilith_config.toml";
 const CONFIG_FILE: &str = "lilith_config.toml";
 const CONFIG_FILE_CONTENTS: &str = include_str!("../lilith_config.toml");
 const CONFIG_FILE_CONTENTS: &str = include_str!("../lilith_config.toml");
 
 
+/// Struct representing a spawned p2p network.
+pub struct Spawn {
+    pub name: String,
+    pub p2p: P2pPtr,
+}
+
+impl Spawn {
+    async fn addresses(&self) -> Vec<String> {
+        self.p2p.hosts().load_all().await.iter().map(|addr| addr.to_string()).collect()
+    }
+}
+
+/// Struct representing the daemon.
+pub struct Lilith {
+    /// Spawned networks
+    spawns: Vec<Spawn>,
+}
+
+impl Lilith {
+    // RPCAPI:
+    // Returns all spawned networks names with their node addresses.
+    // --> {"jsonrpc": "2.0", "method": "spawns", "params": [], "id": 42}
+    // <-- {"jsonrpc": "2.0", "result": "{spawns}", "id": 42}
+    async fn spawns(&self, id: Value, _params: &[Value]) -> JsonResult {
+        let mut spawns: HashMap<String, Vec<String>> = HashMap::default();
+        for spawn in &self.spawns {
+            spawns.insert(spawn.name.clone(), spawn.addresses().await);
+        }
+        JsonResponse::new(json!(spawns), id).into()
+    }
+
+    // RPCAPI:
+    // Replies to a ping method.
+    // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
+    // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42}
+    async fn pong(&self, id: Value, _params: &[Value]) -> JsonResult {
+        JsonResponse::new(json!("pong"), id).into()
+    }
+}
+
+#[async_trait]
+impl RequestHandler for Lilith {
+    async fn handle_request(&self, req: JsonRequest) -> JsonResult {
+        if !req.params.is_array() {
+            return JsonError::new(InvalidParams, None, req.id).into()
+        }
+
+        let params = req.params.as_array().unwrap();
+
+        match req.method.as_str() {
+            Some("spawns") => return self.spawns(req.id, params).await,
+            Some("ping") => return self.pong(req.id, params).await,
+            Some(_) | None => return JsonError::new(MethodNotFound, None, req.id).into(),
+        }
+    }
+}
+
 async fn spawn_network(
 async fn spawn_network(
     name: &str,
     name: &str,
     info: NetInfo,
     info: NetInfo,
     urls: Vec<Url>,
     urls: Vec<Url>,
     ex: Arc<Executor<'_>>,
     ex: Arc<Executor<'_>>,
-) -> Result<()> {
+) -> Result<Spawn> {
     let mut full_urls = Vec::new();
     let mut full_urls = Vec::new();
     for url in &urls {
     for url in &urls {
         let mut url = url.clone();
         let mut url = url.clone();
@@ -51,14 +119,17 @@ async fn spawn_network(
     info!("Starting seed network node for {} at: {:?}", name, urls_vec);
     info!("Starting seed network node for {} at: {:?}", name, urls_vec);
     p2p.clone().start(ex.clone()).await?;
     p2p.clone().start(ex.clone()).await?;
     let _ex = ex.clone();
     let _ex = ex.clone();
+    let _p2p = p2p.clone();
     ex.spawn(async move {
     ex.spawn(async move {
-        if let Err(e) = p2p.run(_ex).await {
+        if let Err(e) = _p2p.run(_ex).await {
             error!("Failed starting P2P network seed: {}", e);
             error!("Failed starting P2P network seed: {}", e);
         }
         }
     })
     })
     .detach();
     .detach();
 
 
-    Ok(())
+    let spawn = Spawn { name: name.to_string(), p2p };
+
+    Ok(spawn)
 }
 }
 
 
 async_daemonize!(realmain);
 async_daemonize!(realmain);
@@ -92,12 +163,21 @@ async fn realmain(args: Args, ex: Arc<Executor<'_>>) -> Result<()> {
     }
     }
 
 
     // Spawn configured networks
     // Spawn configured networks
+    let mut spawns = vec![];
     for (name, info) in &configured_nets {
     for (name, info) in &configured_nets {
-        if let Err(e) = spawn_network(name, info.clone(), urls.clone(), ex.clone()).await {
-            error!("Failed starting {} P2P network seed: {}", name, e);
+        match spawn_network(name, info.clone(), urls.clone(), ex.clone()).await {
+            Ok(spawn) => spawns.push(spawn),
+            Err(e) => error!("Failed starting {} P2P network seed: {}", name, e),
         }
         }
     }
     }
 
 
+    let lilith = Lilith { spawns };
+    let lilith = Arc::new(lilith);
+
+    // JSON-RPC server
+    info!("Starting JSON-RPC server");
+    ex.spawn(listen_and_serve(args.rpc_listen, lilith)).detach();
+
     // Wait for SIGINT
     // Wait for SIGINT
     shutdown.recv().await?;
     shutdown.recv().await?;
     print!("\r");
     print!("\r");

+ 3 - 0
contrib/localnet/lilith_config.toml

@@ -6,6 +6,9 @@
 ## The default values are left commented. They can be overridden either by
 ## The default values are left commented. They can be overridden either by
 ## uncommenting, or by using the command-line.
 ## uncommenting, or by using the command-line.
 
 
+# Daemon published url, common for all enabled networks
+#urls = ["tcp://127.0.0.1"]
+
 # Daemon published urls, common for all enabled networks
 # Daemon published urls, common for all enabled networks
 urls = ["tcp://127.0.0.1"]
 urls = ["tcp://127.0.0.1"]
 
 

+ 3 - 0
script/research/fud/localnet/lilith_config.toml

@@ -6,6 +6,9 @@
 ## The default values are left commented. They can be overridden either by
 ## The default values are left commented. They can be overridden either by
 ## uncommenting, or by using the command-line.
 ## uncommenting, or by using the command-line.
 
 
+# Daemon published url, common for all enabled networks
+#urls = ["tcp://127.0.0.1"]
+
 # Daemon published url, common for all enabled networks
 # Daemon published url, common for all enabled networks
 url = ["tcp://127.0.0.1"]
 url = ["tcp://127.0.0.1"]