From 5ac7454620e0adff36f74611c9b886c21763e41e Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 12:07:51 +0000 Subject: [PATCH 01/77] validator: adding Diesel ORM --- Cargo.lock | 33 +++++++++++++++++++++++++++++++++ validator/Cargo.toml | 1 + 2 files changed, 34 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 8e70bb3cfb0..03143d2e253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -549,6 +549,28 @@ dependencies = [ "subtle 2.2.2", ] +[[package]] +name = "diesel" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7cc03b910de9935007861dce440881f69102aaaedfd4bc5a6f40340ca5840c" +dependencies = [ + "byteorder", + "diesel_derives", + "libsqlite3-sys", +] + +[[package]] +name = "diesel_derives" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "difference" version = "2.0.0" @@ -1234,6 +1256,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libsqlite3-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25" +dependencies = [ + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.0.25" @@ -1631,6 +1663,7 @@ dependencies = [ "clap", "config", "crypto", + "diesel", "directory-client", "dirs", "dotenv", diff --git a/validator/Cargo.toml b/validator/Cargo.toml index f000bdb1999..8a8bf9b07da 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" abci = "0.6.4" byteorder = "1.3.2" clap = "2.33.0" +diesel = { version = "1.4.3", features = ["sqlite"] } dirs = "2.0.2" # Read notes https://crates.io/crates/dotenv - tl;dr: don't use in production, set environmental variables properly. dotenv = "0.15.0" From e30f3f7b14eedd1b0e014275ce67e4b52a10597e Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 12:09:27 +0000 Subject: [PATCH 02/77] validator: making sure Iron::status is always avaialable --- validator/src/network/rest/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 17a87785b95..58df155a7a7 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,6 +1,7 @@ use iron::prelude::*; use router::Router; +mod announce; mod models; mod routes; From 516a32addda84226f8efed65fc967cbce50cf41d Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 12:09:33 +0000 Subject: [PATCH 03/77] ibid --- validator/src/network/rest/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 58df155a7a7..bf0b5eecc4b 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,4 +1,5 @@ use iron::prelude::*; +use iron::status; use router::Router; mod announce; From b398c5c8ef212a7baa0cba044e7355e1b90bd7c7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 12:09:56 +0000 Subject: [PATCH 04/77] validator: presence-announcement REST API --- validator/src/network/rest/announce/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 validator/src/network/rest/announce/mod.rs diff --git a/validator/src/network/rest/announce/mod.rs b/validator/src/network/rest/announce/mod.rs new file mode 100644 index 00000000000..8e02b2c4fa5 --- /dev/null +++ b/validator/src/network/rest/announce/mod.rs @@ -0,0 +1,12 @@ +use super::*; + +// POST a new PresenceAnnouncement +pub fn post(req: &mut Request) -> IronResult { + Ok(Response::with(status::Created)) +} + +struct PresenceAnnouncement { + host: String, + public_key: String, + node_type: String, +} From 6dbc7551664c2cc1cfd021cde5bf6267a83ea5a9 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 12:10:14 +0000 Subject: [PATCH 05/77] validator: adding Diesel setup --- diesel.toml | 5 +++++ migrations/.gitkeep | 0 2 files changed, 5 insertions(+) create mode 100644 diesel.toml create mode 100644 migrations/.gitkeep diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 00000000000..92267c829f2 --- /dev/null +++ b/diesel.toml @@ -0,0 +1,5 @@ +# For documentation on how to configure this file, +# see diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d From fd103cdbb1dddb3f09a7b1913aa0e7bff6d156f4 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 13:49:11 +0000 Subject: [PATCH 06/77] Removing Diesel stuff from root of monorepo --- diesel.toml | 5 ----- migrations/.gitkeep | 0 2 files changed, 5 deletions(-) delete mode 100644 diesel.toml delete mode 100644 migrations/.gitkeep diff --git a/diesel.toml b/diesel.toml deleted file mode 100644 index 92267c829f2..00000000000 --- a/diesel.toml +++ /dev/null @@ -1,5 +0,0 @@ -# For documentation on how to configure this file, -# see diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" diff --git a/migrations/.gitkeep b/migrations/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 From a0993b4161fd99bd25cc253af0ab874bd12cee83 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 13:49:39 +0000 Subject: [PATCH 07/77] validator: adding Diesel migrations and setup --- validator/diesel.toml | 5 +++++ validator/migrations/.gitkeep | 0 .../down.sql | 2 ++ .../up.sql | 7 +++++++ validator/src/schema.rs | 8 ++++++++ 5 files changed, 22 insertions(+) create mode 100644 validator/diesel.toml create mode 100644 validator/migrations/.gitkeep create mode 100644 validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql create mode 100644 validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql create mode 100644 validator/src/schema.rs diff --git a/validator/diesel.toml b/validator/diesel.toml new file mode 100644 index 00000000000..92267c829f2 --- /dev/null +++ b/validator/diesel.toml @@ -0,0 +1,5 @@ +# For documentation on how to configure this file, +# see diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" diff --git a/validator/migrations/.gitkeep b/validator/migrations/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql b/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql new file mode 100644 index 00000000000..fb5c7870ba9 --- /dev/null +++ b/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE presence_announcements \ No newline at end of file diff --git a/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql b/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql new file mode 100644 index 00000000000..e45ebf2bf8e --- /dev/null +++ b/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql @@ -0,0 +1,7 @@ +CREATE TABLE presence_announcements +( + id INTEGER PRIMARY KEY NOT NULL, + host VARCHAR NOT NULL, + public_key VARCHAR NOT NULL, + node_type VARCHAR NOT NULL +) \ No newline at end of file diff --git a/validator/src/schema.rs b/validator/src/schema.rs new file mode 100644 index 00000000000..40df3f87153 --- /dev/null +++ b/validator/src/schema.rs @@ -0,0 +1,8 @@ +table! { + presence_announcements (id) { + id -> Integer, + host -> Text, + public_key -> Text, + node_type -> Text, + } +} From 6d8f443a11dd9377dc1314a8569b91b061533228 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 13:53:17 +0000 Subject: [PATCH 08/77] validator: documenting how PresenceAnnouncement is different from presence. --- validator/src/network/rest/announce/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/validator/src/network/rest/announce/mod.rs b/validator/src/network/rest/announce/mod.rs index 8e02b2c4fa5..f4cbb5e4502 100644 --- a/validator/src/network/rest/announce/mod.rs +++ b/validator/src/network/rest/announce/mod.rs @@ -1,10 +1,15 @@ use super::*; -// POST a new PresenceAnnouncement +/// POST a new PresenceAnnouncement pub fn post(req: &mut Request) -> IronResult { Ok(Response::with(status::Created)) } +/// A PresenceAnnouncement received from a node asks for entry into the system. +/// It's not really a "presence" insofar as other means (e.g. health-checks, +/// mixmining, staking etc) are used to determine actual presence, and whether +/// the node is doing the work it should be doing. A PresenceAnnouncement is +/// a node saying "hey, I exist, and am ready to participate". struct PresenceAnnouncement { host: String, public_key: String, From 03f37f6e82d2527a49d984912387fd1ecaea2479 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 14:11:15 +0000 Subject: [PATCH 09/77] validator: added Chrono crate for datetime conversions into sql --- Cargo.lock | 6 ++++-- validator/Cargo.toml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03143d2e253..28f2b05c438 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -335,12 +335,13 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" dependencies = [ "num-integer", "num-traits", + "serde", "time", ] @@ -1660,6 +1661,7 @@ dependencies = [ "abci", "built", "byteorder", + "chrono", "clap", "config", "crypto", diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 8a8bf9b07da..77923b0ea5a 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" abci = "0.6.4" byteorder = "1.3.2" clap = "2.33.0" +chrono = { version = "0.4.11", features = ["serde"] } diesel = { version = "1.4.3", features = ["sqlite"] } dirs = "2.0.2" # Read notes https://crates.io/crates/dotenv - tl;dr: don't use in production, set environmental variables properly. From 53665e3828a786f547de513e639dadb0b2872b9f Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 14:11:30 +0000 Subject: [PATCH 10/77] validator: restructured the presence module --- validator/src/network/rest/announce/mod.rs | 17 --------------- validator/src/network/rest/mod.rs | 12 ++++++----- validator/src/network/rest/models/mod.rs | 1 - .../network/rest/presence/announcements.rs | 21 +++++++++++++++++++ validator/src/network/rest/presence/mod.rs | 4 ++++ .../presence.rs => presence/topology.rs} | 12 +++++++++++ validator/src/network/rest/routes/mod.rs | 4 ---- validator/src/network/rest/routes/topology.rs | 12 ----------- 8 files changed, 44 insertions(+), 39 deletions(-) delete mode 100644 validator/src/network/rest/announce/mod.rs delete mode 100644 validator/src/network/rest/models/mod.rs create mode 100644 validator/src/network/rest/presence/announcements.rs create mode 100644 validator/src/network/rest/presence/mod.rs rename validator/src/network/rest/{models/presence.rs => presence/topology.rs} (67%) delete mode 100644 validator/src/network/rest/routes/mod.rs delete mode 100644 validator/src/network/rest/routes/topology.rs diff --git a/validator/src/network/rest/announce/mod.rs b/validator/src/network/rest/announce/mod.rs deleted file mode 100644 index f4cbb5e4502..00000000000 --- a/validator/src/network/rest/announce/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::*; - -/// POST a new PresenceAnnouncement -pub fn post(req: &mut Request) -> IronResult { - Ok(Response::with(status::Created)) -} - -/// A PresenceAnnouncement received from a node asks for entry into the system. -/// It's not really a "presence" insofar as other means (e.g. health-checks, -/// mixmining, staking etc) are used to determine actual presence, and whether -/// the node is doing the work it should be doing. A PresenceAnnouncement is -/// a node saying "hey, I exist, and am ready to participate". -struct PresenceAnnouncement { - host: String, - public_key: String, - node_type: String, -} diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index bf0b5eecc4b..0cc50f3d75e 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,10 +1,7 @@ use iron::prelude::*; -use iron::status; use router::Router; -mod announce; -mod models; -mod routes; +mod presence; pub struct Api {} @@ -25,7 +22,12 @@ impl Api { pub fn setup_routes(&self) -> Router { let mut router = Router::new(); - router.get("/topology", routes::topology::get, "topology_get"); + router.get("/topology", presence::topology::get, "topology_get"); + router.post( + "/presence/announcements", + presence::announcements::post, + "presence_announcements_post", + ); router } } diff --git a/validator/src/network/rest/models/mod.rs b/validator/src/network/rest/models/mod.rs deleted file mode 100644 index bb4ee05c5c3..00000000000 --- a/validator/src/network/rest/models/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod presence; diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs new file mode 100644 index 00000000000..836ea3d677e --- /dev/null +++ b/validator/src/network/rest/presence/announcements.rs @@ -0,0 +1,21 @@ +use super::*; +use chrono::NaiveDateTime; +use iron::status; + +/// POST a new presence::Announcement +pub fn post(req: &mut Request) -> IronResult { + Ok(Response::with(status::Created)) +} + +/// A presence::Announcement received from a node asks for entry into the system. +/// It's not really a "presence" insofar as other means (e.g. health-checks, +/// mixmining, staking etc) are used to determine actual presence, and whether +/// the node is doing the work it should be doing. A presence::Announcement is +/// a node saying "hey, I exist, and am ready to participate, but you need to +/// figure out if I should be made active by the system." +struct Announcement { + host: String, + public_key: String, + node_type: String, + seen_at: NaiveDateTime, +} diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs new file mode 100644 index 00000000000..09696d4e86b --- /dev/null +++ b/validator/src/network/rest/presence/mod.rs @@ -0,0 +1,4 @@ +use super::*; + +pub mod announcements; +pub mod topology; diff --git a/validator/src/network/rest/models/presence.rs b/validator/src/network/rest/presence/topology.rs similarity index 67% rename from validator/src/network/rest/models/presence.rs rename to validator/src/network/rest/presence/topology.rs index 300e80ca6da..2057a5c84b2 100644 --- a/validator/src/network/rest/models/presence.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -1,5 +1,17 @@ +use super::*; +use iron::status; use serde::{Deserialize, Serialize}; +pub fn get(_req: &mut Request) -> IronResult { + let topology = Topology { + mix_nodes: Vec::::new(), + service_providers: Vec::::new(), + validators: Vec::::new(), + }; + let response = serde_json::to_string_pretty(&topology).unwrap(); + Ok(Response::with((status::Ok, response))) +} + // Topology shows us the current state of the overall Nym network #[derive(Serialize, Deserialize, Debug)] pub struct Topology { diff --git a/validator/src/network/rest/routes/mod.rs b/validator/src/network/rest/routes/mod.rs deleted file mode 100644 index 1265efcf407..00000000000 --- a/validator/src/network/rest/routes/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -use iron::prelude::*; -use iron::status; - -pub mod topology; diff --git a/validator/src/network/rest/routes/topology.rs b/validator/src/network/rest/routes/topology.rs deleted file mode 100644 index 2b72ccad3f5..00000000000 --- a/validator/src/network/rest/routes/topology.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::*; -use crate::network::rest::models::presence::{MixNode, ServiceProvider, Topology, Validator}; - -pub fn get(_req: &mut Request) -> IronResult { - let topology = Topology { - mix_nodes: Vec::::new(), - service_providers: Vec::::new(), - validators: Vec::::new(), - }; - let response = serde_json::to_string_pretty(&topology).unwrap(); - Ok(Response::with((status::Ok, response))) -} From 660943911cddafdd53161a4b47c84c9ba32bddc7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 14:12:46 +0000 Subject: [PATCH 11/77] validator: removed presence announcements from persistence --- .../down.sql | 2 -- .../up.sql | 7 ------- validator/src/schema.rs | 9 +-------- 3 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql delete mode 100644 validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql diff --git a/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql b/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql deleted file mode 100644 index fb5c7870ba9..00000000000 --- a/validator/migrations/2020-03-17-121545_create_presence_announcements/down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- This file should undo anything in `up.sql` -DROP TABLE presence_announcements \ No newline at end of file diff --git a/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql b/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql deleted file mode 100644 index e45ebf2bf8e..00000000000 --- a/validator/migrations/2020-03-17-121545_create_presence_announcements/up.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE presence_announcements -( - id INTEGER PRIMARY KEY NOT NULL, - host VARCHAR NOT NULL, - public_key VARCHAR NOT NULL, - node_type VARCHAR NOT NULL -) \ No newline at end of file diff --git a/validator/src/schema.rs b/validator/src/schema.rs index 40df3f87153..8b137891791 100644 --- a/validator/src/schema.rs +++ b/validator/src/schema.rs @@ -1,8 +1 @@ -table! { - presence_announcements (id) { - id -> Integer, - host -> Text, - public_key -> Text, - node_type -> Text, - } -} + From 342bef8ad827d9652bf244ea97a2ec9f838dc6d6 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 14:35:33 +0000 Subject: [PATCH 12/77] validator: commenting topology --- validator/src/network/rest/presence/topology.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 2057a5c84b2..42030b106cf 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -2,6 +2,7 @@ use super::*; use iron::status; use serde::{Deserialize, Serialize}; +/// Retrieve the current Nym network topology via HTTP pub fn get(_req: &mut Request) -> IronResult { let topology = Topology { mix_nodes: Vec::::new(), @@ -12,7 +13,7 @@ pub fn get(_req: &mut Request) -> IronResult { Ok(Response::with((status::Ok, response))) } -// Topology shows us the current state of the overall Nym network +/// Topology shows us the current state of the overall Nym network #[derive(Serialize, Deserialize, Debug)] pub struct Topology { pub validators: Vec, From e7cef031726823508d93e2cc65836fb1db27f6e7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 14:35:52 +0000 Subject: [PATCH 13/77] Adding staking to the mixmining service --- validator/src/services/mixmining/db.rs | 0 validator/src/services/mixmining/mod.rs | 1 + validator/src/services/mixmining/staking.rs | 15 +++++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 validator/src/services/mixmining/db.rs create mode 100644 validator/src/services/mixmining/staking.rs diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index b80e115b6dc..fb9189f4bf4 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -1 +1,2 @@ pub mod health_check_runner; +pub mod staking; diff --git a/validator/src/services/mixmining/staking.rs b/validator/src/services/mixmining/staking.rs new file mode 100644 index 00000000000..8a4524e1474 --- /dev/null +++ b/validator/src/services/mixmining/staking.rs @@ -0,0 +1,15 @@ +pub struct StakeService {} + +impl StakeService { + fn update(stake: MixnodeStake) { + // Update (or create) a given mixnode stake, identified by the mixnode's public key + } + fn active_mixnodes() { + // For now, we have no notion of capacity. Return the top 6 mixnodes by stake. + } +} + +pub struct MixnodeStake { + public_key: String, + amount: u64, +} From 8c0fca5fb01762aafc1cd8be19a73f53913f2641 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 17:37:31 +0000 Subject: [PATCH 14/77] Start of mixmining + stake service --- validator/src/services/mixmining/db.rs | 15 ++++ validator/src/services/mixmining/mod.rs | 1 + validator/src/services/mixmining/staking.rs | 90 +++++++++++++++++++-- 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index e69de29bb2d..863d31c9ab5 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -0,0 +1,15 @@ +use super::staking::Mixnode; + +#[derive(Clone, Debug, PartialEq)] +pub struct MixminingDb { + pub mixnodes: Box>, +} + +impl MixminingDb { + pub fn new() -> MixminingDb { + let mut mixnodes = Vec::::new(); + MixminingDb { + mixnodes: Box::new(mixnodes), + } + } +} diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index fb9189f4bf4..95bb50f6b0c 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -1,2 +1,3 @@ +pub mod db; pub mod health_check_runner; pub mod staking; diff --git a/validator/src/services/mixmining/staking.rs b/validator/src/services/mixmining/staking.rs index 8a4524e1474..b641427d7cf 100644 --- a/validator/src/services/mixmining/staking.rs +++ b/validator/src/services/mixmining/staking.rs @@ -1,15 +1,91 @@ -pub struct StakeService {} +use super::db::MixminingDb; +pub struct StakeService { + db: MixminingDb, +} + +/// The mixmining::StakeService provides logic for updating and slashing mixnode +/// stake, retrieving lists of mixnodes based on stake, and adding/removing +/// mixnodes from the active set. +/// +/// Mixing and staking interact in interesting ways. Mixnodes first need to announce +/// their presence to the validators. The validators will then proceed to do a +/// health check on them. +/// +/// Once a Mixnode passes its health check, it goes into the stack of available +/// mixnodes. However, it's not necessarily going to start actively mixing traffic. +/// That depends on how much stake is riding on it: we depend on the wisdom of +/// stakers to put their money on trustworthy mixnodes. +/// +/// The active set of mixnodes will be able to expand or contract based on capacity +/// (not yet implemented). For now, we simply take the top N nodes available, +/// ordered by node stake. +/// +/// A lot is going to need to change here. Commented code is here mainly to +/// quickly sketch out the guts of the staking service. This is not the basis +/// of our real staking system quite yet - it's a way to start getting the system +/// to function with all the different node types to start talking to each other, +/// and will be dramatically reworked over the next few months. impl StakeService { - fn update(stake: MixnodeStake) { - // Update (or create) a given mixnode stake, identified by the mixnode's public key + fn new(db: MixminingDb) -> StakeService { + StakeService { db } } - fn active_mixnodes() { - // For now, we have no notion of capacity. Return the top 6 mixnodes by stake. + // Add a mixnode so that it becomes part of the possible mixnode set. + // Presumably it's passed health check. + fn add(&self, mixnode: Mixnode) {} + + /// Update (or create) a given mixnode stake, identified by the mixnode's public key + fn update(&self, public_key: &str, amount: u64) { + // retrieve the given Mixnode from the database and update its stake + } + + /// For now, we have no notion of capacity. Return the top 6 mixnodes, ordered by stake. + fn active_mixnodes(&self) -> Vec { + Vec::::new() + // hit the database + } + + /// Remove a mixnode from the active set in a way that does not impact its stake. + /// The mixnode has done its job well and requested to leave, so it can be removed + /// at the end of an epoch. + fn remove(&self, public_key: &str) { + // free locked up stake back to originating stakeholder + // remove the mixnode from the database + } + + // Add the given amount of stake to the given Mixnode. Presumably it has done + // its job well. + fn reward(&self, public_key: &str, amount: u64) {} + + /// Slash a mixnode's stake based on bad performance or detected malign intent. + fn slash(&self, public_key: &str, amount: u64) { + // transfer slashed stake amount to reserve fund + // retrieve the mixnode from the database, and decrement its stake amount + // by the amount given. + } + + /// Slash a mixnode's stake and immediately remove it from the mixnode set. + fn slash_remove(&self, public_key: String, amount: u64) { + // call slash (the method, not the guitarist) + // remove the mixnode from the database } } -pub struct MixnodeStake { +#[derive(Clone, Debug, PartialEq)] +pub struct Mixnode { public_key: String, - amount: u64, + stake: u64, +} + +#[cfg(test)] +mod test_constructor { + use super::*; + + #[test] + fn test_constructor_sets_database() { + let db = super::super::db::MixminingDb::new(); + let service = StakeService::new(db.clone()); + + assert_eq!(db, service.db); + } } From 73a05ecb7ecec04a3893e768f6c62d89588f3eb4 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 20:17:33 +0000 Subject: [PATCH 15/77] validator: added a bit about mixmining to README --- validator/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator/README.md b/validator/README.md index c8bbad50420..47b90bec59d 100644 --- a/validator/README.md +++ b/validator/README.md @@ -4,10 +4,10 @@ Nym Validator The Nym Validator has several jobs: * use Tendermint (v0.33.0) to maintain a total global ordering of incoming transactions -* track quality of service for mixnet nodes (mixmining) +* rewards + stake slashing based quality of service measurements for mixnet nodes (aka "mixmining") * generate Coconut credentials and ensure they're not double spent * maintain a decentralized directory of all Nym nodes that have staked into the system - + Some of these functions may be moved away to their own node types in the future, for example to increase scalability or performance. At the moment, we'd like to keep deployments simple, so they're all in the validator node. Running the validator on your local machine From 97b6a0ef0049ae411688a3b0168c3b0b01d295c8 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 20:17:51 +0000 Subject: [PATCH 16/77] validator: added Iron's params crate --- Cargo.lock | 211 ++++++++++++++++++++++++++++++++++++++++++- validator/Cargo.toml | 1 + 2 files changed, 207 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28f2b05c438..00831b95beb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" dependencies = [ - "memchr", + "memchr 2.3.3", ] [[package]] @@ -175,7 +175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" dependencies = [ "byteorder", - "safemem", + "safemem 0.3.3", ] [[package]] @@ -252,12 +252,35 @@ dependencies = [ "byte-tools", ] +[[package]] +name = "bodyparser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f023abfa58aad6f6bc4ae0630799e24d5ee0ab8bb2e49f651d9b1f9aa4f52f30" +dependencies = [ + "iron", + "persistent", + "plugin", + "serde", + "serde_json", +] + [[package]] name = "bs58" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae" +[[package]] +name = "buf_redux" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9279646319ff816b05fb5897883ece50d7d854d12b59992683d4f8a71b0f949" +dependencies = [ + "memchr 1.0.2", + "safemem 0.2.0", +] + [[package]] name = "built" version = "0.3.2" @@ -878,7 +901,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr", + "memchr 2.3.3", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1336,6 +1359,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +[[package]] +name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.3.3" @@ -1508,6 +1540,23 @@ dependencies = [ "tokio 0.2.12", ] +[[package]] +name = "multipart" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92f54eb45230c3aa20864ccf0c277eeaeadcf5e437e91731db498dbf7fbe0ec6" +dependencies = [ + "buf_redux", + "httparse", + "log 0.3.9", + "mime 0.2.6", + "mime_guess 1.8.8", + "rand 0.3.23", + "safemem 0.2.0", + "tempdir", + "twoway", +] + [[package]] name = "native-tls" version = "0.2.3" @@ -1537,6 +1586,42 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.4.6", + "rustc-serialize", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +dependencies = [ + "num-traits", + "rustc-serialize", +] + [[package]] name = "num-integer" version = "0.1.42" @@ -1547,6 +1632,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +dependencies = [ + "autocfg 1.0.0", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "rustc-serialize", +] + [[package]] name = "num-traits" version = "0.2.11" @@ -1673,6 +1781,7 @@ dependencies = [ "healthcheck", "iron", "log 0.4.8", + "params", "pretty_env_logger", "router", "serde", @@ -1721,6 +1830,22 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "params" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c789fdad2cfdaa551ea0e3a9eadb74c5d634968a9fb3a8c767d89be470d21589" +dependencies = [ + "bodyparser", + "iron", + "multipart", + "num", + "plugin", + "serde_json", + "tempdir", + "urlencoded", +] + [[package]] name = "parking_lot" version = "0.9.0" @@ -1780,6 +1905,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "persistent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8fa0009c4f3d350281309909c618abddf10bb7e3145f28410782f6a5ec74c5" +dependencies = [ + "iron", + "plugin", +] + [[package]] name = "pest" version = "2.1.3" @@ -2043,6 +2178,29 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.8", +] + [[package]] name = "rand" version = "0.6.5" @@ -2232,7 +2390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" dependencies = [ "aho-corasick", - "memchr", + "memchr 2.3.3", "regex-syntax", "thread_local", ] @@ -2321,6 +2479,12 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.2.3" @@ -2347,6 +2511,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +[[package]] +name = "safemem" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" + [[package]] name = "safemem" version = "0.3.3" @@ -2621,6 +2791,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + [[package]] name = "tempfile" version = "3.1.0" @@ -2705,7 +2885,7 @@ dependencies = [ "iovec", "lazy_static", "libc", - "memchr", + "memchr 2.3.3", "mio", "mio-named-pipes", "mio-uds", @@ -2930,6 +3110,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr 2.3.3", +] + [[package]] name = "typeable" version = "0.1.2" @@ -3036,6 +3225,18 @@ dependencies = [ "percent-encoding 2.1.0", ] +[[package]] +name = "urlencoded" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a52f50139118b60ae91af08bf15ed158817d34b91b9d24c11ffbe21195d33e3" +dependencies = [ + "bodyparser", + "iron", + "plugin", + "url 1.7.2", +] + [[package]] name = "utf-8" version = "0.7.5" diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 77923b0ea5a..a08b9cd4e2c 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -19,6 +19,7 @@ dotenv = "0.15.0" futures = "0.3.1" iron = "0.6.1" log = "0.4" +params = "0.8.0" pretty_env_logger = "0.3" router = "0.6.0" serde = "1.0.104" From 0d17414419196cc08870cf51c6d10195fe953607 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 17 Mar 2020 20:19:02 +0000 Subject: [PATCH 17/77] validator: reorganized mixmining service and db code --- validator/src/network/rest/mod.rs | 15 ++- .../network/rest/presence/announcements.rs | 34 ++++--- validator/src/network/rest/presence/mod.rs | 50 ++++++++++ .../src/network/rest/presence/topology.rs | 36 ------- validator/src/services/mixmining/db.rs | 2 +- validator/src/services/mixmining/mod.rs | 95 ++++++++++++++++++- validator/src/services/mixmining/staking.rs | 91 ------------------ 7 files changed, 170 insertions(+), 153 deletions(-) delete mode 100644 validator/src/services/mixmining/staking.rs diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 0cc50f3d75e..6bea2247bbe 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,4 +1,5 @@ use iron::prelude::*; +use presence::announcements; use router::Router; mod presence; @@ -14,20 +15,16 @@ impl Api { let port = 3000; println!("* starting REST API on localhost:{}", port); - let router = self.setup_routes(); - Iron::new(router) - .http(format!("localhost:{}", port)) - .unwrap(); - } - - pub fn setup_routes(&self) -> Router { let mut router = Router::new(); router.get("/topology", presence::topology::get, "topology_get"); router.post( "/presence/announcements", - presence::announcements::post, + announcements::post, "presence_announcements_post", ); - router + + Iron::new(router) + .http(format!("localhost:{}", port)) + .unwrap(); } } diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index 836ea3d677e..d43c6a4a11c 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -1,21 +1,25 @@ use super::*; -use chrono::NaiveDateTime; +use crate::services::mixmining; use iron::status; -/// POST a new presence::Announcement +use params::{Params, Value}; + pub fn post(req: &mut Request) -> IronResult { - Ok(Response::with(status::Created)) -} + // the part where we check if the worst possible handler code can work. + let db = mixmining::db::MixminingDb::new(); + let service = mixmining::Service::new(db); + let m = mixmining::Mixnode { + public_key: "foo".to_string(), + stake: 6, + }; + service.add(m); -/// A presence::Announcement received from a node asks for entry into the system. -/// It's not really a "presence" insofar as other means (e.g. health-checks, -/// mixmining, staking etc) are used to determine actual presence, and whether -/// the node is doing the work it should be doing. A presence::Announcement is -/// a node saying "hey, I exist, and am ready to participate, but you need to -/// figure out if I should be made active by the system." -struct Announcement { - host: String, - public_key: String, - node_type: String, - seen_at: NaiveDateTime, + // the actual params handling part. + let map = req.get_ref::().unwrap(); + match map.find(&["user", "name"]) { + Some(&Value::String(ref name)) if name == "Marie" => { + Ok(Response::with((status::Ok, "Welcome back, Marie!"))) + } + _ => Ok(Response::with(status::NotFound)), + } } diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index 09696d4e86b..8abc904fc7b 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -1,4 +1,54 @@ use super::*; +use chrono::NaiveDateTime; +use serde::{Deserialize, Serialize}; pub mod announcements; pub mod topology; + +/// A presence::Announcement received from a node asks for entry into the system. +/// It's not really a "presence" insofar as other means (e.g. health-checks, +/// mixmining, staking etc) are used to determine actual presence, and whether +/// the node is doing the work it should be doing. A presence::Announcement is +/// a node saying "hey, I exist, and am ready to participate, but you need to +/// figure out if I should be made active by the system." +struct Announcement { + host: String, + public_key: String, + node_type: String, + seen_at: NaiveDateTime, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct MixNode { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceProvider { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} + +/// Topology shows us the current state of the overall Nym network +#[derive(Serialize, Deserialize, Debug)] +pub struct Topology { + pub mix_nodes: Vec, + pub service_providers: Vec, + pub validators: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Validator { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 42030b106cf..962a510ab0c 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -1,6 +1,5 @@ use super::*; use iron::status; -use serde::{Deserialize, Serialize}; /// Retrieve the current Nym network topology via HTTP pub fn get(_req: &mut Request) -> IronResult { @@ -12,38 +11,3 @@ pub fn get(_req: &mut Request) -> IronResult { let response = serde_json::to_string_pretty(&topology).unwrap(); Ok(Response::with((status::Ok, response))) } - -/// Topology shows us the current state of the overall Nym network -#[derive(Serialize, Deserialize, Debug)] -pub struct Topology { - pub validators: Vec, - pub mix_nodes: Vec, - pub service_providers: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Validator { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct MixNode { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ServiceProvider { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 863d31c9ab5..81b25ddb14b 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -1,4 +1,4 @@ -use super::staking::Mixnode; +use super::Mixnode; #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 95bb50f6b0c..4774b1244af 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -1,3 +1,96 @@ +use db::MixminingDb; + pub mod db; pub mod health_check_runner; -pub mod staking; + +pub struct Service { + db: MixminingDb, +} + +/// The mixmining::StakeService provides logic for updating and slashing mixnode +/// stake, retrieving lists of mixnodes based on stake, and adding/removing +/// mixnodes from the active set. +/// +/// Mixing and staking interact in interesting ways. Mixnodes first need to announce +/// their presence to the validators. The validators will then proceed to do a +/// health check on them. +/// +/// Once a Mixnode passes its health check, it goes into the stack of available +/// mixnodes. However, it's not necessarily going to start actively mixing traffic. +/// That depends on how much stake is riding on it: we depend on the wisdom of +/// stakers to put their money on trustworthy mixnodes. +/// +/// The active set of mixnodes will be able to expand or contract based on capacity +/// (not yet implemented). For now, we simply take the top N nodes available, +/// ordered by node stake. +/// +/// A lot is going to need to change here. Commented code is here mainly to +/// quickly sketch out the guts of the staking service. This is not the basis +/// of our real staking system quite yet - it's a way to start getting the system +/// to function with all the different node types to start talking to each other, +/// and will be dramatically reworked over the next few months. +impl Service { + pub fn new(db: MixminingDb) -> Service { + Service { db } + } + // Add a mixnode so that it becomes part of the possible mixnode set. + // Presumably it's passed health check. + pub fn add(&self, mixnode: Mixnode) { + println!("Add hit, mixnode: {:?}", mixnode); + } + + /// Update (or create) a given mixnode stake, identified by the mixnode's public key + fn update(&self, public_key: &str, amount: u64) { + // retrieve the given Mixnode from the database and update its stake + } + + /// For now, we have no notion of capacity. Return the top 6 mixnodes, ordered by stake. + fn active_mixnodes(&self) -> Vec { + Vec::::new() + // hit the database + } + + /// Remove a mixnode from the active set in a way that does not impact its stake. + /// The mixnode has done its job well and requested to leave, so it can be removed + /// at the end of an epoch. + fn remove(&self, public_key: &str) { + // free locked up stake back to originating stakeholder + // remove the mixnode from the database + } + + // Add the given amount of stake to the given Mixnode. Presumably it has done + // its job well. + fn reward(&self, public_key: &str, amount: u64) {} + + /// Slash a mixnode's stake based on bad performance or detected malign intent. + fn slash(&self, public_key: &str, amount: u64) { + // transfer slashed stake amount to reserve fund + // retrieve the mixnode from the database, and decrement its stake amount + // by the amount given. + } + + /// Slash a mixnode's stake and immediately remove it from the mixnode set. + fn slash_remove(&self, public_key: String, amount: u64) { + // call slash (the method, not the guitarist) + // remove the mixnode from the database + } +} + +#[derive(Clone, Debug, PartialEq)] +pub struct Mixnode { + pub public_key: String, + pub stake: u64, +} + +#[cfg(test)] +mod test_constructor { + use super::*; + + #[test] + fn test_constructor_sets_database() { + let db = db::MixminingDb::new(); + let service = Service::new(db.clone()); + + assert_eq!(db, service.db); + } +} diff --git a/validator/src/services/mixmining/staking.rs b/validator/src/services/mixmining/staking.rs deleted file mode 100644 index b641427d7cf..00000000000 --- a/validator/src/services/mixmining/staking.rs +++ /dev/null @@ -1,91 +0,0 @@ -use super::db::MixminingDb; - -pub struct StakeService { - db: MixminingDb, -} - -/// The mixmining::StakeService provides logic for updating and slashing mixnode -/// stake, retrieving lists of mixnodes based on stake, and adding/removing -/// mixnodes from the active set. -/// -/// Mixing and staking interact in interesting ways. Mixnodes first need to announce -/// their presence to the validators. The validators will then proceed to do a -/// health check on them. -/// -/// Once a Mixnode passes its health check, it goes into the stack of available -/// mixnodes. However, it's not necessarily going to start actively mixing traffic. -/// That depends on how much stake is riding on it: we depend on the wisdom of -/// stakers to put their money on trustworthy mixnodes. -/// -/// The active set of mixnodes will be able to expand or contract based on capacity -/// (not yet implemented). For now, we simply take the top N nodes available, -/// ordered by node stake. -/// -/// A lot is going to need to change here. Commented code is here mainly to -/// quickly sketch out the guts of the staking service. This is not the basis -/// of our real staking system quite yet - it's a way to start getting the system -/// to function with all the different node types to start talking to each other, -/// and will be dramatically reworked over the next few months. -impl StakeService { - fn new(db: MixminingDb) -> StakeService { - StakeService { db } - } - // Add a mixnode so that it becomes part of the possible mixnode set. - // Presumably it's passed health check. - fn add(&self, mixnode: Mixnode) {} - - /// Update (or create) a given mixnode stake, identified by the mixnode's public key - fn update(&self, public_key: &str, amount: u64) { - // retrieve the given Mixnode from the database and update its stake - } - - /// For now, we have no notion of capacity. Return the top 6 mixnodes, ordered by stake. - fn active_mixnodes(&self) -> Vec { - Vec::::new() - // hit the database - } - - /// Remove a mixnode from the active set in a way that does not impact its stake. - /// The mixnode has done its job well and requested to leave, so it can be removed - /// at the end of an epoch. - fn remove(&self, public_key: &str) { - // free locked up stake back to originating stakeholder - // remove the mixnode from the database - } - - // Add the given amount of stake to the given Mixnode. Presumably it has done - // its job well. - fn reward(&self, public_key: &str, amount: u64) {} - - /// Slash a mixnode's stake based on bad performance or detected malign intent. - fn slash(&self, public_key: &str, amount: u64) { - // transfer slashed stake amount to reserve fund - // retrieve the mixnode from the database, and decrement its stake amount - // by the amount given. - } - - /// Slash a mixnode's stake and immediately remove it from the mixnode set. - fn slash_remove(&self, public_key: String, amount: u64) { - // call slash (the method, not the guitarist) - // remove the mixnode from the database - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct Mixnode { - public_key: String, - stake: u64, -} - -#[cfg(test)] -mod test_constructor { - use super::*; - - #[test] - fn test_constructor_sets_database() { - let db = super::super::db::MixminingDb::new(); - let service = StakeService::new(db.clone()); - - assert_eq!(db, service.db); - } -} From 0d0bc33f0031c7f98c09bf967afb955d0c4cc715 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:25:15 +0000 Subject: [PATCH 18/77] validator: no need for this .env warning --- validator/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 86c9271947c..5aed75ed1d9 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -14,7 +14,6 @@ clap = "2.33.0" chrono = { version = "0.4.11", features = ["serde"] } diesel = { version = "1.4.3", features = ["sqlite"] } dirs = "2.0.2" -# Read notes https://crates.io/crates/dotenv - tl;dr: don't use in production, set environmental variables properly. dotenv = "0.15.0" futures = "0.3.1" iron = "0.6.1" From 7bd7ede1eab7d69440f60fbaed71788ccc9be82d Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:25:36 +0000 Subject: [PATCH 19/77] validator: removing params parser, it's now unused --- validator/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/Cargo.toml b/validator/Cargo.toml index 5aed75ed1d9..d0abd75d3d8 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -18,7 +18,6 @@ dotenv = "0.15.0" futures = "0.3.1" iron = "0.6.1" log = "0.4" -params = "0.8.0" pretty_env_logger = "0.3" router = "0.6.0" serde = "1.0.104" From d5eed7e34633e92ec65e78f1415f0ebc41611813 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:25:52 +0000 Subject: [PATCH 20/77] validator: adding json body parser library for Iron --- validator/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/Cargo.toml b/validator/Cargo.toml index d0abd75d3d8..a5050d43708 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] abci = "0.6.4" +bodyparser = "0.8.0" byteorder = "1.3.2" clap = "2.33.0" chrono = { version = "0.4.11", features = ["serde"] } From 656f79af6d0a29160067ed462200f64d4822438e Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:26:16 +0000 Subject: [PATCH 21/77] validator: adding spelling exceptions --- validator/.vscode/settings.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 validator/.vscode/settings.json diff --git a/validator/.vscode/settings.json b/validator/.vscode/settings.json new file mode 100644 index 00000000000..7a0ac106d72 --- /dev/null +++ b/validator/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "bodyparser" + ] +} \ No newline at end of file From 1a4a43fd35ee70c52f7f46512d48cf87944e30a7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:26:36 +0000 Subject: [PATCH 22/77] validator: adding bodyparser deps --- Cargo.lock | 189 ++--------------------------------------------------- 1 file changed, 6 insertions(+), 183 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0716456b4fc..d983c73570f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,7 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" dependencies = [ - "memchr 2.3.3", + "memchr", ] [[package]] @@ -175,7 +175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" dependencies = [ "byteorder", - "safemem 0.3.3", + "safemem", ] [[package]] @@ -271,16 +271,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae" -[[package]] -name = "buf_redux" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9279646319ff816b05fb5897883ece50d7d854d12b59992683d4f8a71b0f949" -dependencies = [ - "memchr 1.0.2", - "safemem 0.2.0", -] - [[package]] name = "built" version = "0.3.2" @@ -901,7 +891,7 @@ dependencies = [ "futures-macro", "futures-sink", "futures-task", - "memchr 2.3.3", + "memchr", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1359,15 +1349,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -dependencies = [ - "libc", -] - [[package]] name = "memchr" version = "2.3.3" @@ -1540,23 +1521,6 @@ dependencies = [ "tokio 0.2.12", ] -[[package]] -name = "multipart" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92f54eb45230c3aa20864ccf0c277eeaeadcf5e437e91731db498dbf7fbe0ec6" -dependencies = [ - "buf_redux", - "httparse", - "log 0.3.9", - "mime 0.2.6", - "mime_guess 1.8.8", - "rand 0.3.23", - "safemem 0.2.0", - "tempdir", - "twoway", -] - [[package]] name = "native-tls" version = "0.2.3" @@ -1586,42 +1550,6 @@ dependencies = [ "winapi 0.3.8", ] -[[package]] -name = "num" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.4.6", - "rustc-serialize", -] - -[[package]] -name = "num-complex" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" -dependencies = [ - "num-traits", - "rustc-serialize", -] - [[package]] name = "num-integer" version = "0.1.42" @@ -1632,29 +1560,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" -dependencies = [ - "autocfg 1.0.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", - "rustc-serialize", -] - [[package]] name = "num-traits" version = "0.2.11" @@ -1767,6 +1672,7 @@ name = "nym-validator" version = "0.5.0" dependencies = [ "abci", + "bodyparser", "built", "byteorder", "chrono", @@ -1781,7 +1687,6 @@ dependencies = [ "healthcheck", "iron", "log 0.4.8", - "params", "pretty_env_logger", "router", "serde", @@ -1830,22 +1735,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "params" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c789fdad2cfdaa551ea0e3a9eadb74c5d634968a9fb3a8c767d89be470d21589" -dependencies = [ - "bodyparser", - "iron", - "multipart", - "num", - "plugin", - "serde_json", - "tempdir", - "urlencoded", -] - [[package]] name = "parking_lot" version = "0.9.0" @@ -2178,29 +2067,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi 0.3.8", -] - [[package]] name = "rand" version = "0.6.5" @@ -2390,7 +2256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" dependencies = [ "aho-corasick", - "memchr 2.3.3", + "memchr", "regex-syntax", "thread_local", ] @@ -2479,12 +2345,6 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" - [[package]] name = "rustc_version" version = "0.2.3" @@ -2511,12 +2371,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" - [[package]] name = "safemem" version = "0.3.3" @@ -2791,16 +2645,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -dependencies = [ - "rand 0.4.6", - "remove_dir_all", -] - [[package]] name = "tempfile" version = "3.1.0" @@ -2885,7 +2729,7 @@ dependencies = [ "iovec", "lazy_static", "libc", - "memchr 2.3.3", + "memchr", "mio", "mio-named-pipes", "mio-uds", @@ -3110,15 +2954,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr 2.3.3", -] - [[package]] name = "typeable" version = "0.1.2" @@ -3225,18 +3060,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "urlencoded" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a52f50139118b60ae91af08bf15ed158817d34b91b9d24c11ffbe21195d33e3" -dependencies = [ - "bodyparser", - "iron", - "plugin", - "url 1.7.2", -] - [[package]] name = "utf-8" version = "0.7.5" From 397853cc26011de84553421e6883bfc6ddc82d98 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:27:02 +0000 Subject: [PATCH 23/77] validator: ability to (de)serialize Mixnode struct --- validator/src/services/mixmining/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 4774b1244af..4824c7ba7e1 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -1,4 +1,5 @@ use db::MixminingDb; +use serde::{Deserialize, Serialize}; pub mod db; pub mod health_check_runner; @@ -76,7 +77,7 @@ impl Service { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Mixnode { pub public_key: String, pub stake: u64, From 1343af015392a17c98cade8a46b3cac69efd743d Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 14:27:20 +0000 Subject: [PATCH 24/77] validator: further announcement HTTP progress --- .../network/rest/presence/announcements.rs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index d43c6a4a11c..b02a5f48173 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -1,25 +1,27 @@ use super::*; use crate::services::mixmining; +use bodyparser::Struct; use iron::status; -use params::{Params, Value}; - pub fn post(req: &mut Request) -> IronResult { // the part where we check if the worst possible handler code can work. let db = mixmining::db::MixminingDb::new(); let service = mixmining::Service::new(db); - let m = mixmining::Mixnode { - public_key: "foo".to_string(), - stake: 6, + + let maybe_mixnode = match req.get::>() { + Ok(Some(mixnode)) => Ok(mixnode), + Ok(None) => Err("JSON parsing error"), + Err(_) => Err("JSON parsing error"), }; - service.add(m); - // the actual params handling part. - let map = req.get_ref::().unwrap(); - match map.find(&["user", "name"]) { - Some(&Value::String(ref name)) if name == "Marie" => { - Ok(Response::with((status::Ok, "Welcome back, Marie!"))) - } - _ => Ok(Response::with(status::NotFound)), + if maybe_mixnode.is_ok() { + let mixnode = maybe_mixnode.unwrap(); + service.add(mixnode); + Ok(Response::with(status::Created)) + } else { + Ok(Response::with(( + status::BadRequest, + maybe_mixnode.unwrap_err(), + ))) } } From cb349aa1f66733a2be2dc1eac984779be13e0892 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 15:26:30 +0000 Subject: [PATCH 25/77] validator: simplified announcement route --- .../src/network/rest/presence/announcements.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index b02a5f48173..324292d2165 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -8,20 +8,14 @@ pub fn post(req: &mut Request) -> IronResult { let db = mixmining::db::MixminingDb::new(); let service = mixmining::Service::new(db); - let maybe_mixnode = match req.get::>() { - Ok(Some(mixnode)) => Ok(mixnode), - Ok(None) => Err("JSON parsing error"), - Err(_) => Err("JSON parsing error"), - }; + let json_parse = req.get::>(); - if maybe_mixnode.is_ok() { - let mixnode = maybe_mixnode.unwrap(); + if json_parse.is_ok() { + let mixnode = json_parse.unwrap().expect("No JSON supplied"); service.add(mixnode); Ok(Response::with(status::Created)) } else { - Ok(Response::with(( - status::BadRequest, - maybe_mixnode.unwrap_err(), - ))) + let error = json_parse.unwrap_err(); + Ok(Response::with((status::BadRequest, error.detail))) } } From 8235ccc59e47be1e3c09652b856b14aada9d2682 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 16:14:20 +0000 Subject: [PATCH 26/77] validator: injecting database and service into handler --- validator/src/network/rest/mod.rs | 13 +++++--- .../network/rest/presence/announcements.rs | 33 ++++++++++++------- validator/src/validator.rs | 8 +++-- 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 6bea2247bbe..c1001469236 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,25 +1,30 @@ +use crate::services::mixmining; use iron::prelude::*; use presence::announcements; use router::Router; mod presence; -pub struct Api {} +pub struct Api { + mixmining_service: mixmining::Service, +} impl Api { - pub fn new() -> Api { - Api {} + pub fn new(mixmining_service: mixmining::Service) -> Api { + Api { mixmining_service } } pub async fn run(self) { let port = 3000; println!("* starting REST API on localhost:{}", port); + let create_announcement = announcements::Create::new(self.mixmining_service); + let mut router = Router::new(); router.get("/topology", presence::topology::get, "topology_get"); router.post( "/presence/announcements", - announcements::post, + create_announcement, "presence_announcements_post", ); diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index 324292d2165..5b7390cff46 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -1,21 +1,30 @@ use super::*; use crate::services::mixmining; use bodyparser::Struct; +use iron::middleware::Handler; use iron::status; -pub fn post(req: &mut Request) -> IronResult { - // the part where we check if the worst possible handler code can work. - let db = mixmining::db::MixminingDb::new(); - let service = mixmining::Service::new(db); +pub struct Create { + service: mixmining::Service, +} + +impl Create { + pub fn new(service: mixmining::Service) -> Create { + Create { service } + } +} - let json_parse = req.get::>(); +impl Handler for Create { + fn handle(&self, req: &mut Request) -> IronResult { + let json_parse = req.get::>(); - if json_parse.is_ok() { - let mixnode = json_parse.unwrap().expect("No JSON supplied"); - service.add(mixnode); - Ok(Response::with(status::Created)) - } else { - let error = json_parse.unwrap_err(); - Ok(Response::with((status::BadRequest, error.detail))) + if json_parse.is_ok() { + let mixnode = json_parse.unwrap().expect("No JSON supplied"); + self.service.add(mixnode); + Ok(Response::with(status::Created)) + } else { + let error = json_parse.unwrap_err(); + Ok(Response::with((status::BadRequest, error.detail))) + } } } diff --git a/validator/src/validator.rs b/validator/src/validator.rs index 9c12cef95a0..26b8bc1fe3c 100644 --- a/validator/src/validator.rs +++ b/validator/src/validator.rs @@ -1,6 +1,7 @@ use crate::config::Config; use crate::network::rest; use crate::network::tendermint; +use crate::services::mixmining; use crate::services::mixmining::health_check_runner; use crypto::identity::MixIdentityKeyPair; use healthcheck::HealthChecker; @@ -30,7 +31,10 @@ impl Validator { hc, ); - let rest_api = rest::Api::new(); + let db = mixmining::db::MixminingDb::new(); + let mixmining_service = mixmining::Service::new(db); + + let rest_api = rest::Api::new(mixmining_service); Validator { health_check_runner, @@ -49,7 +53,7 @@ impl Validator { rt.spawn(self.rest_api.run()); rt.spawn(self.tendermint_abci.run()); - // TODO: this message is going to come out of order (if at all), as spawns are async + // TODO: this message is going to come out of order (if at all), as spawns are async, see issue above println!("Validator startup complete."); rt.block_on(blocker()); } From 85397d434c0ded7e9eb52db4e2cf2280760a13f6 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 17:19:42 +0000 Subject: [PATCH 27/77] validator: renaming service and db variables --- validator/src/validator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator/src/validator.rs b/validator/src/validator.rs index 26b8bc1fe3c..5c365155910 100644 --- a/validator/src/validator.rs +++ b/validator/src/validator.rs @@ -31,8 +31,8 @@ impl Validator { hc, ); - let db = mixmining::db::MixminingDb::new(); - let mixmining_service = mixmining::Service::new(db); + let mixmining_db = mixmining::db::MixminingDb::new(); + let mixmining_service = mixmining::Service::new(mixmining_db); let rest_api = rest::Api::new(mixmining_service); From 9ff34208f33b258ac52e8f44caf84ed44e22b4ed Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 17:25:06 +0000 Subject: [PATCH 28/77] validator: using camelCase json --- validator/src/services/mixmining/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 4824c7ba7e1..b40ea176391 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -78,6 +78,7 @@ impl Service { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct Mixnode { pub public_key: String, pub stake: u64, From 131e976c0630d88008b6a5445bfd29829df47cf3 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:32:38 +0000 Subject: [PATCH 29/77] validator: using base Iron handler rather than middleware handler --- validator/src/network/rest/presence/announcements.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index 5b7390cff46..63696c49156 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -1,8 +1,8 @@ use super::*; use crate::services::mixmining; use bodyparser::Struct; -use iron::middleware::Handler; use iron::status; +use iron::Handler; pub struct Create { service: mixmining::Service, From 9a96713716cc0aa5beeae34bb84b58b0ed1b2ee7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:33:01 +0000 Subject: [PATCH 30/77] validator: better error message on unexpected json parsing --- validator/src/network/rest/presence/announcements.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index 63696c49156..08f88f2fec2 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -19,7 +19,9 @@ impl Handler for Create { let json_parse = req.get::>(); if json_parse.is_ok() { - let mixnode = json_parse.unwrap().expect("No JSON supplied"); + let mixnode = json_parse + .unwrap() + .expect("Unexpected JSON parsing problem"); self.service.add(mixnode); Ok(Response::with(status::Created)) } else { From 2543516e46b3602bb73a0bfda6c04fe0f636606f Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:33:19 +0000 Subject: [PATCH 31/77] validator: adding 'location' to presence::Announcement --- validator/src/network/rest/presence/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index 8abc904fc7b..2f4fb98c275 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -16,6 +16,7 @@ struct Announcement { public_key: String, node_type: String, seen_at: NaiveDateTime, + location: String, } #[derive(Serialize, Deserialize, Debug)] From 21bd0e898c8807ec70d127ca4954e8ac853a04b1 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:33:35 +0000 Subject: [PATCH 32/77] comments on mixmining::Db --- validator/src/services/mixmining/db.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 81b25ddb14b..7928bca9a94 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -1,5 +1,7 @@ use super::Mixnode; +/// A (currently RAM-based) data store to keep tabs on which nodes have what +/// stake assigned to them. #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { pub mixnodes: Box>, From 614b60a5d22ad6195ef50ca4d5ada0e58fe3bd81 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:34:00 +0000 Subject: [PATCH 33/77] validator: commenting out unused mixmining::Service methods for the moment --- validator/src/services/mixmining/mod.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index b40ea176391..27009853a0b 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -8,9 +8,10 @@ pub struct Service { db: MixminingDb, } -/// The mixmining::StakeService provides logic for updating and slashing mixnode +/// The mixmining::Service provides logic for updating and slashing mixnode /// stake, retrieving lists of mixnodes based on stake, and adding/removing -/// mixnodes from the active set. +/// mixnodes from the active set. It monitors mixnodes and rewards or stakeslashes +/// based on the observed quality of service provided by a given mixnode. /// /// Mixing and staking interact in interesting ways. Mixnodes first need to announce /// their presence to the validators. The validators will then proceed to do a @@ -39,6 +40,7 @@ impl Service { pub fn add(&self, mixnode: Mixnode) { println!("Add hit, mixnode: {:?}", mixnode); } + /* /// Update (or create) a given mixnode stake, identified by the mixnode's public key fn update(&self, public_key: &str, amount: u64) { @@ -51,16 +53,22 @@ impl Service { // hit the database } + /// A fake capacity, so we can take the top n mixnodes based on stake + fn capacity(&self) -> u32 { + 6 + } + /// Remove a mixnode from the active set in a way that does not impact its stake. - /// The mixnode has done its job well and requested to leave, so it can be removed - /// at the end of an epoch. + /// In a more built-out system, this method would mean: + /// "mixnode x has done its job well and requested to leave, so it can be removed + /// at the end of an epoch." fn remove(&self, public_key: &str) { // free locked up stake back to originating stakeholder // remove the mixnode from the database } - // Add the given amount of stake to the given Mixnode. Presumably it has done - // its job well. + /// Add the given amount of stake to the given Mixnode. Presumably it has done + /// its job well. fn reward(&self, public_key: &str, amount: u64) {} /// Slash a mixnode's stake based on bad performance or detected malign intent. @@ -75,6 +83,7 @@ impl Service { // call slash (the method, not the guitarist) // remove the mixnode from the database } + */ } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] From 9bfa746e90cb4fe9fbdd347c0e9cbc20677fd463 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 18:36:02 +0000 Subject: [PATCH 34/77] validator: noting that we don't yet know how to measure capacity --- validator/src/services/mixmining/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 27009853a0b..6e3f5db3773 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -47,7 +47,7 @@ impl Service { // retrieve the given Mixnode from the database and update its stake } - /// For now, we have no notion of capacity. Return the top 6 mixnodes, ordered by stake. + /// For now, we have no notion of measuring capacity. For now just use capacity(). fn active_mixnodes(&self) -> Vec { Vec::::new() // hit the database From 11d606ac848ab0d9e1b53106bb8d18164ab8f312 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 19:06:12 +0000 Subject: [PATCH 35/77] validator: comments --- validator/src/services/mixmining/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 6e3f5db3773..d6315643ca0 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -10,7 +10,7 @@ pub struct Service { /// The mixmining::Service provides logic for updating and slashing mixnode /// stake, retrieving lists of mixnodes based on stake, and adding/removing -/// mixnodes from the active set. It monitors mixnodes and rewards or stakeslashes +/// mixnodes from the active set. It monitors mixnodes and rewards or slashes /// based on the observed quality of service provided by a given mixnode. /// /// Mixing and staking interact in interesting ways. Mixnodes first need to announce From 1cbb6f222346814cc6b62b1358cd34796a853270 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 19:07:52 +0000 Subject: [PATCH 36/77] validator: starting to add correct serializers in rest API --- validator/src/network/rest/presence/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index 2f4fb98c275..cfad82ce003 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -19,7 +19,8 @@ struct Announcement { location: String, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct MixNode { host: String, public_key: String, From bdcfe815a0c2106c836987cbf25bcf3c2171c8e2 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Wed, 25 Mar 2020 19:09:24 +0000 Subject: [PATCH 37/77] validator: renaming a mixnode announcements --- validator/src/network/rest/mod.rs | 4 ++-- validator/src/network/rest/presence/announcements.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index c1001469236..55ccdd93e22 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -18,13 +18,13 @@ impl Api { let port = 3000; println!("* starting REST API on localhost:{}", port); - let create_announcement = announcements::Create::new(self.mixmining_service); + let mixnode_announcement = announcements::MixnodeHandler::new(self.mixmining_service); let mut router = Router::new(); router.get("/topology", presence::topology::get, "topology_get"); router.post( "/presence/announcements", - create_announcement, + mixnode_announcement, "presence_announcements_post", ); diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/announcements.rs index 08f88f2fec2..b2ac39b9b52 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/announcements.rs @@ -4,17 +4,17 @@ use bodyparser::Struct; use iron::status; use iron::Handler; -pub struct Create { +pub struct MixnodeHandler { service: mixmining::Service, } -impl Create { - pub fn new(service: mixmining::Service) -> Create { - Create { service } +impl MixnodeHandler { + pub fn new(service: mixmining::Service) -> MixnodeHandler { + MixnodeHandler { service } } } -impl Handler for Create { +impl Handler for MixnodeHandler { fn handle(&self, req: &mut Request) -> IronResult { let json_parse = req.get::>(); From a341f5219288d404838765e5a651f951bb24faf2 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 14:29:48 +0000 Subject: [PATCH 38/77] validator: extracted route creation --- validator/src/network/rest/mod.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 55ccdd93e22..e1ad12e3714 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -14,22 +14,33 @@ impl Api { Api { mixmining_service } } + /// Run the REST API. pub async fn run(self) { - let port = 3000; - println!("* starting REST API on localhost:{}", port); + let port = 3000; // TODO: make this configurable + let address = format!("localhost:{}", port); + println!("* starting REST API on {}", address); - let mixnode_announcement = announcements::MixnodeHandler::new(self.mixmining_service); + let router = self.setup_router(); + Iron::new(router).http(address).unwrap(); + } + + /// Tie together URL route paths with handler functions. + fn setup_router(self) -> Router { + // define a Router to hold our routes let mut router = Router::new(); + + // set up handlers + let create_mixnode_presence = announcements::MixnodeHandler::new(self.mixmining_service); + + // tie routes to handlers router.get("/topology", presence::topology::get, "topology_get"); router.post( - "/presence/announcements", - mixnode_announcement, - "presence_announcements_post", + "/presence/mixnodes", + create_mixnode_presence, + "presence_mixnodes_post", ); - Iron::new(router) - .http(format!("localhost:{}", port)) - .unwrap(); + router } } From b2608796d84b99fa0538265d5b3fa7103b2d76f0 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 14:35:22 +0000 Subject: [PATCH 39/77] validator: going lower-case for node in "Mixnode" --- validator/src/network/rest/presence/mod.rs | 4 ++-- validator/src/network/rest/presence/topology.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index cfad82ce003..6f69a5a681e 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -21,7 +21,7 @@ struct Announcement { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct MixNode { +pub struct Mixnode { host: String, public_key: String, version: String, @@ -41,7 +41,7 @@ pub struct ServiceProvider { /// Topology shows us the current state of the overall Nym network #[derive(Serialize, Deserialize, Debug)] pub struct Topology { - pub mix_nodes: Vec, + pub mix_nodes: Vec, pub service_providers: Vec, pub validators: Vec, } diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 962a510ab0c..97e29b372e6 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -4,7 +4,7 @@ use iron::status; /// Retrieve the current Nym network topology via HTTP pub fn get(_req: &mut Request) -> IronResult { let topology = Topology { - mix_nodes: Vec::::new(), + mix_nodes: Vec::::new(), service_providers: Vec::::new(), validators: Vec::::new(), }; From 44a49d1c1345cf4d1b6682ce66b7dedafd990fcc Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 14:36:02 +0000 Subject: [PATCH 40/77] validator: removing the "announcement" model --- validator/src/network/rest/presence/mod.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index 6f69a5a681e..d2803ef702d 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -5,20 +5,6 @@ use serde::{Deserialize, Serialize}; pub mod announcements; pub mod topology; -/// A presence::Announcement received from a node asks for entry into the system. -/// It's not really a "presence" insofar as other means (e.g. health-checks, -/// mixmining, staking etc) are used to determine actual presence, and whether -/// the node is doing the work it should be doing. A presence::Announcement is -/// a node saying "hey, I exist, and am ready to participate, but you need to -/// figure out if I should be made active by the system." -struct Announcement { - host: String, - public_key: String, - node_type: String, - seen_at: NaiveDateTime, - location: String, -} - #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Mixnode { From c45e85d0b54b5a05c01324acd639bd68c862ed1d Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 15:17:10 +0000 Subject: [PATCH 41/77] validator: renamed annoucements handlers --- validator/src/network/rest/mod.rs | 4 ++-- .../rest/presence/{announcements.rs => mixnode.rs} | 10 +++++----- validator/src/network/rest/presence/mod.rs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) rename validator/src/network/rest/presence/{announcements.rs => mixnode.rs} (78%) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index e1ad12e3714..39152835eaf 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,6 +1,6 @@ use crate::services::mixmining; use iron::prelude::*; -use presence::announcements; +use presence::mixnode; use router::Router; mod presence; @@ -31,7 +31,7 @@ impl Api { let mut router = Router::new(); // set up handlers - let create_mixnode_presence = announcements::MixnodeHandler::new(self.mixmining_service); + let create_mixnode_presence = mixnode::CreatePresence::new(self.mixmining_service); // tie routes to handlers router.get("/topology", presence::topology::get, "topology_get"); diff --git a/validator/src/network/rest/presence/announcements.rs b/validator/src/network/rest/presence/mixnode.rs similarity index 78% rename from validator/src/network/rest/presence/announcements.rs rename to validator/src/network/rest/presence/mixnode.rs index b2ac39b9b52..e3b89894409 100644 --- a/validator/src/network/rest/presence/announcements.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -4,17 +4,17 @@ use bodyparser::Struct; use iron::status; use iron::Handler; -pub struct MixnodeHandler { +pub struct CreatePresence { service: mixmining::Service, } -impl MixnodeHandler { - pub fn new(service: mixmining::Service) -> MixnodeHandler { - MixnodeHandler { service } +impl CreatePresence { + pub fn new(service: mixmining::Service) -> CreatePresence { + CreatePresence { service } } } -impl Handler for MixnodeHandler { +impl Handler for CreatePresence { fn handle(&self, req: &mut Request) -> IronResult { let json_parse = req.get::>(); diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index d2803ef702d..dc4066003fa 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -1,8 +1,8 @@ use super::*; -use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; -pub mod announcements; +mod conversions; +pub mod mixnode; pub mod topology; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] From 1d82585f7ae3fe9c010a29e9e636a1747ef7cdd7 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 15:17:37 +0000 Subject: [PATCH 42/77] validator: temporarily removed Chrono, remove it fully if it's not needed. --- Cargo.lock | 2 -- validator/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d983c73570f..8127c0a8fab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,7 +354,6 @@ checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" dependencies = [ "num-integer", "num-traits", - "serde", "time", ] @@ -1675,7 +1674,6 @@ dependencies = [ "bodyparser", "built", "byteorder", - "chrono", "clap", "config", "crypto", diff --git a/validator/Cargo.toml b/validator/Cargo.toml index a5050d43708..1a64477f586 100644 --- a/validator/Cargo.toml +++ b/validator/Cargo.toml @@ -12,7 +12,7 @@ abci = "0.6.4" bodyparser = "0.8.0" byteorder = "1.3.2" clap = "2.33.0" -chrono = { version = "0.4.11", features = ["serde"] } +# chrono = { version = "0.4.11", features = ["serde"] } TODO: remove this if I don't start using it again soon diesel = { version = "1.4.3", features = ["sqlite"] } dirs = "2.0.2" dotenv = "0.15.0" From 9b9fed76b7654431a32db67119ad1b4d841fa30f Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:00:53 +0000 Subject: [PATCH 43/77] validator: added all the needed Mixnode fields to the service model --- validator/src/services/mixmining/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index d6315643ca0..9c00f3af247 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -87,10 +87,13 @@ impl Service { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct Mixnode { + pub host: String, pub public_key: String, + pub last_seen: u64, + pub location: String, pub stake: u64, + pub version: String, } #[cfg(test)] From bcac889fc443c9cda8734d6cb867994c90b7974f Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:01:13 +0000 Subject: [PATCH 44/77] validator: moved models into their own file. --- validator/src/network/rest/presence/mod.rs | 38 +----------------- validator/src/network/rest/presence/models.rs | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 validator/src/network/rest/presence/models.rs diff --git a/validator/src/network/rest/presence/mod.rs b/validator/src/network/rest/presence/mod.rs index dc4066003fa..108d75277ea 100644 --- a/validator/src/network/rest/presence/mod.rs +++ b/validator/src/network/rest/presence/mod.rs @@ -1,42 +1,6 @@ use super::*; -use serde::{Deserialize, Serialize}; mod conversions; pub mod mixnode; +mod models; pub mod topology; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Mixnode { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ServiceProvider { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} - -/// Topology shows us the current state of the overall Nym network -#[derive(Serialize, Deserialize, Debug)] -pub struct Topology { - pub mix_nodes: Vec, - pub service_providers: Vec, - pub validators: Vec, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct Validator { - host: String, - public_key: String, - version: String, - last_seen: u64, - location: String, -} diff --git a/validator/src/network/rest/presence/models.rs b/validator/src/network/rest/presence/models.rs new file mode 100644 index 00000000000..ce1d344910b --- /dev/null +++ b/validator/src/network/rest/presence/models.rs @@ -0,0 +1,39 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Mixnode { + pub host: String, + pub public_key: String, + pub version: String, + pub location: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ServiceProvider { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} + +/// Topology shows us the current state of the overall Nym network +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Topology { + pub mix_nodes: Vec, + pub service_providers: Vec, + pub validators: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Validator { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} From 1dd74603770c87864d4a2bc55b11d3d202924522 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:01:29 +0000 Subject: [PATCH 45/77] validator: conversions to/from api vs service models --- .../src/network/rest/presence/conversions.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 validator/src/network/rest/presence/conversions.rs diff --git a/validator/src/network/rest/presence/conversions.rs b/validator/src/network/rest/presence/conversions.rs new file mode 100644 index 00000000000..b5b61499c10 --- /dev/null +++ b/validator/src/network/rest/presence/conversions.rs @@ -0,0 +1,41 @@ +use crate::network::rest::presence::models::Mixnode as PresenceMixnode; +use crate::services::mixmining::Mixnode as ServiceMixnode; +use std::convert::From; +use std::time::{SystemTime, UNIX_EPOCH}; + +impl From for ServiceMixnode { + fn from(value: PresenceMixnode) -> ServiceMixnode { + let now = SystemTime::now(); + let timestamp = now.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64; + ServiceMixnode { + host: value.host, + last_seen: timestamp, + location: value.location, + public_key: value.public_key, + stake: 0, + version: value.version, + } + } +} + +#[cfg(test)] +mod test_presence_conversions_for_mixmining_service { + use super::*; + + #[test] + fn test_converting_presence_mixnode_to_mixmining_service_mixnode() { + let presence_mixnode = PresenceMixnode { + host: "foo.org".to_owned(), + public_key: "abc".to_owned(), + location: "London".to_owned(), + version: "1.0.0".to_owned(), + }; + + let result: ServiceMixnode = presence_mixnode.clone().into(); + assert_eq!(result.host, presence_mixnode.host); + assert_eq!(result.public_key, presence_mixnode.public_key); + assert_eq!(result.location, presence_mixnode.location); + assert_eq!(result.version, presence_mixnode.version); + assert_eq!(result.stake, 0); + } +} From 348260c1f8f5f8da726404fe5544b6997728b47c Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:01:59 +0000 Subject: [PATCH 46/77] validator: doing type conversions from rest to service models --- validator/src/network/rest/presence/mixnode.rs | 7 ++++--- validator/src/network/rest/presence/topology.rs | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/validator/src/network/rest/presence/mixnode.rs b/validator/src/network/rest/presence/mixnode.rs index e3b89894409..489a38fbc02 100644 --- a/validator/src/network/rest/presence/mixnode.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -1,5 +1,6 @@ use super::*; -use crate::services::mixmining; +use crate::network::rest::presence::models::Mixnode as PresenceMixnode; +use crate::services::mixmining::Mixnode as ServiceMixnode; use bodyparser::Struct; use iron::status; use iron::Handler; @@ -16,13 +17,13 @@ impl CreatePresence { impl Handler for CreatePresence { fn handle(&self, req: &mut Request) -> IronResult { - let json_parse = req.get::>(); + let json_parse = req.get::>(); if json_parse.is_ok() { let mixnode = json_parse .unwrap() .expect("Unexpected JSON parsing problem"); - self.service.add(mixnode); + self.service.add(mixnode.into()); Ok(Response::with(status::Created)) } else { let error = json_parse.unwrap_err(); diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 97e29b372e6..92d4196a9ea 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -1,3 +1,4 @@ +use super::models::*; use super::*; use iron::status; From e7c11d51475975b4b6c53d56e4b260448bda09af Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:02:40 +0000 Subject: [PATCH 47/77] validator: unused import cleanup --- validator/src/network/rest/presence/mixnode.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/src/network/rest/presence/mixnode.rs b/validator/src/network/rest/presence/mixnode.rs index 489a38fbc02..e0e06da0b10 100644 --- a/validator/src/network/rest/presence/mixnode.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -1,6 +1,5 @@ use super::*; use crate::network::rest::presence::models::Mixnode as PresenceMixnode; -use crate::services::mixmining::Mixnode as ServiceMixnode; use bodyparser::Struct; use iron::status; use iron::Handler; From 24f9152d970c0c2a4ff742220967f4e3c1c75cee Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:07:08 +0000 Subject: [PATCH 48/77] validator: rewrote mixmining service comments in light of recent thinking --- validator/src/services/mixmining/mod.rs | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 9c00f3af247..4715e8864b8 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -13,21 +13,22 @@ pub struct Service { /// mixnodes from the active set. It monitors mixnodes and rewards or slashes /// based on the observed quality of service provided by a given mixnode. /// -/// Mixing and staking interact in interesting ways. Mixnodes first need to announce -/// their presence to the validators. The validators will then proceed to do a -/// health check on them. +/// Mixing and staking interact. Mixnodes first need to announce +/// their presence to the validators. /// -/// Once a Mixnode passes its health check, it goes into the stack of available -/// mixnodes. However, it's not necessarily going to start actively mixing traffic. -/// That depends on how much stake is riding on it: we depend on the wisdom of -/// stakers to put their money on trustworthy mixnodes. +/// The mixnode then goes into the stack of available mixnodes. /// -/// The active set of mixnodes will be able to expand or contract based on capacity -/// (not yet implemented). For now, we simply take the top N nodes available, -/// ordered by node stake. +/// However, it's not necessarily going to start actively mixing traffic. +/// That depends on how much stake is riding on it, and how much capacity the +/// network requires right now. We depend on the wisdom of stakers to put their +/// money on trustworthy mixnodes. +/// +/// The active set of mixnodes will be able to expand or contract based on capacity. +/// For now, we simply take the top nodes available, ordered by +/// . /// /// A lot is going to need to change here. Commented code is here mainly to -/// quickly sketch out the guts of the staking service. This is not the basis +/// quickly sketch out the guts of the mixmining and staking service. This is not the basis /// of our real staking system quite yet - it's a way to start getting the system /// to function with all the different node types to start talking to each other, /// and will be dramatically reworked over the next few months. @@ -36,9 +37,8 @@ impl Service { Service { db } } // Add a mixnode so that it becomes part of the possible mixnode set. - // Presumably it's passed health check. pub fn add(&self, mixnode: Mixnode) { - println!("Add hit, mixnode: {:?}", mixnode); + println!("Adding mixnode: {:?}", mixnode); } /* From ab993d7f62bc5f4f6efe1c1d1fbdf61e7857b9b2 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 26 Mar 2020 16:30:03 +0000 Subject: [PATCH 49/77] validator: some notes on type conversion tests --- validator/src/network/rest/presence/conversions.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/conversions.rs b/validator/src/network/rest/presence/conversions.rs index b5b61499c10..d583dbfbf8f 100644 --- a/validator/src/network/rest/presence/conversions.rs +++ b/validator/src/network/rest/presence/conversions.rs @@ -35,7 +35,10 @@ mod test_presence_conversions_for_mixmining_service { assert_eq!(result.host, presence_mixnode.host); assert_eq!(result.public_key, presence_mixnode.public_key); assert_eq!(result.location, presence_mixnode.location); - assert_eq!(result.version, presence_mixnode.version); assert_eq!(result.stake, 0); + assert_eq!(result.version, presence_mixnode.version); + // I'm not going to test the last_seen timestamp as I can't be bothered + // setting up a fake clock right now. + // The behaviour is: it should set time to SystemTime::now(). } } From a65d6b4a38516708e1def65e71827fb0d07a598a Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 27 Mar 2020 18:23:59 +0000 Subject: [PATCH 50/77] wip --- validator/src/services/mixmining/db.rs | 8 ++++--- validator/src/services/mixmining/mod.rs | 30 +++++++++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 7928bca9a94..63aed62eedc 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -4,14 +4,16 @@ use super::Mixnode; /// stake assigned to them. #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { - pub mixnodes: Box>, + pub mixnodes: Vec, + pub capacity: u32, } impl MixminingDb { pub fn new() -> MixminingDb { - let mut mixnodes = Vec::::new(); + let mixnodes = Vec::::new(); MixminingDb { - mixnodes: Box::new(mixnodes), + capacity: 0, + mixnodes, } } } diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 4715e8864b8..b6a79220173 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -40,6 +40,16 @@ impl Service { pub fn add(&self, mixnode: Mixnode) { println!("Adding mixnode: {:?}", mixnode); } + + pub fn set_capacity(mut self, capacity: u32) { + self.db.capacity = capacity; + } + + /// A fake capacity, so we can take the top n mixnodes based on stake + fn capacity(&self) -> u32 { + 6 + } + /* /// Update (or create) a given mixnode stake, identified by the mixnode's public key @@ -53,10 +63,6 @@ impl Service { // hit the database } - /// A fake capacity, so we can take the top n mixnodes based on stake - fn capacity(&self) -> u32 { - 6 - } /// Remove a mixnode from the active set in a way that does not impact its stake. /// In a more built-out system, this method would mean: @@ -108,3 +114,19 @@ mod test_constructor { assert_eq!(db, service.db); } } + +#[cfg(test)] +mod test_setting_capacity { + use super::*; + + #[test] + fn setting_capacity_sends_correct_value_to_datastore() { + let mock_db = db::MixminingDb::new(); + let mut service = Service::new(mock_db); + let cap = 3; + + service.set_capacity(cap); + + assert_eq!(3, service.db.capacity); + } +} From 98cc48ffa35aff91ba18e6db6aeb6725e82cbc93 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 31 Mar 2020 10:58:59 +0100 Subject: [PATCH 51/77] validator: getting capacity from db works --- validator/src/services/mixmining/mod.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index b6a79220173..d994b7b64c1 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -41,13 +41,13 @@ impl Service { println!("Adding mixnode: {:?}", mixnode); } - pub fn set_capacity(mut self, capacity: u32) { + pub fn set_capacity(&mut self, capacity: u32) { self.db.capacity = capacity; } /// A fake capacity, so we can take the top n mixnodes based on stake fn capacity(&self) -> u32 { - 6 + self.db.capacity } /* @@ -116,7 +116,7 @@ mod test_constructor { } #[cfg(test)] -mod test_setting_capacity { +mod test_capacity { use super::*; #[test] @@ -129,4 +129,12 @@ mod test_setting_capacity { assert_eq!(3, service.db.capacity); } + + #[test] + fn test_getting_capacity() { + let mut mock_db = db::MixminingDb::new(); + mock_db.capacity = 3; + let service = Service::new(mock_db); + assert_eq!(3, service.capacity()); + } } From 9eecac4c7c1050685e2aacfdf30c8f684860027f Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Tue, 31 Mar 2020 14:39:54 +0100 Subject: [PATCH 52/77] wip --- validator/src/network/rest/mod.rs | 6 ++++-- validator/src/network/rest/presence/mixnode.rs | 2 +- .../src/network/rest/presence/topology.rs | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 39152835eaf..341b80eb195 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -1,6 +1,7 @@ use crate::services::mixmining; use iron::prelude::*; use presence::mixnode; +use presence::topology; use router::Router; mod presence; @@ -31,10 +32,11 @@ impl Api { let mut router = Router::new(); // set up handlers - let create_mixnode_presence = mixnode::CreatePresence::new(self.mixmining_service); + let create_mixnode_presence = mixnode::CreatePresence::new(&self.mixmining_service); + let get_topology = topology::GetTopology::new(&self.mixmining_service); // tie routes to handlers - router.get("/topology", presence::topology::get, "topology_get"); + router.get("/topology", get_topology, "topology_get"); router.post( "/presence/mixnodes", create_mixnode_presence, diff --git a/validator/src/network/rest/presence/mixnode.rs b/validator/src/network/rest/presence/mixnode.rs index e0e06da0b10..9b71be9d4e9 100644 --- a/validator/src/network/rest/presence/mixnode.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -9,7 +9,7 @@ pub struct CreatePresence { } impl CreatePresence { - pub fn new(service: mixmining::Service) -> CreatePresence { + pub fn new(service: &mixmining::Service) -> CreatePresence { CreatePresence { service } } } diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 92d4196a9ea..344ebc2c25a 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -1,6 +1,7 @@ use super::models::*; use super::*; use iron::status; +use iron::Handler; /// Retrieve the current Nym network topology via HTTP pub fn get(_req: &mut Request) -> IronResult { @@ -12,3 +13,20 @@ pub fn get(_req: &mut Request) -> IronResult { let response = serde_json::to_string_pretty(&topology).unwrap(); Ok(Response::with((status::Ok, response))) } + +pub struct GetTopology { + service: mixmining::Service, +} + +impl GetTopology { + pub fn new(service: &mixmining::Service) -> GetTopology { + GetTopology { service } + } +} + +impl Handler for GetTopology { + fn handle(&self, req: &mut Request) -> IronResult { + println!("Getting topology!..."); + Ok(Response::with(status::Ok)) + } +} From d5dea8eeed28aa354889f054e2793fd388396afd Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 11:27:45 +0100 Subject: [PATCH 53/77] validator: eliminating borrows so we can have something pure to mutex out on --- validator/src/network/rest/mod.rs | 4 ++-- validator/src/network/rest/presence/mixnode.rs | 2 +- validator/src/network/rest/presence/topology.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 341b80eb195..ee9d5257034 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -32,8 +32,8 @@ impl Api { let mut router = Router::new(); // set up handlers - let create_mixnode_presence = mixnode::CreatePresence::new(&self.mixmining_service); - let get_topology = topology::GetTopology::new(&self.mixmining_service); + let create_mixnode_presence = mixnode::CreatePresence::new(self.mixmining_service); + let get_topology = topology::GetTopology::new(self.mixmining_service); // tie routes to handlers router.get("/topology", get_topology, "topology_get"); diff --git a/validator/src/network/rest/presence/mixnode.rs b/validator/src/network/rest/presence/mixnode.rs index 9b71be9d4e9..e0e06da0b10 100644 --- a/validator/src/network/rest/presence/mixnode.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -9,7 +9,7 @@ pub struct CreatePresence { } impl CreatePresence { - pub fn new(service: &mixmining::Service) -> CreatePresence { + pub fn new(service: mixmining::Service) -> CreatePresence { CreatePresence { service } } } diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 344ebc2c25a..c789b05d21d 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -19,7 +19,7 @@ pub struct GetTopology { } impl GetTopology { - pub fn new(service: &mixmining::Service) -> GetTopology { + pub fn new(service: mixmining::Service) -> GetTopology { GetTopology { service } } } From 522ac8b526c407d377b3837d4a0464b4b44ba9e8 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 17:26:53 +0100 Subject: [PATCH 54/77] validator: a working mutex on the mixmining service --- validator/src/network/rest/mod.rs | 15 ++-- .../src/network/rest/presence/mixnode.rs | 6 +- .../src/network/rest/presence/topology.rs | 6 +- validator/src/services/mixmining/db.rs | 90 ++++++++++++++++++- 4 files changed, 104 insertions(+), 13 deletions(-) diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index ee9d5257034..67281eb7dbd 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -3,23 +3,27 @@ use iron::prelude::*; use presence::mixnode; use presence::topology; use router::Router; +use std::sync::{Arc, Mutex}; mod presence; pub struct Api { - mixmining_service: mixmining::Service, + mixmining_service: Arc>, } impl Api { pub fn new(mixmining_service: mixmining::Service) -> Api { - Api { mixmining_service } + let service = Arc::new(Mutex::new(mixmining_service)); + Api { + mixmining_service: service, + } } /// Run the REST API. pub async fn run(self) { let port = 3000; // TODO: make this configurable let address = format!("localhost:{}", port); - println!("* starting REST API on {}", address); + println!("* starting REST API on http://{}", address); let router = self.setup_router(); @@ -32,8 +36,9 @@ impl Api { let mut router = Router::new(); // set up handlers - let create_mixnode_presence = mixnode::CreatePresence::new(self.mixmining_service); - let get_topology = topology::GetTopology::new(self.mixmining_service); + let create_mixnode_presence = + mixnode::CreatePresence::new(Arc::clone(&self.mixmining_service)); + let get_topology = topology::GetTopology::new(Arc::clone(&self.mixmining_service)); // tie routes to handlers router.get("/topology", get_topology, "topology_get"); diff --git a/validator/src/network/rest/presence/mixnode.rs b/validator/src/network/rest/presence/mixnode.rs index e0e06da0b10..ed4f46d229d 100644 --- a/validator/src/network/rest/presence/mixnode.rs +++ b/validator/src/network/rest/presence/mixnode.rs @@ -5,11 +5,11 @@ use iron::status; use iron::Handler; pub struct CreatePresence { - service: mixmining::Service, + service: Arc>, } impl CreatePresence { - pub fn new(service: mixmining::Service) -> CreatePresence { + pub fn new(service: Arc>) -> CreatePresence { CreatePresence { service } } } @@ -22,7 +22,7 @@ impl Handler for CreatePresence { let mixnode = json_parse .unwrap() .expect("Unexpected JSON parsing problem"); - self.service.add(mixnode.into()); + self.service.lock().unwrap().add(mixnode.into()); Ok(Response::with(status::Created)) } else { let error = json_parse.unwrap_err(); diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index c789b05d21d..b9b37e6565f 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -15,17 +15,17 @@ pub fn get(_req: &mut Request) -> IronResult { } pub struct GetTopology { - service: mixmining::Service, + service: Arc>, } impl GetTopology { - pub fn new(service: mixmining::Service) -> GetTopology { + pub fn new(service: Arc>) -> GetTopology { GetTopology { service } } } impl Handler for GetTopology { - fn handle(&self, req: &mut Request) -> IronResult { + fn handle(&self, _req: &mut Request) -> IronResult { println!("Getting topology!..."); Ok(Response::with(status::Ok)) } diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 63aed62eedc..120f22fdd6c 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -4,7 +4,7 @@ use super::Mixnode; /// stake assigned to them. #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { - pub mixnodes: Vec, + mixnodes: Vec, pub capacity: u32, } @@ -12,8 +12,94 @@ impl MixminingDb { pub fn new() -> MixminingDb { let mixnodes = Vec::::new(); MixminingDb { - capacity: 0, + capacity: 6, mixnodes, } } + + pub fn add(&mut self, mixnode: Mixnode) { + self.mixnodes.push(mixnode); + } + + pub fn list(&self) -> &Vec { + &self.mixnodes + } + + pub fn set_capacity(&mut self, capacity: u32) { + self.capacity = capacity; + } + + pub fn get_capacity(&self) -> u32 { + self.capacity + } +} + +#[cfg(test)] +mod capacity { + use super::*; + + #[test] + fn starts_at_6() { + let db = MixminingDb::new(); + assert_eq!(6, db.get_capacity()); + } + + #[test] + fn setting_and_getting_work() { + let mut db = MixminingDb::new(); + db.set_capacity(1); + assert_eq!(1, db.get_capacity()); + } +} + +#[cfg(test)] +mod adding_and_retrieving_mixnodes { + use super::*; + + #[test] + fn add_and_retrieve_one_works() { + let node = fake_mixnode("London, UK"); + let mut db = MixminingDb::new(); + + db.add(node.clone()); + + assert_eq!(&node, db.list().first().unwrap()); + } + + #[test] + fn add_and_retrieve_two_works() { + let node1 = fake_mixnode("London, UK"); + let node2 = fake_mixnode("Neuchatel"); + let mut db = MixminingDb::new(); + + db.add(node1.clone()); + db.add(node2.clone()); + + assert_eq!(node1, db.list()[0]); + assert_eq!(node2, db.list()[1]); + } + + #[test] + fn starts_empty() { + let db = MixminingDb::new(); + assert_eq!(0, db.mixnodes.len()); + } + + #[test] + fn calling_list_when_empty_returns_empty_vec() { + let db = MixminingDb::new(); + let empty: Vec = vec![]; + assert_eq!(&empty, db.list()); + } + + fn fake_mixnode(location: &str) -> Mixnode { + Mixnode { + host: String::from("foo.com"), + last_seen: 123, + location: String::from(location), + public_key: String::from("abc123"), + stake: 8, + version: String::from("1.0"), + } + } } From 76d7c6d7eb24427df4788f817f149a2ba759b203 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 17:33:11 +0100 Subject: [PATCH 55/77] validator: renaming mixmining db get_capacity to capacity --- validator/src/services/mixmining/db.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 120f22fdd6c..7d2e19c5a9b 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -29,7 +29,7 @@ impl MixminingDb { self.capacity = capacity; } - pub fn get_capacity(&self) -> u32 { + pub fn capacity(&self) -> u32 { self.capacity } } @@ -41,14 +41,14 @@ mod capacity { #[test] fn starts_at_6() { let db = MixminingDb::new(); - assert_eq!(6, db.get_capacity()); + assert_eq!(6, db.capacity()); } #[test] fn setting_and_getting_work() { let mut db = MixminingDb::new(); db.set_capacity(1); - assert_eq!(1, db.get_capacity()); + assert_eq!(1, db.capacity()); } } From 58c7f52130ed7e866b5c601a27d224d57e28d23d Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 17:33:35 +0100 Subject: [PATCH 56/77] validator: making mixmining db capacity field private, using accessor --- validator/src/services/mixmining/db.rs | 2 +- validator/src/services/mixmining/mod.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 7d2e19c5a9b..03e2b8eb372 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -5,7 +5,7 @@ use super::Mixnode; #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { mixnodes: Vec, - pub capacity: u32, + capacity: u32, } impl MixminingDb { diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index d994b7b64c1..00c40ac8795 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -42,12 +42,12 @@ impl Service { } pub fn set_capacity(&mut self, capacity: u32) { - self.db.capacity = capacity; + self.db.set_capacity(capacity); } /// A fake capacity, so we can take the top n mixnodes based on stake fn capacity(&self) -> u32 { - self.db.capacity + self.db.capacity() } /* @@ -125,15 +125,15 @@ mod test_capacity { let mut service = Service::new(mock_db); let cap = 3; - service.set_capacity(cap); + service.set_capacity(3); - assert_eq!(3, service.db.capacity); + assert_eq!(3, service.capacity()); } #[test] fn test_getting_capacity() { let mut mock_db = db::MixminingDb::new(); - mock_db.capacity = 3; + mock_db.set_capacity(3); let service = Service::new(mock_db); assert_eq!(3, service.capacity()); } From 6d7fb2a25a125026ebda36eb96fb00dba5c395a6 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 18:09:26 +0100 Subject: [PATCH 57/77] validator: local capacity updates working --- validator/src/network/rest/capacity/mod.rs | 62 ++++++++++++++++++++++ validator/src/network/rest/mod.rs | 14 +++-- validator/src/services/mixmining/db.rs | 6 +-- validator/src/services/mixmining/mod.rs | 5 +- 4 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 validator/src/network/rest/capacity/mod.rs diff --git a/validator/src/network/rest/capacity/mod.rs b/validator/src/network/rest/capacity/mod.rs new file mode 100644 index 00000000000..e78b7eb3eec --- /dev/null +++ b/validator/src/network/rest/capacity/mod.rs @@ -0,0 +1,62 @@ +use serde::{Deserialize, Serialize}; + +use super::*; +use bodyparser::Struct; +use iron::mime::Mime; +use iron::status; +use iron::Handler; + +/// Holds data for a capacity update (json) +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Capacity { + value: usize, +} + +pub struct Update { + service: Arc>, +} + +impl Update { + pub fn new(service: Arc>) -> Update { + Update { service } + } +} + +impl Handler for Update { + fn handle(&self, req: &mut Request) -> IronResult { + let json_parse = req.get::>(); + + if json_parse.is_ok() { + let capacity = json_parse + .unwrap() + .expect("Unexpected JSON parsing problem") + .value; + self.service.lock().unwrap().set_capacity(capacity); + Ok(Response::with(status::Created)) + } else { + let error = json_parse.unwrap_err(); + Ok(Response::with((status::BadRequest, error.detail))) + } + } +} + +pub struct Get { + service: Arc>, +} + +impl Get { + pub fn new(service: Arc>) -> Get { + Get { service } + } +} + +impl Handler for Get { + fn handle(&self, req: &mut Request) -> IronResult { + let content_type = "application/json".parse::().unwrap(); + let value = self.service.lock().unwrap().capacity(); + let c = Capacity { value }; + let json = serde_json::to_string(&c).unwrap(); + Ok(Response::with((content_type, status::Ok, json))) + } +} diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index 67281eb7dbd..ca646db6394 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -5,7 +5,9 @@ use presence::topology; use router::Router; use std::sync::{Arc, Mutex}; +mod capacity; mod presence; +mod stakes; pub struct Api { mixmining_service: Arc>, @@ -36,15 +38,19 @@ impl Api { let mut router = Router::new(); // set up handlers - let create_mixnode_presence = + let capacity_update = capacity::Update::new(Arc::clone(&self.mixmining_service)); + let capacity_get = capacity::Get::new(Arc::clone(&self.mixmining_service)); + let presence_mixnode_create = mixnode::CreatePresence::new(Arc::clone(&self.mixmining_service)); - let get_topology = topology::GetTopology::new(Arc::clone(&self.mixmining_service)); + let topology_get = topology::GetTopology::new(Arc::clone(&self.mixmining_service)); // tie routes to handlers - router.get("/topology", get_topology, "topology_get"); + router.get("/capacity", capacity_get, "capacity_get"); + router.post("/capacity", capacity_update, "capacity_update"); + router.get("/topology", topology_get, "topology_get"); router.post( "/presence/mixnodes", - create_mixnode_presence, + presence_mixnode_create, "presence_mixnodes_post", ); diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index 03e2b8eb372..c0a8a71e2a6 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -5,7 +5,7 @@ use super::Mixnode; #[derive(Clone, Debug, PartialEq)] pub struct MixminingDb { mixnodes: Vec, - capacity: u32, + capacity: usize, } impl MixminingDb { @@ -25,11 +25,11 @@ impl MixminingDb { &self.mixnodes } - pub fn set_capacity(&mut self, capacity: u32) { + pub fn set_capacity(&mut self, capacity: usize) { self.capacity = capacity; } - pub fn capacity(&self) -> u32 { + pub fn capacity(&self) -> usize { self.capacity } } diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 00c40ac8795..fb7c5edab81 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -36,17 +36,18 @@ impl Service { pub fn new(db: MixminingDb) -> Service { Service { db } } + // Add a mixnode so that it becomes part of the possible mixnode set. pub fn add(&self, mixnode: Mixnode) { println!("Adding mixnode: {:?}", mixnode); } - pub fn set_capacity(&mut self, capacity: u32) { + pub fn set_capacity(&mut self, capacity: usize) { self.db.set_capacity(capacity); } /// A fake capacity, so we can take the top n mixnodes based on stake - fn capacity(&self) -> u32 { + pub fn capacity(&self) -> usize { self.db.capacity() } From eba02a0f2bb333732fa2deb5553e447d07886ee6 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 18:21:01 +0100 Subject: [PATCH 58/77] validator: starting REST API for staking --- validator/src/network/rest/mod.rs | 2 +- validator/src/network/rest/staking/mod.rs | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 validator/src/network/rest/staking/mod.rs diff --git a/validator/src/network/rest/mod.rs b/validator/src/network/rest/mod.rs index ca646db6394..957411abe9a 100644 --- a/validator/src/network/rest/mod.rs +++ b/validator/src/network/rest/mod.rs @@ -7,7 +7,7 @@ use std::sync::{Arc, Mutex}; mod capacity; mod presence; -mod stakes; +mod staking; pub struct Api { mixmining_service: Arc>, diff --git a/validator/src/network/rest/staking/mod.rs b/validator/src/network/rest/staking/mod.rs new file mode 100644 index 00000000000..e69de29bb2d From 04d2ac0565553c3b7841a9a90f63550e33f72978 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 18:21:42 +0100 Subject: [PATCH 59/77] validator: fixing clippy warning --- validator/src/network/rest/capacity/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/network/rest/capacity/mod.rs b/validator/src/network/rest/capacity/mod.rs index e78b7eb3eec..c9b77fe3d9d 100644 --- a/validator/src/network/rest/capacity/mod.rs +++ b/validator/src/network/rest/capacity/mod.rs @@ -52,7 +52,7 @@ impl Get { } impl Handler for Get { - fn handle(&self, req: &mut Request) -> IronResult { + fn handle(&self, _: &mut Request) -> IronResult { let content_type = "application/json".parse::().unwrap(); let value = self.service.lock().unwrap().capacity(); let c = Capacity { value }; From dd854d3e7138d6650f8c8de59f7796f1ca87fe19 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Thu, 2 Apr 2020 18:23:51 +0100 Subject: [PATCH 60/77] validator: minor naming fixes on mixmining service --- validator/src/services/mixmining/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index fb7c5edab81..0e7bff3d506 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -104,11 +104,11 @@ pub struct Mixnode { } #[cfg(test)] -mod test_constructor { +mod constructor { use super::*; #[test] - fn test_constructor_sets_database() { + fn sets_database() { let db = db::MixminingDb::new(); let service = Service::new(db.clone()); @@ -117,14 +117,13 @@ mod test_constructor { } #[cfg(test)] -mod test_capacity { +mod capacity { use super::*; #[test] fn setting_capacity_sends_correct_value_to_datastore() { let mock_db = db::MixminingDb::new(); let mut service = Service::new(mock_db); - let cap = 3; service.set_capacity(3); @@ -132,7 +131,7 @@ mod test_capacity { } #[test] - fn test_getting_capacity() { + fn getting_capacity_works() { let mut mock_db = db::MixminingDb::new(); mock_db.set_capacity(3); let service = Service::new(mock_db); From e43b9500ac0b825e951fab536ff796daa460faa3 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:41:07 +0100 Subject: [PATCH 61/77] validator: service mixnode and rest mixnode + topology conversions + tests --- .../src/network/rest/presence/conversions.rs | 80 ++++++++++++++++--- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/validator/src/network/rest/presence/conversions.rs b/validator/src/network/rest/presence/conversions.rs index d583dbfbf8f..5229ea1ec97 100644 --- a/validator/src/network/rest/presence/conversions.rs +++ b/validator/src/network/rest/presence/conversions.rs @@ -1,10 +1,12 @@ -use crate::network::rest::presence::models::Mixnode as PresenceMixnode; -use crate::services::mixmining::Mixnode as ServiceMixnode; +use crate::network::rest::presence::models::Mixnode as RestMixnode; +use crate::network::rest::presence::models::Topology as RestTopology; +use crate::services::mixmining::models::Mixnode as ServiceMixnode; +use crate::services::mixmining::models::Topology as ServiceTopology; use std::convert::From; use std::time::{SystemTime, UNIX_EPOCH}; -impl From for ServiceMixnode { - fn from(value: PresenceMixnode) -> ServiceMixnode { +impl From for ServiceMixnode { + fn from(value: RestMixnode) -> ServiceMixnode { let now = SystemTime::now(); let timestamp = now.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64; ServiceMixnode { @@ -18,27 +20,79 @@ impl From for ServiceMixnode { } } +impl From for ServiceTopology { + fn from(value: RestTopology) -> ServiceTopology { + let mut converted_mixnodes: Vec = Vec::new(); + for mixnode in value.mixnodes { + converted_mixnodes.push(mixnode.into()); + } + ServiceTopology { + mixnodes: converted_mixnodes.to_vec(), + service_providers: vec![], // add these when they exist + validators: vec![], // add these when they exist + } + } +} + #[cfg(test)] mod test_presence_conversions_for_mixmining_service { + + fn mixnode_fixture() -> RestMixnode { + RestMixnode { + host: "foo.org".to_owned(), + public_key: "abc".to_owned(), + location: "London".to_owned(), + version: "1.0.0".to_owned(), + } + } + use super::*; #[test] - fn test_converting_presence_mixnode_to_mixmining_service_mixnode() { - let presence_mixnode = PresenceMixnode { + fn test_converting_rest_mixnode_to_mixmining_service_mixnode() { + let rest_mixnode = mixnode_fixture(); + let result: ServiceMixnode = rest_mixnode.clone().into(); + assert_eq!(result.host, rest_mixnode.host); + assert_eq!(result.public_key, rest_mixnode.public_key); + assert_eq!(result.location, rest_mixnode.location); + assert_eq!(result.stake, 0); + assert_eq!(result.version, rest_mixnode.version); + // I'm not going to test the last_seen timestamp as I can't be bothered + // setting up a fake clock right now. + // The behaviour is: it should set time to SystemTime::now(). + } + + #[test] + fn test_building_service_mixnode_from_rest_mixnode() { + let rest_mixnode = RestMixnode { host: "foo.org".to_owned(), - public_key: "abc".to_owned(), + // last_seen: 1234, location: "London".to_owned(), + public_key: "abc".to_owned(), + // stake: 0, version: "1.0.0".to_owned(), }; - - let result: ServiceMixnode = presence_mixnode.clone().into(); - assert_eq!(result.host, presence_mixnode.host); - assert_eq!(result.public_key, presence_mixnode.public_key); - assert_eq!(result.location, presence_mixnode.location); + let result = ServiceMixnode::from(rest_mixnode.clone()); + assert_eq!(result.host, rest_mixnode.host); + assert_eq!(result.public_key, rest_mixnode.public_key); + assert_eq!(result.location, rest_mixnode.location); assert_eq!(result.stake, 0); - assert_eq!(result.version, presence_mixnode.version); + assert_eq!(result.version, rest_mixnode.version); // I'm not going to test the last_seen timestamp as I can't be bothered // setting up a fake clock right now. // The behaviour is: it should set time to SystemTime::now(). } + + #[test] + fn test_converting_service_topology_into_rest_topology() { + let rest_topology = RestTopology { + mixnodes: vec![mixnode_fixture()], + service_providers: vec![], + validators: vec![], + }; + + let service_topology: ServiceTopology = rest_topology.into(); + let service_mixnode: ServiceMixnode = mixnode_fixture().into(); + assert_eq!(service_mixnode, service_topology.mixnodes[0]); + } } From c0231ab6f7666e515f70a1c9eb54b3194663f6ed Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:41:55 +0100 Subject: [PATCH 62/77] validator: renaming mix_nodes to mixnodes for consistency --- validator/src/network/rest/presence/models.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/models.rs b/validator/src/network/rest/presence/models.rs index ce1d344910b..94a0dfd83cb 100644 --- a/validator/src/network/rest/presence/models.rs +++ b/validator/src/network/rest/presence/models.rs @@ -23,7 +23,7 @@ pub struct ServiceProvider { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Topology { - pub mix_nodes: Vec, + pub mixnodes: Vec, pub service_providers: Vec, pub validators: Vec, } From afa624c70a7de2f17119668a8705190786d29abe Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:42:44 +0100 Subject: [PATCH 63/77] validator: test fixtures for mixnode --- validator/src/services/mixmining/tests/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 validator/src/services/mixmining/tests/mod.rs diff --git a/validator/src/services/mixmining/tests/mod.rs b/validator/src/services/mixmining/tests/mod.rs new file mode 100644 index 00000000000..246d74b9a6f --- /dev/null +++ b/validator/src/services/mixmining/tests/mod.rs @@ -0,0 +1,13 @@ +use super::Mixnode; + +#[cfg(test)] +pub fn fake_mixnode(location: &str) -> Mixnode { + Mixnode { + host: String::from("foo.com"), + last_seen: 123, + location: String::from(location), + public_key: String::from("abc123"), + stake: 8, + version: String::from("1.0"), + } +} From 599755659236c6680b3e327d47452d6d2aa7cd71 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:43:03 +0100 Subject: [PATCH 64/77] validator: moved service models into their own file --- validator/src/services/mixmining/models.rs | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 validator/src/services/mixmining/models.rs diff --git a/validator/src/services/mixmining/models.rs b/validator/src/services/mixmining/models.rs new file mode 100644 index 00000000000..bff8702ed78 --- /dev/null +++ b/validator/src/services/mixmining/models.rs @@ -0,0 +1,51 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Mixnode { + pub host: String, + pub public_key: String, + pub last_seen: u64, + pub location: String, + pub stake: u64, + pub version: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceProvider { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} + +/// Topology shows us the current state of the overall Nym network +#[derive(Serialize, Deserialize, Debug)] +pub struct Topology { + pub mixnodes: Vec, + pub service_providers: Vec, + pub validators: Vec, +} + +impl Topology { + pub fn new( + mixnodes: Vec, + service_providers: Vec, + validators: Vec, + ) -> Topology { + Topology { + mixnodes, + service_providers, + validators, + } + } +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Validator { + host: String, + public_key: String, + version: String, + last_seen: u64, + location: String, +} From f81441e2f74611b22c790ecd6428ca9af0c571f8 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:43:24 +0100 Subject: [PATCH 65/77] validator: a properly-structured toplogy route --- validator/src/network/rest/presence/topology.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index b9b37e6565f..7ba9fd1c5cc 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -1,19 +1,7 @@ -use super::models::*; use super::*; use iron::status; use iron::Handler; -/// Retrieve the current Nym network topology via HTTP -pub fn get(_req: &mut Request) -> IronResult { - let topology = Topology { - mix_nodes: Vec::::new(), - service_providers: Vec::::new(), - validators: Vec::::new(), - }; - let response = serde_json::to_string_pretty(&topology).unwrap(); - Ok(Response::with((status::Ok, response))) -} - pub struct GetTopology { service: Arc>, } @@ -27,6 +15,9 @@ impl GetTopology { impl Handler for GetTopology { fn handle(&self, _req: &mut Request) -> IronResult { println!("Getting topology!..."); - Ok(Response::with(status::Ok)) + let service_topology = self.service.lock().unwrap().topology(); + let topology = service_topology; //models::Topology::from(service_topology); + let response = serde_json::to_string_pretty(&topology).unwrap(); + Ok(Response::with((status::Ok, response))) } } From 4d4ecb9332a17181ede6d875a0cbcb366cdbec40 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:43:41 +0100 Subject: [PATCH 66/77] validator: topology retrieval --- validator/src/services/mixmining/db.rs | 10 +++--- validator/src/services/mixmining/mod.rs | 45 +++++++++++++++++++------ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/validator/src/services/mixmining/db.rs b/validator/src/services/mixmining/db.rs index c0a8a71e2a6..c53a2e19f0b 100644 --- a/validator/src/services/mixmining/db.rs +++ b/validator/src/services/mixmining/db.rs @@ -21,7 +21,7 @@ impl MixminingDb { self.mixnodes.push(mixnode); } - pub fn list(&self) -> &Vec { + pub fn get_mixnodes(&self) -> &Vec { &self.mixnodes } @@ -63,7 +63,7 @@ mod adding_and_retrieving_mixnodes { db.add(node.clone()); - assert_eq!(&node, db.list().first().unwrap()); + assert_eq!(&node, db.get_mixnodes().first().unwrap()); } #[test] @@ -75,8 +75,8 @@ mod adding_and_retrieving_mixnodes { db.add(node1.clone()); db.add(node2.clone()); - assert_eq!(node1, db.list()[0]); - assert_eq!(node2, db.list()[1]); + assert_eq!(node1, db.get_mixnodes()[0]); + assert_eq!(node2, db.get_mixnodes()[1]); } #[test] @@ -89,7 +89,7 @@ mod adding_and_retrieving_mixnodes { fn calling_list_when_empty_returns_empty_vec() { let db = MixminingDb::new(); let empty: Vec = vec![]; - assert_eq!(&empty, db.list()); + assert_eq!(&empty, db.get_mixnodes()); } fn fake_mixnode(location: &str) -> Mixnode { diff --git a/validator/src/services/mixmining/mod.rs b/validator/src/services/mixmining/mod.rs index 0e7bff3d506..9af7dbb73fc 100644 --- a/validator/src/services/mixmining/mod.rs +++ b/validator/src/services/mixmining/mod.rs @@ -1,8 +1,10 @@ use db::MixminingDb; -use serde::{Deserialize, Serialize}; +use models::*; pub mod db; pub mod health_check_runner; +pub mod models; +mod tests; pub struct Service { db: MixminingDb, @@ -38,8 +40,15 @@ impl Service { } // Add a mixnode so that it becomes part of the possible mixnode set. - pub fn add(&self, mixnode: Mixnode) { - println!("Adding mixnode: {:?}", mixnode); + pub fn add(&mut self, mixnode: Mixnode) { + self.db.add(mixnode); + } + + pub fn topology(&self) -> Topology { + let mixnodes = self.db.get_mixnodes(); + let service_providers: Vec = vec![]; + let validators: Vec = vec![]; + Topology::new(mixnodes.to_vec(), service_providers, validators) } pub fn set_capacity(&mut self, capacity: usize) { @@ -93,14 +102,28 @@ impl Service { */ } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Mixnode { - pub host: String, - pub public_key: String, - pub last_seen: u64, - pub location: String, - pub stake: u64, - pub version: String, +#[cfg(test)] +mod mixnodes { + use super::*; + + #[test] + fn adding_and_retrieving_works() { + let mock_db = MixminingDb::new(); + let mut service = Service::new(mock_db); + let node1 = tests::fake_mixnode("London, UK"); + + service.add(node1.clone()); + let nodes = service.topology().mixnodes; + assert_eq!(1, nodes.len()); + assert_eq!(node1.clone(), nodes[0]); + let node2 = tests::fake_mixnode("Neuchatel"); + + service.add(node2.clone()); + let nodes = service.topology().mixnodes; + assert_eq!(2, nodes.len()); + assert_eq!(node1.clone(), nodes[0]); + assert_eq!(node2.clone(), nodes[1]); + } } #[cfg(test)] From cf5e7bb6b37484240c9bf84e419bb593fe69d927 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:45:25 +0100 Subject: [PATCH 67/77] validator: killed test fixture warning --- validator/src/services/mixmining/tests/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/validator/src/services/mixmining/tests/mod.rs b/validator/src/services/mixmining/tests/mod.rs index 246d74b9a6f..fac930f9022 100644 --- a/validator/src/services/mixmining/tests/mod.rs +++ b/validator/src/services/mixmining/tests/mod.rs @@ -1,8 +1,6 @@ -use super::Mixnode; - #[cfg(test)] -pub fn fake_mixnode(location: &str) -> Mixnode { - Mixnode { +pub fn fake_mixnode(location: &str) -> super::Mixnode { + super::Mixnode { host: String::from("foo.com"), last_seen: 123, location: String::from(location), From b685903527548c366989b1f38434c647865bc834 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 13:55:03 +0100 Subject: [PATCH 68/77] validator: getting set for topology equality checks (testing purposes) --- validator/src/network/rest/presence/models.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validator/src/network/rest/presence/models.rs b/validator/src/network/rest/presence/models.rs index 94a0dfd83cb..60293d930d0 100644 --- a/validator/src/network/rest/presence/models.rs +++ b/validator/src/network/rest/presence/models.rs @@ -9,7 +9,7 @@ pub struct Mixnode { pub location: String, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct ServiceProvider { host: String, @@ -20,7 +20,7 @@ pub struct ServiceProvider { } /// Topology shows us the current state of the overall Nym network -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Topology { pub mixnodes: Vec, @@ -28,7 +28,7 @@ pub struct Topology { pub validators: Vec, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Validator { host: String, From 324a6c4bf203a7832218853a543cb11cecaf708a Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:12:15 +0100 Subject: [PATCH 69/77] validator: otherway conversions for topology and mixnode types --- .../src/network/rest/presence/conversions.rs | 93 ++++++++++++------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/validator/src/network/rest/presence/conversions.rs b/validator/src/network/rest/presence/conversions.rs index 5229ea1ec97..703d97000b4 100644 --- a/validator/src/network/rest/presence/conversions.rs +++ b/validator/src/network/rest/presence/conversions.rs @@ -20,6 +20,17 @@ impl From for ServiceMixnode { } } +impl From for RestMixnode { + fn from(value: ServiceMixnode) -> RestMixnode { + RestMixnode { + host: value.host, + location: value.location, + public_key: value.public_key, + version: value.version, + } + } +} + impl From for ServiceTopology { fn from(value: RestTopology) -> ServiceTopology { let mut converted_mixnodes: Vec = Vec::new(); @@ -28,16 +39,29 @@ impl From for ServiceTopology { } ServiceTopology { mixnodes: converted_mixnodes.to_vec(), - service_providers: vec![], // add these when they exist - validators: vec![], // add these when they exist + service_providers: vec![], // add these when conversions exist + validators: vec![], // add these when conversions exist + } + } +} + +impl From for RestTopology { + fn from(value: ServiceTopology) -> RestTopology { + let mut converted_mixnodes: Vec = Vec::new(); + for mixnode in value.mixnodes { + converted_mixnodes.push(mixnode.into()); + } + RestTopology { + mixnodes: converted_mixnodes.to_vec(), + service_providers: vec![], // add these when conversions exist + validators: vec![], // add these when conversions exist } } } #[cfg(test)] mod test_presence_conversions_for_mixmining_service { - - fn mixnode_fixture() -> RestMixnode { + fn rest_mixnode_fixture() -> RestMixnode { RestMixnode { host: "foo.org".to_owned(), public_key: "abc".to_owned(), @@ -46,53 +70,54 @@ mod test_presence_conversions_for_mixmining_service { } } + fn service_mixnode_fixture() -> ServiceMixnode { + ServiceMixnode { + host: "foo.org".to_owned(), + public_key: "abc".to_owned(), + last_seen: 1234, + location: "London".to_owned(), + stake: 0, + version: "1.0.0".to_owned(), + } + } + use super::*; #[test] - fn test_converting_rest_mixnode_to_mixmining_service_mixnode() { - let rest_mixnode = mixnode_fixture(); - let result: ServiceMixnode = rest_mixnode.clone().into(); - assert_eq!(result.host, rest_mixnode.host); - assert_eq!(result.public_key, rest_mixnode.public_key); - assert_eq!(result.location, rest_mixnode.location); - assert_eq!(result.stake, 0); - assert_eq!(result.version, rest_mixnode.version); + fn test_building_service_mixnode_from_rest_mixnode() { + let rest_mixnode = rest_mixnode_fixture(); + let service_mixnode = ServiceMixnode::from(rest_mixnode.clone()); + assert_eq!(service_mixnode.host, rest_mixnode.host); + assert_eq!(service_mixnode.public_key, rest_mixnode.public_key); + assert_eq!(service_mixnode.location, rest_mixnode.location); + assert_eq!(service_mixnode.stake, 0); + assert_eq!(service_mixnode.version, rest_mixnode.version); // I'm not going to test the last_seen timestamp as I can't be bothered // setting up a fake clock right now. // The behaviour is: it should set time to SystemTime::now(). } #[test] - fn test_building_service_mixnode_from_rest_mixnode() { - let rest_mixnode = RestMixnode { - host: "foo.org".to_owned(), - // last_seen: 1234, - location: "London".to_owned(), - public_key: "abc".to_owned(), - // stake: 0, - version: "1.0.0".to_owned(), - }; - let result = ServiceMixnode::from(rest_mixnode.clone()); - assert_eq!(result.host, rest_mixnode.host); - assert_eq!(result.public_key, rest_mixnode.public_key); - assert_eq!(result.location, rest_mixnode.location); - assert_eq!(result.stake, 0); - assert_eq!(result.version, rest_mixnode.version); - // I'm not going to test the last_seen timestamp as I can't be bothered - // setting up a fake clock right now. - // The behaviour is: it should set time to SystemTime::now(). + fn test_building_rest_mixnode_from_service_mixnode() { + let service_mixnode = service_mixnode_fixture(); + let rest_mixnode = RestMixnode::from(service_mixnode.clone()); + assert_eq!(rest_mixnode.host, service_mixnode.host); + assert_eq!(rest_mixnode.public_key, service_mixnode.public_key); + assert_eq!(rest_mixnode.location, service_mixnode.location); + assert_eq!(rest_mixnode.version, service_mixnode.version); } #[test] - fn test_converting_service_topology_into_rest_topology() { + fn test_building_service_topology_from_rest_topology() { + let rest_mixnode = rest_mixnode_fixture(); let rest_topology = RestTopology { - mixnodes: vec![mixnode_fixture()], + mixnodes: vec![rest_mixnode.clone()], service_providers: vec![], validators: vec![], }; - let service_topology: ServiceTopology = rest_topology.into(); - let service_mixnode: ServiceMixnode = mixnode_fixture().into(); + let service_topology = ServiceTopology::from(rest_topology); + let service_mixnode = ServiceMixnode::from(rest_mixnode); assert_eq!(service_mixnode, service_topology.mixnodes[0]); } } From 66bda28b3db364773c1f748b4cde19a9d8705a7a Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:14:16 +0100 Subject: [PATCH 70/77] validator: initial topology retrieval working --- validator/src/network/rest/presence/topology.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/network/rest/presence/topology.rs b/validator/src/network/rest/presence/topology.rs index 7ba9fd1c5cc..46517c62f70 100644 --- a/validator/src/network/rest/presence/topology.rs +++ b/validator/src/network/rest/presence/topology.rs @@ -16,7 +16,7 @@ impl Handler for GetTopology { fn handle(&self, _req: &mut Request) -> IronResult { println!("Getting topology!..."); let service_topology = self.service.lock().unwrap().topology(); - let topology = service_topology; //models::Topology::from(service_topology); + let topology = models::Topology::from(service_topology); let response = serde_json::to_string_pretty(&topology).unwrap(); Ok(Response::with((status::Ok, response))) } From 535ae4a1ac5afaca3b76ba3af6a6ee0528ec7873 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:15:44 +0100 Subject: [PATCH 71/77] validator: ditching go-ish variable name :) --- validator/src/network/tendermint/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/validator/src/network/tendermint/mod.rs b/validator/src/network/tendermint/mod.rs index 563760ea3df..12538e7014c 100644 --- a/validator/src/network/tendermint/mod.rs +++ b/validator/src/network/tendermint/mod.rs @@ -32,18 +32,18 @@ impl abci::Application for Abci { fn check_tx(&mut self, req: &RequestCheckTx) -> ResponseCheckTx { // Get the Tx [u8] and convert to u64 let c = convert_tx(req.get_tx()); - let mut resp = ResponseCheckTx::new(); + let mut response = ResponseCheckTx::new(); // Validation logic if c != self.count + 1 { - resp.set_code(1); - resp.set_log(String::from("Count must be incremental!")); - return resp; + response.set_code(1); + response.set_log(String::from("Count must be incremental!")); + return response; } // Update state to keep state correct for next check_tx call self.count = c; - resp + response } fn deliver_tx(&mut self, req: &RequestDeliverTx) -> ResponseDeliverTx { From d7be51243b28ccd560aff5c6a9db4ed05aa2d70b Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:16:06 +0100 Subject: [PATCH 72/77] ibid --- validator/src/network/tendermint/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validator/src/network/tendermint/mod.rs b/validator/src/network/tendermint/mod.rs index 12538e7014c..baa77de9a18 100644 --- a/validator/src/network/tendermint/mod.rs +++ b/validator/src/network/tendermint/mod.rs @@ -57,12 +57,12 @@ impl abci::Application for Abci { fn commit(&mut self, _req: &RequestCommit) -> ResponseCommit { // Create the response - let mut resp = ResponseCommit::new(); + let mut response = ResponseCommit::new(); // Convert count to bits let mut buf = [0; 8]; BigEndian::write_u64(&mut buf, self.count); // Set data so last state is included in the block - resp.set_data(buf.to_vec()); - resp + response.set_data(buf.to_vec()); + response } } From 36d4f04ca3ba7fec7c4e60d139a114c11cffba53 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:43:42 +0100 Subject: [PATCH 73/77] validator: added a StakeUpdate struct to get around cargo fmt failing --- validator/src/network/rest/staking/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/src/network/rest/staking/mod.rs b/validator/src/network/rest/staking/mod.rs index e69de29bb2d..e46e00127b3 100644 --- a/validator/src/network/rest/staking/mod.rs +++ b/validator/src/network/rest/staking/mod.rs @@ -0,0 +1 @@ +pub struct StakeUpdate {} From 8737a0ee7da4d63073839389da4859ac3f675469 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Fri, 3 Apr 2020 14:46:28 +0100 Subject: [PATCH 74/77] validator: commenting out struct so kill warning --- validator/src/network/rest/staking/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/src/network/rest/staking/mod.rs b/validator/src/network/rest/staking/mod.rs index e46e00127b3..b4780ebde8d 100644 --- a/validator/src/network/rest/staking/mod.rs +++ b/validator/src/network/rest/staking/mod.rs @@ -1 +1 @@ -pub struct StakeUpdate {} +// pub struct StakeUpdate {} From 19868398c6a02988a3b6b7fddea435f512f39af6 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Mon, 6 Apr 2020 16:36:22 +0100 Subject: [PATCH 75/77] Ignoring validator vscode settings --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0e2a851081d..78a344df707 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ target .env /.vscode/settings.json +/validator/.vscode/settings.json sample-configs/validator-config.toml \ No newline at end of file From c54775149f80de01f18fc75a7f232f509365e75b Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Mon, 6 Apr 2020 16:36:59 +0100 Subject: [PATCH 76/77] ibid --- validator/.vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 validator/.vscode/settings.json diff --git a/validator/.vscode/settings.json b/validator/.vscode/settings.json deleted file mode 100644 index 7a0ac106d72..00000000000 --- a/validator/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "bodyparser" - ] -} \ No newline at end of file From 2da3a8bfade3a265be1fb51c149c250358c64db9 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Mon, 6 Apr 2020 16:38:11 +0100 Subject: [PATCH 77/77] ibid --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 78a344df707..dd3546d3290 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,5 @@ target .env /.vscode/settings.json -/validator/.vscode/settings.json +validator/.vscode sample-configs/validator-config.toml \ No newline at end of file