diff --git a/Cargo.lock b/Cargo.lock
index 4f80ede3961f86585e0c01c6b96e6b14a95fa9fe..7462c888c69db1d76567ebebf2713874e07cf297 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -457,7 +457,6 @@ dependencies = [
"pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -548,22 +547,23 @@ dependencies = [
name = "durs-ws2p-v1-legacy"
version = "0.1.0-a0.1"
dependencies = [
+ "bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"dubp-documents 0.12.0",
"duniter-conf 0.1.0-a0.1",
"duniter-module 0.1.0-a0.1",
"duniter-network 0.1.0-a0.1",
"dup-crypto 0.6.0",
+ "durs-common-tools 0.1.0",
"durs-message 0.1.0-a0.1",
"durs-network-documents 0.3.1",
"durs-wot 0.8.0-a0.9",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1145,6 +1145,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "serde"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "serde_derive"
@@ -1210,33 +1213,6 @@ name = "snowflake"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "sqlite"
-version = "0.23.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sqlite3-src"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
- "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sqlite3-sys"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
- "sqlite3-src 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "strsim"
version = "0.7.0"
@@ -1377,6 +1353,11 @@ dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "unwrap"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "url"
version = "1.7.2"
@@ -1571,9 +1552,6 @@ dependencies = [
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15"
"checksum snowflake 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
-"checksum sqlite 0.23.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d7b10278336e7fd9dc259399a0f9ff419616738b6a841b136c362e16db626"
-"checksum sqlite3-src 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "62cd5d67c1eb94a2a019b8049f625f65ae7faee8f3c54f0197e5dbc68d5f698c"
-"checksum sqlite3-sys 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71fec807a1534bd13eeaaec396175d67c79bdc68df55e18a452726ec62a8fb08"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3"
"checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04"
@@ -1592,6 +1570,7 @@ dependencies = [
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum unwrap 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e33648dd74328e622c7be51f3b40a303c63f93e6fa5f08778b6203a4c25c20f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
diff --git a/lib/modules/ws2p-v1-legacy/Cargo.toml b/lib/modules/ws2p-v1-legacy/Cargo.toml
index 30909adcbd8fd8a1b68575c73b674dc764638240..6b2f9788e9322cb7e04df870d65c7b29277a61ed 100644
--- a/lib/modules/ws2p-v1-legacy/Cargo.toml
+++ b/lib/modules/ws2p-v1-legacy/Cargo.toml
@@ -7,26 +7,27 @@ license = "AGPL-3.0"
edition = "2018"
[lib]
-path = "lib.rs"
+path = "src/lib.rs"
[dependencies]
+bincode = "1.0.1"
byteorder = "1.2.3"
+dubp-documents= { path = "../../tools/documents" }
duniter-conf = { path = "../../core/conf" }
+duniter-module = { path = "../../core/module" }
+duniter-network = { path = "../../core/network" }
dup-crypto = { path = "../../tools/crypto" }
-dubp-documents= { path = "../../tools/documents" }
durs-network-documents = { path = "../../tools/network-documents" }
durs-message = { path = "../../core/message" }
-duniter-module = { path = "../../core/module" }
-duniter-network = { path = "../../core/network" }
+durs-common-tools = { path = "../../tools/common-tools" }
durs-wot = { path = "../../tools/wot" }
log = "0.4.*"
rand = "0.4.*"
-sqlite = "0.23.*"
-serde = "1.0.*"
-serde_derive = "1.0.*"
+serde = { version = "1.0.*", features = ["derive"] }
serde_json = "1.0.*"
structopt= "0.2.*"
-ws = { version = "0.7.*", features = ["permessage-deflate"] }
+unwrap = "1.2.1"
+ws = "0.7.*"
[features]
ssl = ["ws/ssl"]
\ No newline at end of file
diff --git a/lib/modules/ws2p-v1-legacy/clippy.toml b/lib/modules/ws2p-v1-legacy/clippy.toml
index 05bd01e10385174463601aedba2ae3ab0fbe921b..fbfe7d8acc90ca3b7b85b00e5f8111ce7f9ab078 100644
--- a/lib/modules/ws2p-v1-legacy/clippy.toml
+++ b/lib/modules/ws2p-v1-legacy/clippy.toml
@@ -1 +1 @@
-cyclomatic-complexity-threshold = 77
\ No newline at end of file
+cyclomatic-complexity-threshold = 51
\ No newline at end of file
diff --git a/lib/modules/ws2p-v1-legacy/constants.rs b/lib/modules/ws2p-v1-legacy/constants.rs
deleted file mode 100644
index aaada76d3146c71a060bf8edea98979815bcad7d..0000000000000000000000000000000000000000
--- a/lib/modules/ws2p-v1-legacy/constants.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-pub static WS2P_OUTCOMING_INTERVAL_AT_STARTUP: &'static u64 = &75;
-pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300;
-pub static WS2P_DEFAULT_OUTCOMING_QUOTA: &'static usize = &10;
-pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15;
-//pub static WS2P_REQUEST_TIMEOUT : &'static u64 = &30;
-pub static WS2P_EXPIRE_TIMEOUT: &'static u64 = &120;
-pub static WS2P_SPAM_INTERVAL_IN_MILLI_SECS: &'static u64 = &80;
-pub static WS2P_SPAM_LIMIT: &'static usize = &6;
-pub static WS2P_SPAM_SLEEP_TIME_IN_SEC: &'static u64 = &100;
-pub static DURATION_BEFORE_RECORDING_ENDPOINT: &'static u64 = &180;
-pub static BLOCKS_REQUEST_INTERVAL: &'static u64 = &60;
-pub static PENDING_IDENTITIES_REQUEST_INTERVAL: &'static u64 = &40;
diff --git a/lib/modules/ws2p-v1-legacy/datas.rs b/lib/modules/ws2p-v1-legacy/datas.rs
deleted file mode 100644
index 89968a51f3c43f48a1a1350b08881efa54a3481d..0000000000000000000000000000000000000000
--- a/lib/modules/ws2p-v1-legacy/datas.rs
+++ /dev/null
@@ -1,491 +0,0 @@
-// Copyright (C) 2018 The Duniter Project Developers.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-use crate::*;
-use dup_crypto::keys::*;
-use durs_message::requests::BlockchainRequest;
-use durs_message::*;
-use durs_network_documents::network_endpoint::*;
-use durs_network_documents::network_head::*;
-use durs_network_documents::*;
-use std::collections::HashSet;
-use std::sync::mpsc;
-
-#[derive(Debug)]
-pub struct WS2PModuleDatas {
- pub router_sender: mpsc::Sender>,
- pub currency: Option,
- pub key_pair: Option,
- pub conf: WS2PConf,
- pub ssl: bool,
- pub node_id: NodeId,
- pub main_thread_channel: (
- mpsc::Sender,
- mpsc::Receiver,
- ),
- pub ws2p_endpoints: HashMap,
- pub websockets: HashMap,
- pub requests_awaiting_response:
- HashMap,
- pub heads_cache: HashMap,
- pub my_head: Option,
- pub uids_cache: HashMap,
- pub count_dal_requests: u32,
-}
-
-#[inline]
-#[cfg(not(feature = "ssl"))]
-fn ssl() -> bool {
- false
-}
-#[cfg(feature = "ssl")]
-fn ssl() -> bool {
- true
-}
-
-impl WS2PModuleDatas {
- pub fn new(
- router_sender: mpsc::Sender>,
- conf: WS2PConf,
- node_id: NodeId,
- ) -> WS2PModuleDatas {
- WS2PModuleDatas {
- router_sender,
- key_pair: None,
- currency: None,
- conf,
- ssl: ssl(),
- node_id,
- main_thread_channel: mpsc::channel(),
- ws2p_endpoints: HashMap::new(),
- websockets: HashMap::new(),
- requests_awaiting_response: HashMap::new(),
- heads_cache: HashMap::new(),
- my_head: None,
- uids_cache: HashMap::new(),
- count_dal_requests: 0,
- }
- }
- pub fn open_db(db_path: &PathBuf) -> Result {
- let conn: sqlite::Connection;
- if !db_path.as_path().exists() {
- conn = sqlite::open(db_path.as_path())?;
- conn.execute(
- "CREATE TABLE endpoints (hash_full_id TEXT, status INTEGER, node_id INTEGER, pubkey TEXT,
- api INTEGER, version INTEGER, endpoint TEXT, last_check INTEGER);",
- )?;
- } else {
- conn = sqlite::open(db_path.as_path())?;
- }
- Ok(conn)
- }
- pub fn send_dal_request(&mut self, req: &BlockchainRequest) {
- self.count_dal_requests += 1;
- if self.count_dal_requests == std::u32::MAX {
- self.count_dal_requests = 0;
- }
- self.router_sender
- .send(RouterThreadMessage::ModuleMessage(DursMsg::Request {
- req_from: WS2PModule::name(),
- req_to: ModuleRole::BlockchainDatas,
- req_id: ModuleReqId(self.count_dal_requests),
- req_content: DursReqContent::BlockchainRequest(req.clone()),
- }))
- .expect("Fail to send message to router !");
- }
- pub fn send_network_req_response(
- &self,
- requester: ModuleStaticName,
- req_id: ModuleReqId,
- response: NetworkResponse,
- ) {
- self.router_sender
- .send(RouterThreadMessage::ModuleMessage(DursMsg::Response {
- res_from: WS2PModule::name(),
- res_to: requester,
- req_id,
- res_content: DursResContent::NetworkResponse(response),
- }))
- .expect("Fail to send message to router !");
- }
- pub fn send_network_event(&self, event: &NetworkEvent) {
- let module_event = match event {
- NetworkEvent::ConnectionStateChange(_, _, _, _) => {
- ModuleEvent::ConnectionsChangeNodeNetwork
- }
- NetworkEvent::ReceiveBlocks(_) => ModuleEvent::NewBlockFromNetwork,
- NetworkEvent::ReceiveDocuments(network_docs) => {
- if !network_docs.is_empty() {
- match network_docs[0] {
- BlockchainDocument::Block(_) => ModuleEvent::NewBlockFromNetwork,
- BlockchainDocument::Transaction(_) => ModuleEvent::NewTxFromNetwork,
- _ => ModuleEvent::NewWotDocFromNetwork,
- }
- } else {
- return;
- }
- }
- NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
- NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
- NetworkEvent::NewSelfPeer(_) => ModuleEvent::NewSelfPeer,
- };
- self.router_sender
- .send(RouterThreadMessage::ModuleMessage(DursMsg::Event {
- event_type: module_event,
- event_content: DursEvent::NetworkEvent(event.clone()),
- }))
- .expect("Fail to send network event to router !");
- }
- fn count_established_connections(&self) -> usize {
- let mut count_established_connections = 0;
- for (_ws2p_full_id, (_ep, state)) in self.ws2p_endpoints.clone() {
- if let WS2PConnectionState::Established = state {
- count_established_connections += 1;
- }
- }
- count_established_connections
- }
- pub fn connect_to_know_endpoints(&mut self) {
- info!("WS2P: connect to know endpoints...");
- let mut count_established_connections = 0;
- let mut pubkeys = HashSet::new();
- let mut reachable_endpoints = Vec::new();
- let mut unreachable_endpoints = Vec::new();
- for (_ws2p_full_id, (ep, state)) in self.ws2p_endpoints.clone() {
- if ep.issuer == self.key_pair.unwrap().public_key() || !pubkeys.contains(&ep.issuer) {
- match state {
- WS2PConnectionState::Established => count_established_connections += 1,
- WS2PConnectionState::NeverTry
- | WS2PConnectionState::Close
- | WS2PConnectionState::Denial => {
- pubkeys.insert(ep.issuer);
- reachable_endpoints.push(ep);
- }
- _ => {
- pubkeys.insert(ep.issuer);
- unreachable_endpoints.push(ep);
- }
- }
- }
- }
- let mut free_outcoming_rooms =
- self.conf.clone().outcoming_quota - count_established_connections;
- while free_outcoming_rooms > 0 {
- let ep = if !reachable_endpoints.is_empty() {
- reachable_endpoints
- .pop()
- .expect("WS2P: Fail to pop() reachable_endpoints !")
- } else if !unreachable_endpoints.is_empty() {
- unreachable_endpoints
- .pop()
- .expect("WS2P: Fail to pop() unreachable_endpoints !")
- } else {
- break;
- };
- if !self.ssl && ep.port == 443 {
- continue;
- }
- self.connect_to_without_checking_quotas(&ep);
- free_outcoming_rooms -= 1;
- }
- }
- pub fn connect_to(&mut self, endpoint: &EndpointV1) {
- // Add endpoint to endpoints list (if there isn't already)
- match self.ws2p_endpoints.get(
- &endpoint
- .node_full_id()
- .expect("WS2P: Fail to get ep.node_full_id() !"),
- ) {
- Some(_) => {
- self.ws2p_endpoints
- .get_mut(
- &endpoint
- .node_full_id()
- .expect("WS2P: Fail to get ep.node_full_id() !"),
- )
- .expect("WS2P: Fail to get_mut() a ws2p_endpoint !")
- .1 = WS2PConnectionState::NeverTry;
- }
- None => {
- self.ws2p_endpoints.insert(
- endpoint
- .node_full_id()
- .expect("WS2P: Fail to get ep.node_full_id() !"),
- (endpoint.clone(), WS2PConnectionState::NeverTry),
- );
- }
- };
- if self.conf.clone().outcoming_quota > self.count_established_connections() {
- self.connect_to_without_checking_quotas(&endpoint);
- }
- }
- pub fn close_connection(
- &mut self,
- ws2p_full_id: &NodeFullId,
- reason: WS2PCloseConnectionReason,
- ) {
- match reason {
- WS2PCloseConnectionReason::NegociationTimeout => {}
- WS2PCloseConnectionReason::AuthMessInvalidSig
- | WS2PCloseConnectionReason::Timeout
- | WS2PCloseConnectionReason::WsError
- | WS2PCloseConnectionReason::Unknow => {
- self.ws2p_endpoints
- .get_mut(ws2p_full_id)
- .expect("Failure : attempt to delete a non-existent connection !")
- .1 = WS2PConnectionState::Close
- }
- }
- if let Some(websocket) = self.websockets.get(&ws2p_full_id) {
- let _result = websocket.0.close(ws::CloseCode::Normal);
- }
- let _result = self.websockets.remove(ws2p_full_id);
- }
- pub fn ws2p_conn_message_pretreatment(&mut self, message: WS2PConnectionMessage) -> WS2PSignal {
- let ws2p_full_id = message.0;
- match message.1 {
- WS2PConnectionMessagePayload::WrongUrl
- | WS2PConnectionMessagePayload::FailOpenWS
- | WS2PConnectionMessagePayload::FailToSplitWS => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = WS2PConnectionState::WSError;
- return WS2PSignal::WSError(ws2p_full_id);
- }
- WS2PConnectionMessagePayload::TryToSendConnectMess => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = WS2PConnectionState::TryToSendConnectMess;
- }
- WS2PConnectionMessagePayload::FailSendConnectMess => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to mut ep !")
- .1 = WS2PConnectionState::Unreachable;
- }
- WS2PConnectionMessagePayload::WebsocketOk(sender) => {
- self.websockets.insert(ws2p_full_id, sender);
- }
- WS2PConnectionMessagePayload::ValidConnectMessage(response, new_con_state) => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = new_con_state;
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("Endpoint don't exist !")
- .1 = WS2PConnectionState::ConnectMessOk;
- debug!("Send: {:#?}", response);
- if let Some(websocket) = self.websockets.get_mut(&ws2p_full_id) {
- if websocket.0.send(Message::text(response)).is_err() {
- return WS2PSignal::WSError(ws2p_full_id);
- }
- } else {
- // Connection closed by remote peer
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("Endpoint don't exist !")
- .1 = WS2PConnectionState::Close;
- }
- }
- WS2PConnectionMessagePayload::ValidAckMessage(response, new_con_state) => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = new_con_state;
- if let WS2PConnectionState::AckMessOk = self.ws2p_endpoints[&ws2p_full_id].1 {
- debug!("Send: {:#?}", response);
- if let Some(websocket) = self.websockets.get_mut(&ws2p_full_id) {
- if websocket.0.send(Message::text(response)).is_err() {
- return WS2PSignal::WSError(ws2p_full_id);
- }
- } else {
- panic!("Fatal error : no websocket for {} !", ws2p_full_id);
- }
- }
- }
- WS2PConnectionMessagePayload::ValidOk(new_con_state) => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = new_con_state;
- match self.ws2p_endpoints[&ws2p_full_id].1 {
- WS2PConnectionState::OkMessOkWaitingAckMess => {}
- WS2PConnectionState::Established => {
- return WS2PSignal::ConnectionEstablished(ws2p_full_id);
- }
- _ => {
- self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Unknow);
- return WS2PSignal::Empty;
- }
- }
- }
- WS2PConnectionMessagePayload::DalRequest(req_id, req_body) => {
- return WS2PSignal::DalRequest(ws2p_full_id, req_id, req_body);
- }
- WS2PConnectionMessagePayload::PeerCard(body, ws2p_endpoints) => {
- return WS2PSignal::PeerCard(ws2p_full_id, body, ws2p_endpoints);
- }
- WS2PConnectionMessagePayload::Heads(heads) => {
- let mut applied_heads = Vec::with_capacity(heads.len());
- for head in heads {
- if let Ok(head) = NetworkHead::from_json_value(&head) {
- if head.verify()
- && (self.my_head.is_none()
- || head.node_full_id()
- != self
- .my_head
- .clone()
- .expect("WS2P: Fail to clone my_head")
- .node_full_id())
- && head.apply(&mut self.heads_cache)
- {
- applied_heads.push(head);
- }
- }
- }
- return WS2PSignal::Heads(ws2p_full_id, applied_heads);
- }
- WS2PConnectionMessagePayload::Document(network_doc) => {
- return WS2PSignal::Document(ws2p_full_id, network_doc);
- }
- WS2PConnectionMessagePayload::ReqResponse(req_id, response) => {
- if self.requests_awaiting_response.len() > req_id.0 as usize {
- if let Some((ref ws2p_request, ref recipient_fulld_id, ref _timestamp)) =
- self.requests_awaiting_response.remove(&req_id)
- {
- return WS2PSignal::ReqResponse(
- req_id,
- *ws2p_request,
- *recipient_fulld_id,
- response,
- );
- }
- }
- }
- WS2PConnectionMessagePayload::NegociationTimeout => {
- match self.ws2p_endpoints[&ws2p_full_id].1 {
- WS2PConnectionState::AckMessOk | WS2PConnectionState::ConnectMessOk => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = WS2PConnectionState::Denial
- }
- WS2PConnectionState::WaitingConnectMess => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = WS2PConnectionState::NoResponse
- }
- _ => {
- self.ws2p_endpoints
- .get_mut(&ws2p_full_id)
- .expect("WS2P: Fail to get mut ep !")
- .1 = WS2PConnectionState::Unreachable
- }
- }
- self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::NegociationTimeout);
- return WS2PSignal::NegociationTimeout(ws2p_full_id);
- }
- WS2PConnectionMessagePayload::Timeout => {
- self.close_connection(&ws2p_full_id, WS2PCloseConnectionReason::Timeout);
- return WS2PSignal::Timeout(ws2p_full_id);
- }
- WS2PConnectionMessagePayload::UnknowMessage => {
- warn!("WS2P : Receive Unknow Message from {}.", &ws2p_full_id.1)
- }
- WS2PConnectionMessagePayload::WrongFormatMessage => warn!(
- "WS2P : Receive Wrong Format Message from {}.",
- &ws2p_full_id.1
- ),
- WS2PConnectionMessagePayload::InvalidMessage => return WS2PSignal::Empty,
- WS2PConnectionMessagePayload::Close => {
- if self.websockets.contains_key(&ws2p_full_id) {
- self.close_connection(
- &ws2p_full_id,
- WS2PCloseConnectionReason::AuthMessInvalidSig,
- )
- }
- }
- }
- let connections_count = self.websockets.len();
- if connections_count == 0 {
- return WS2PSignal::NoConnection;
- }
- // Detect timeout requests
- let mut requests_timeout = Vec::new();
- for &(ref req, ref ws2p_full_id, ref timestamp) in
- self.requests_awaiting_response.clone().values()
- {
- if SystemTime::now().duration_since(*timestamp).unwrap() > Duration::new(20, 0) {
- requests_timeout.push(req.get_req_full_id());
- warn!("request timeout : {:?} (sent to {:?})", req, ws2p_full_id);
- }
- }
- // Delete (and resend) timeout requests
- for req_id in requests_timeout {
- //let ws2p_endpoints = self.ws2p_endpoints.clone();
- let _request_option = self.requests_awaiting_response.remove(&req_id.1);
- /*if let Some((request, _, _)) = request_option {
- let _request_result = self.send_request_to_specific_node(
- &get_random_connection(&ws2p_endpoints),
- &request,
- );
- }*/
- }
- WS2PSignal::Empty
- }
-
- pub fn send_request_to_specific_node(
- &mut self,
- receiver_ws2p_full_id: &NodeFullId,
- ws2p_request: &OldNetworkRequest,
- ) -> ws::Result<()> {
- self.websockets
- .get_mut(receiver_ws2p_full_id)
- .expect("WS2P: Fail to get mut websocket !")
- .0
- .send(Message::text(
- network_request_to_json(ws2p_request).to_string(),
- ))?;
- self.requests_awaiting_response.insert(
- ws2p_request.get_req_id(),
- (*ws2p_request, *receiver_ws2p_full_id, SystemTime::now()),
- );
- debug!(
- "send request {} to {}",
- network_request_to_json(ws2p_request).to_string(),
- receiver_ws2p_full_id
- );
- Ok(())
- }
-
- fn connect_to_without_checking_quotas(&mut self, endpoint: &EndpointV1) {
- let endpoint_copy = endpoint.clone();
- let conductor_sender_copy = self.main_thread_channel.0.clone();
- let currency_copy = self.currency.clone();
- let key_pair_copy = self.key_pair;
- thread::spawn(move || {
- let _result = connect_to_ws2p_endpoint(
- &endpoint_copy,
- &conductor_sender_copy,
- ¤cy_copy.expect("WS2PError : No currency !"),
- key_pair_copy.expect("WS2PError : No key_pair !"),
- );
- });
- }
-}
diff --git a/lib/modules/ws2p-v1-legacy/lib.rs b/lib/modules/ws2p-v1-legacy/lib.rs
deleted file mode 100644
index a3e7663e068d2b5ee8ab454e75133c49390b155f..0000000000000000000000000000000000000000
--- a/lib/modules/ws2p-v1-legacy/lib.rs
+++ /dev/null
@@ -1,1147 +0,0 @@
-// Copyright (C) 2018 The Duniter Project Developers.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-//! WebSocketToPeer API for the Duniter project.
-
-#![deny(
- missing_debug_implementations,
- missing_copy_implementations,
- trivial_casts,
- unsafe_code,
- unstable_features,
- unused_import_braces,
- unused_qualifications
-)]
-#![recursion_limit = "256"]
-
-#[macro_use]
-extern crate log;
-#[macro_use]
-extern crate serde_derive;
-#[macro_use]
-extern crate serde_json;
-#[macro_use]
-extern crate structopt;
-
-mod ack_message;
-mod connect_message;
-pub mod constants;
-mod datas;
-mod heads;
-mod ok_message;
-pub mod parsers;
-pub mod serializer;
-pub mod ws2p_connection;
-pub mod ws2p_db;
-pub mod ws2p_requests;
-
-use crate::ack_message::WS2PAckMessageV1;
-use crate::connect_message::WS2PConnectMessageV1;
-use crate::constants::*;
-use crate::datas::*;
-use crate::ok_message::WS2POkMessageV1;
-use crate::parsers::blocks::parse_json_block;
-use crate::ws2p_connection::*;
-use crate::ws2p_requests::network_request_to_json;
-use dubp_documents::{Blockstamp, Document};
-use duniter_conf::DuRsConf;
-use duniter_module::*;
-use duniter_network::cli::sync::SyncOpt;
-use duniter_network::documents::*;
-use duniter_network::events::*;
-use duniter_network::requests::*;
-use duniter_network::*;
-use dup_crypto::keys::*;
-use durs_message::events::*;
-use durs_message::requests::*;
-use durs_message::responses::*;
-use durs_message::*;
-use durs_network_documents::network_endpoint::*;
-use durs_network_documents::network_head::*;
-use durs_network_documents::*;
-use std::collections::HashMap;
-use std::ops::Deref;
-use std::path::PathBuf;
-use std::sync::mpsc;
-use std::thread;
-use std::time::{Duration, SystemTime, UNIX_EPOCH};
-use ws::Message;
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-/// WS2P Configuration
-pub struct WS2PConf {
- /// Limit of outcoming connections
- pub outcoming_quota: usize,
- /// Default WS2P endpoints provides by configuration file
- pub sync_endpoints: Vec,
-}
-
-impl Default for WS2PConf {
- fn default() -> Self {
- WS2PConf {
- outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA,
- sync_endpoints: vec![
- EndpointV1::parse_from_raw(
- "WS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p",
- PubKey::Ed25519(
- ed25519::PublicKey::from_base58(
- "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
- )
- .unwrap(),
- ),
- 0,
- 0,
- )
- .unwrap(),
- EndpointV1::parse_from_raw(
- "WS2P fb17fcd4 g1.duniter.fr 443 /ws2p",
- PubKey::Ed25519(
- ed25519::PublicKey::from_base58(
- "38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE",
- )
- .unwrap(),
- ),
- 0,
- 0,
- )
- .unwrap(),
- EndpointV1::parse_from_raw(
- "WS2P 7b33becd g1.nordstrom.duniter.org 443 /ws2p",
- PubKey::Ed25519(
- ed25519::PublicKey::from_base58(
- "DWoSCRLQyQ48dLxUGr1MDKg4NFcbPbC56LN2hJjCCPpZ",
- )
- .unwrap(),
- ),
- 0,
- 0,
- )
- .unwrap(),
- EndpointV1::parse_from_raw(
- "WS2P dff60418 duniter.normandie-libre.fr 443 /ws2p",
- PubKey::Ed25519(
- ed25519::PublicKey::from_base58(
- "8t6Di3pLxxoTEfjXHjF49pNpjSTXuGEQ6BpkT75CkNb2",
- )
- .unwrap(),
- ),
- 0,
- 0,
- )
- .unwrap(),
- ],
- }
- }
-}
-
-#[derive(Debug)]
-/// Store a Signal receive from network (after message treatment)
-pub enum WS2PSignal {
- /// Receive a websocket error from a connextion. `NodeFullId` store the identifier of connection.
- WSError(NodeFullId),
- /// A new connection is successfully established with `NodeFullId`.
- ConnectionEstablished(NodeFullId),
- NegociationTimeout(NodeFullId),
- Timeout(NodeFullId),
- DalRequest(NodeFullId, ModuleReqId, serde_json::Value),
- PeerCard(NodeFullId, serde_json::Value, Vec),
- Heads(NodeFullId, Vec),
- Document(NodeFullId, BlockchainDocument),
- ReqResponse(
- ModuleReqId,
- OldNetworkRequest,
- NodeFullId,
- serde_json::Value,
- ),
- Empty,
- NoConnection,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum NetworkConsensusError {
- InsufficientData(usize),
- Fork,
-}
-
-#[derive(Debug)]
-pub enum SendRequestError {
- RequestTypeMustNotBeTransmitted(),
- WSError(usize, Vec),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct WS2PModule {}
-
-#[derive(Debug)]
-pub enum WS2PThreadSignal {
- DursMsg(Box),
- WS2PConnectionMessage(WS2PConnectionMessage),
-}
-
-pub trait WS2PMessage: Sized {
- fn parse(v: &serde_json::Value, currency: String) -> Option;
- fn to_raw(&self) -> String;
- fn sign(&self, key_pair: KeyPairEnum) -> Sig {
- key_pair.sign(self.to_raw().as_bytes())
- }
- fn verify(&self) -> bool;
- //fn parse_and_verify(v: serde_json::Value, currency: String) -> bool;
-}
-
-impl Default for WS2PModule {
- fn default() -> WS2PModule {
- WS2PModule {}
- }
-}
-
-#[derive(Debug)]
-/// WS2PFeaturesParseError
-pub enum WS2PFeaturesParseError {
- /// UnknowApiFeature
- UnknowApiFeature(String),
-}
-
-impl ApiModule for WS2PModule {
- type ParseErr = WS2PFeaturesParseError;
- /// Parse raw api features
- fn parse_raw_api_features(str_features: &str) -> Result {
- let str_features: Vec<&str> = str_features.split(' ').collect();
- let mut api_features = Vec::with_capacity(0);
- for str_feature in str_features {
- match str_feature {
- "DEF" => api_features[0] += 1u8,
- "LOW" => api_features[0] += 2u8,
- "ABF" => api_features[0] += 4u8,
- _ => {
- return Err(WS2PFeaturesParseError::UnknowApiFeature(String::from(
- str_feature,
- )));
- }
- }
- }
- Ok(ApiFeatures(api_features))
- }
-}
-
-impl NetworkModule for WS2PModule {
- fn sync(
- _soft_meta_datas: &SoftwareMetaDatas,
- _keys: RequiredKeysContent,
- _conf: WS2PConf,
- _main_sender: mpsc::Sender>,
- _sync_params: SyncOpt,
- ) -> Result<(), ModuleInitError> {
- println!("Downlaod blockchain from network...");
- println!("Error : not yet implemented !");
- Ok(())
- }
-}
-
-#[derive(StructOpt, Debug, Copy, Clone)]
-#[structopt(
- name = "ws2p",
- raw(setting = "structopt::clap::AppSettings::ColoredHelp")
-)]
-/// WS2Pv1 subcommand options
-pub struct WS2POpt {}
-
-impl DursModule for WS2PModule {
- type ModuleConf = WS2PConf;
- type ModuleOpt = WS2POpt;
-
- fn name() -> ModuleStaticName {
- ModuleStaticName("ws2p")
- }
- fn priority() -> ModulePriority {
- ModulePriority::Essential()
- }
- fn ask_required_keys() -> RequiredKeys {
- RequiredKeys::NetworkKeyPair()
- }
- fn have_subcommand() -> bool {
- true
- }
- fn exec_subcommand(
- _soft_meta_datas: &SoftwareMetaDatas,
- _keys: RequiredKeysContent,
- _module_conf: Self::ModuleConf,
- _subcommand_args: WS2POpt,
- ) {
- println!("Succesfully exec ws2p subcommand !")
- }
- fn start(
- soft_meta_datas: &SoftwareMetaDatas,
- keys: RequiredKeysContent,
- conf: WS2PConf,
- router_sender: mpsc::Sender>,
- load_conf_only: bool,
- ) -> Result<(), ModuleInitError> {
- // Get start time
- let start_time = SystemTime::now();
-
- // Define WS2PModuleDatas
- let mut ws2p_module = WS2PModuleDatas::new(
- router_sender.clone(),
- conf,
- NodeId(soft_meta_datas.conf.my_node_id()),
- );
-
- // load conf
- let key_pair = match keys {
- RequiredKeysContent::NetworkKeyPair(key_pair) => key_pair,
- _ => panic!("WS2PModule fatal error at load_conf() : keys != NetworkKeyPair"),
- };
- let mut ws2p_endpoints = HashMap::new();
- for ep in &ws2p_module.conf.sync_endpoints {
- ws2p_endpoints.insert(
- ep.node_full_id()
- .expect("Fail to get endpoint node_full_id"),
- (ep.clone(), WS2PConnectionState::Close),
- );
- info!("Load sync endpoint {}", ep.raw_endpoint);
- }
- ws2p_module.key_pair = Some(key_pair);
- ws2p_module.currency = Some(soft_meta_datas.conf.currency().to_string());
- ws2p_module.ws2p_endpoints = ws2p_endpoints;
-
- // Create ws2p main thread channel
- let ws2p_sender_clone = ws2p_module.main_thread_channel.0.clone();
-
- // Create proxy channel
- let (proxy_sender, proxy_receiver): (mpsc::Sender, mpsc::Receiver) =
- mpsc::channel();
- let proxy_sender_clone = proxy_sender.clone();
-
- // Launch a proxy thread that transform DursMsg to WS2PThreadSignal(DursMsg)
- thread::spawn(move || {
- // Send proxy sender to main
- router_sender
- .send(RouterThreadMessage::ModuleRegistration(
- WS2PModule::name(),
- proxy_sender_clone,
- vec![ModuleRole::InterNodesNetwork],
- vec![
- ModuleEvent::NewValidBlock,
- ModuleEvent::NewWotDocInPool,
- ModuleEvent::NewTxinPool,
- ],
- vec![],
- vec![],
- ))
- .expect("Fatal error : ws2p module fail to send is sender channel !");
- debug!("Send ws2p sender to main thread.");
- loop {
- match proxy_receiver.recv() {
- Ok(message) => {
- let stop = if let DursMsg::Stop = message {
- true
- } else {
- false
- };
- ws2p_sender_clone
- .send(WS2PThreadSignal::DursMsg(Box::new(message)))
- .expect(
- "Fatal error : fail to relay DursMsgContent to ws2p main thread !",
- );
- if stop {
- break;
- };
- }
- Err(e) => panic!(format!("{}", e)),
- }
- }
- });
-
- // open ws2p bdd
- let mut db_path =
- duniter_conf::datas_path(&soft_meta_datas.profile, &soft_meta_datas.conf.currency());
- db_path.push("ws2p.db");
- let db = WS2PModuleDatas::open_db(&db_path).expect("Fatal error : fail to open WS2P DB !");
-
- // Get ws2p endpoints in BDD
- let mut count = 0;
- let dal_enpoints =
- ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P")));
- for ep in dal_enpoints {
- if ep.api == NetworkEndpointApi(String::from("WS2P"))
- && (cfg!(feature = "ssl") || ep.port != 443)
- {
- count += 1;
- ws2p_module.ws2p_endpoints.insert(
- ep.node_full_id()
- .expect("WS2P: Fail to get ep.node_full_id() !"),
- (ep.clone(), WS2PConnectionState::from(ep.status)),
- );
- }
- }
- info!("Load {} endpoints from bdd !", count);
-
- // Stop here in load_conf_only mode
- if load_conf_only {
- return Ok(());
- }
-
- // Initialize variables
- let mut last_ws2p_connecting_wave = SystemTime::now();
- let mut last_ws2p_connections_print = SystemTime::now();
- let mut endpoints_to_update_status: HashMap = HashMap::new();
- let mut last_identities_request = UNIX_EPOCH;
- let mut current_blockstamp = Blockstamp::default();
- let mut next_receiver = 0;
-
- // Request current blockstamp
- ws2p_module.send_dal_request(&BlockchainRequest::CurrentBlockstamp());
-
- // Start
- ws2p_module.connect_to_know_endpoints();
- loop {
- match ws2p_module
- .main_thread_channel
- .1
- .recv_timeout(Duration::from_millis(200))
- {
- Ok(message) => match message {
- WS2PThreadSignal::DursMsg(ref durs_mesage) => {
- match *durs_mesage.deref() {
- DursMsg::Stop => break,
- DursMsg::Request {
- ref req_content, ..
- } => {
- if let DursReqContent::OldNetworkRequest(ref old_net_request) =
- *req_content
- {
- match *old_net_request {
- OldNetworkRequest::GetBlocks(
- ref req_id,
- ref count,
- ref from,
- ) => {
- let mut receiver_index = 0;
- let mut real_receiver = None;
- for (ws2p_full_id, (_ep, state)) in
- ws2p_module.ws2p_endpoints.clone()
- {
- if let WS2PConnectionState::Established = state {
- if receiver_index == next_receiver {
- real_receiver = Some(ws2p_full_id);
- break;
- }
- receiver_index += 1;
- }
- }
- if real_receiver.is_none() {
- next_receiver = 0;
- for (ws2p_full_id, (_ep, state)) in
- &ws2p_module.ws2p_endpoints
- {
- if let WS2PConnectionState::Established = *state
- {
- real_receiver = Some(*ws2p_full_id);
- break;
- }
- }
- } else {
- next_receiver += 1;
- }
- if let Some(real_receiver) = real_receiver {
- debug!("WS2P: send req to: ({:?})", real_receiver);
- let _blocks_request_result = ws2p_module
- .send_request_to_specific_node(
- &real_receiver,
- &OldNetworkRequest::GetBlocks(
- *req_id, *count, *from,
- ),
- );
- } else {
- warn!("WS2P: not found peer to send request !");
- }
- }
- OldNetworkRequest::GetEndpoints(ref _request) => {}
- _ => {}
- }
- }
- }
- DursMsg::Event {
- ref event_content, ..
- } => {
- if let DursEvent::BlockchainEvent(ref bc_event) = *event_content {
- match *bc_event.deref() {
- BlockchainEvent::StackUpValidBlock(ref block) => {
- current_blockstamp = block.deref().blockstamp();
- debug!(
- "WS2PModule : current_blockstamp = {}",
- current_blockstamp
- );
- ws2p_module.my_head = Some(heads::generate_my_head(
- &key_pair,
- NodeId(soft_meta_datas.conf.my_node_id()),
- soft_meta_datas.soft_name,
- soft_meta_datas.soft_version,
- ¤t_blockstamp,
- None,
- ));
- ws2p_module.send_network_event(
- &NetworkEvent::ReceiveHeads(vec![ws2p_module
- .my_head
- .clone()
- .unwrap()]),
- );
- // Send my head to all connections
- let my_json_head = serializer::serialize_head(
- ws2p_module.my_head.clone().unwrap(),
- );
- trace!("Send my HEAD: {:#?}", my_json_head);
- let _results: Result<(), ws::Error> = ws2p_module
- .websockets
- .iter_mut()
- .map(|ws| {
- (ws.1).0.send(Message::text(
- json!({
- "name": "HEAD",
- "body": {
- "heads": [my_json_head]
- }
- })
- .to_string(),
- ))
- })
- .collect();
- }
- BlockchainEvent::RevertBlocks(ref _blocks) => {}
- _ => {}
- }
- }
- }
- DursMsg::Response {
- ref res_content, ..
- } => {
- if let DursResContent::BlockchainResponse(ref bc_res) = *res_content
- {
- match *bc_res.deref() {
- BlockchainResponse::CurrentBlockstamp(
- ref _requester_id,
- ref current_blockstamp_,
- ) => {
- debug!(
- "WS2PModule : receive DALResBc::CurrentBlockstamp({})",
- current_blockstamp
- );
- current_blockstamp = *current_blockstamp_;
- if ws2p_module.my_head.is_none() {
- ws2p_module.my_head =
- Some(heads::generate_my_head(
- &key_pair,
- NodeId(soft_meta_datas.conf.my_node_id()),
- soft_meta_datas.soft_name,
- soft_meta_datas.soft_version,
- ¤t_blockstamp,
- None,
- ));
- }
- ws2p_module.send_network_event(
- &NetworkEvent::ReceiveHeads(vec![ws2p_module
- .my_head
- .clone()
- .unwrap()]),
- );
- }
- BlockchainResponse::UIDs(ref _req_id, ref uids) => {
- // Add uids to heads
- for head in ws2p_module.heads_cache.values_mut() {
- if let Some(uid_option) = uids.get(&head.pubkey()) {
- if let Some(ref uid) = *uid_option {
- head.set_uid(uid);
- ws2p_module
- .uids_cache
- .insert(head.pubkey(), uid.to_string());
- } else {
- ws2p_module
- .uids_cache
- .remove(&head.pubkey());
- }
- }
- }
- // Resent heads to other modules
- ws2p_module.send_network_event(
- &NetworkEvent::ReceiveHeads(
- ws2p_module
- .heads_cache
- .values()
- .cloned()
- .collect(),
- ),
- );
- // Resent to other modules connections that match receive uids
- for (node_full_id, (ep, conn_state)) in
- &ws2p_module.ws2p_endpoints
- {
- if let Some(uid_option) = uids.get(&node_full_id.1)
- {
- ws2p_module.send_network_event(
- &NetworkEvent::ConnectionStateChange(
- *node_full_id,
- *conn_state as u32,
- uid_option.clone(),
- ep.get_url(false, false)
- .expect("Endpoint unreachable !"),
- ),
- );
- }
- }
- }
- _ => {} // Others BlockchainResponse variants
- }
- }
- }
- _ => {} // Others DursMsg variants
- }
- }
- WS2PThreadSignal::WS2PConnectionMessage(ws2p_conn_message) => match ws2p_module
- .ws2p_conn_message_pretreatment(ws2p_conn_message)
- {
- WS2PSignal::NoConnection => {
- warn!("WS2PSignal::NoConnection");
- }
- WS2PSignal::ConnectionEstablished(ws2p_full_id) => {
- let req_id =
- ModuleReqId(ws2p_module.requests_awaiting_response.len() as u32);
- let module_id = WS2PModule::name();
- debug!("WS2P: send req to: ({:?})", ws2p_full_id);
- let _current_request_result = ws2p_module
- .send_request_to_specific_node(
- &ws2p_full_id,
- &OldNetworkRequest::GetCurrent(ModuleReqFullId(
- module_id, req_id,
- )),
- );
- if ws2p_module.uids_cache.get(&ws2p_full_id.1).is_none() {
- ws2p_module.send_dal_request(&BlockchainRequest::UIDs(vec![
- ws2p_full_id.1,
- ]));
- }
- ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
- ws2p_full_id,
- WS2PConnectionState::Established as u32,
- ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
- ws2p_module.ws2p_endpoints[&ws2p_full_id]
- .0
- .get_url(false, false)
- .expect("Endpoint unreachable !"),
- ));
- }
- WS2PSignal::WSError(ws2p_full_id) => {
- endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
- ws2p_module.close_connection(
- &ws2p_full_id,
- WS2PCloseConnectionReason::WsError,
- );
- ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
- ws2p_full_id,
- WS2PConnectionState::WSError as u32,
- ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
- ws2p_module.ws2p_endpoints[&ws2p_full_id]
- .0
- .get_url(false, false)
- .expect("Endpoint unreachable !"),
- ));
- }
- WS2PSignal::NegociationTimeout(ws2p_full_id) => {
- endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
- ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
- ws2p_full_id,
- WS2PConnectionState::Denial as u32,
- ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
- ws2p_module.ws2p_endpoints[&ws2p_full_id]
- .0
- .get_url(false, false)
- .expect("Endpoint unreachable !"),
- ));
- }
- WS2PSignal::Timeout(ws2p_full_id) => {
- endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
- ws2p_module.send_network_event(&NetworkEvent::ConnectionStateChange(
- ws2p_full_id,
- WS2PConnectionState::Close as u32,
- ws2p_module.uids_cache.get(&ws2p_full_id.1).cloned(),
- ws2p_module.ws2p_endpoints[&ws2p_full_id]
- .0
- .get_url(false, false)
- .expect("Endpoint unreachable !"),
- ));
- }
- WS2PSignal::PeerCard(_ws2p_full_id, _peer_card, ws2p_endpoints) => {
- //trace!("WS2PSignal::PeerCard({})", ws2p_full_id);
- //ws2p_module.send_network_event(NetworkEvent::ReceivePeers(_));
- for ep in ws2p_endpoints {
- match ws2p_module.ws2p_endpoints.get(
- &ep.node_full_id()
- .expect("WS2P: Fail to get ep.node_full_id() !"),
- ) {
- Some(_) => {}
- None => {
- if let Some(_api) =
- ws2p_db::string_to_api(&ep.api.0.clone())
- {
- endpoints_to_update_status.insert(
- ep.node_full_id().expect(
- "WS2P: Fail to get ep.node_full_id() !",
- ),
- SystemTime::now(),
- );
- }
- if cfg!(feature = "ssl") || ep.port != 443 {
- ws2p_module.connect_to(&ep);
- }
- }
- };
- }
- }
- WS2PSignal::Heads(ws2p_full_id, heads) => {
- trace!("WS2PSignal::Heads({}, {:?})", ws2p_full_id, heads.len());
- ws2p_module.send_dal_request(&BlockchainRequest::UIDs(
- heads.iter().map(NetworkHead::pubkey).collect(),
- ));
- ws2p_module.send_network_event(&NetworkEvent::ReceiveHeads(
- heads
- .iter()
- .map(|head| {
- let mut new_head = head.clone();
- if let Some(uid) =
- ws2p_module.uids_cache.get(&head.pubkey())
- {
- new_head.set_uid(uid);
- }
- new_head
- })
- .collect(),
- ));
- }
- WS2PSignal::Document(ws2p_full_id, network_doc) => {
- trace!("WS2PSignal::Document({})", ws2p_full_id);
- ws2p_module.send_network_event(&NetworkEvent::ReceiveDocuments(vec![
- network_doc,
- ]));
- }
- WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => {
- match req {
- OldNetworkRequest::GetCurrent(ref _req_id) => {
- info!("WS2PSignal::ReceiveCurrent({}, {:?})", req_id.0, req);
- if let Some(block) = parse_json_block(&response) {
- ws2p_module.send_network_req_response(
- req.get_req_full_id().0,
- req.get_req_full_id().1,
- NetworkResponse::CurrentBlock(
- ModuleReqFullId(WS2PModule::name(), req_id),
- recipient_full_id,
- Box::new(block),
- ),
- );
- }
- }
- OldNetworkRequest::GetBlocks(ref _req_id, count, from) => {
- info!(
- "WS2PSignal::ReceiveChunk({}, {} blocks from {})",
- req_id.0, count, from
- );
- if response.is_array() {
- let mut chunk = Vec::new();
- for json_block in response.as_array().unwrap() {
- if let Some(block) = parse_json_block(json_block) {
- chunk.push(block);
- } else {
- warn!("WS2PModule: Error : fail to parse one json block !");
- }
- }
- debug!("Send chunk to followers : {}", from);
- ws2p_module.send_network_event(
- &NetworkEvent::ReceiveBlocks(chunk),
- );
- }
- }
- OldNetworkRequest::GetRequirementsPending(_req_id, min_cert) => {
- info!(
- "WS2PSignal::ReceiveRequirementsPending({}, {})",
- req_id.0, min_cert
- );
- debug!("----------------------------------------");
- debug!("- BEGIN IDENTITIES PENDING -");
- debug!("----------------------------------------");
- debug!("{:#?}", response);
- debug!("----------------------------------------");
- debug!("- END IDENTITIES PENDING -");
- debug!("----------------------------------------");
- }
- _ => {}
- }
- }
- WS2PSignal::Empty => {}
- _ => {}
- },
- },
- Err(e) => match e {
- mpsc::RecvTimeoutError::Disconnected => {
- panic!("Disconnected ws2p module !");
- }
- mpsc::RecvTimeoutError::Timeout => {}
- },
- }
- if SystemTime::now()
- .duration_since(last_ws2p_connections_print)
- .unwrap()
- > Duration::new(5, 0)
- {
- last_ws2p_connections_print = SystemTime::now();
- let mut connected_nodes = Vec::new();
- for (k, (_ep, state)) in ws2p_module.ws2p_endpoints.clone() {
- if let WS2PConnectionState::Established = state {
- connected_nodes.push(k);
- }
- }
- // Print current_blockstamp
- info!(
- "WS2PModule : current_blockstamp() = {:?}",
- current_blockstamp
- );
- // New WS2P connection wave
- if connected_nodes.len() < ws2p_module.conf.clone().outcoming_quota
- && (SystemTime::now()
- .duration_since(last_ws2p_connecting_wave)
- .unwrap()
- > Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)
- || (SystemTime::now()
- .duration_since(last_ws2p_connecting_wave)
- .unwrap()
- > Duration::new(*WS2P_OUTCOMING_INTERVAL_AT_STARTUP, 0)
- && SystemTime::now().duration_since(start_time).unwrap()
- < Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)))
- {
- last_ws2p_connecting_wave = SystemTime::now();
- info!("Connected to know endpoints...");
- ws2p_module.connect_to_know_endpoints();
- }
- // Request pending_identities from network
- if SystemTime::now()
- .duration_since(last_identities_request)
- .unwrap()
- > Duration::new(*PENDING_IDENTITIES_REQUEST_INTERVAL, 0)
- && SystemTime::now().duration_since(start_time).unwrap() > Duration::new(10, 0)
- {
- /*info!("get pending_identities from all connections...");
- let _blocks_request_result = ws2p_module.send_request_to_all_connections(
- &OldNetworkRequest::GetRequirementsPending(ModuleReqId(0 as u32), 5),
- );*/
- last_identities_request = SystemTime::now();
- }
- // Write pending endpoints
- for (ep_full_id, received_time) in endpoints_to_update_status.clone() {
- if SystemTime::now().duration_since(received_time).unwrap()
- > Duration::new(*DURATION_BEFORE_RECORDING_ENDPOINT, 0)
- {
- if let Some(&(ref ep, ref state)) =
- ws2p_module.ws2p_endpoints.get(&ep_full_id)
- {
- ws2p_db::write_endpoint(
- &db,
- &ep,
- state.to_u32(),
- SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .unwrap()
- .as_secs(),
- );
- }
- endpoints_to_update_status.remove(&ep_full_id);
- } else {
- info!(
- "Write {} endpoint in {} secs.",
- ep_full_id,
- *DURATION_BEFORE_RECORDING_ENDPOINT
- - SystemTime::now()
- .duration_since(received_time)
- .unwrap()
- .as_secs()
- );
- }
- }
- // ..
- // Request current blockstamp
- ws2p_module.send_dal_request(&BlockchainRequest::CurrentBlockstamp());
- }
- }
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::parsers::blocks::parse_json_block;
- use super::*;
- use dubp_documents::documents::block::BlockDocument;
- use duniter_module::DursModule;
- use dup_crypto::keys::PublicKey;
- use durs_network_documents::network_endpoint::NetworkEndpointApi;
- use std::fs;
- use std::path::PathBuf;
- use std::time::{SystemTime, UNIX_EPOCH};
-
- #[test]
- fn test_parse_json_block() {
- let json_block = json!({
- "fork": false,
- "version": 10,
- "nonce": 10500000059239 as u64,
- "number": 109966,
- "powMin": 88,
- "time": 1523300656,
- "medianTime": 1523295259,
- "membersCount": 933,
- "monetaryMass": 146881563,
- "unitbase": 0,
- "issuersCount": 44,
- "issuersFrame": 221,
- "issuersFrameVar": 0,
- "currency": "g1",
- "issuer": "GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4",
- "signature": "GCg2Lti3TdxWlhA8JF8pRI+dRQ0XZVtcC4BqO/COTpjTQFdWG6qmUNVvdeYCtR/lu1JQe3N/IhrbyV6L/6I+Cg==",
- "hash": "000000EF5B2AA849F4C3AF3D35E1284EA1F34A9F617EA806CE8371619023DC74",
- "parameters": "",
- "previousHash": "000004C00602F8A27AE078DE6351C0DDA1EA0974A78D2BEFA7DFBE7B7C3146FD",
- "previousIssuer": "5SwfQubSat5SunNafCsunEGTY93nVM4kLSsuprNqQb6S",
- "inner_hash": "61F02B1A6AE2E4B9A1FD66CE673258B4B21C0076795571EE3C9DC440DD06C46C",
- "dividend": null,
- "identities": [],
- "joiners": [],
- "actives": [],
- "leavers": [],
- "revoked": [],
- "excluded": [],
- "certifications": [
- "Hm5qjaNuHogNRdGZ4vgnLA9DMZVUu5YWzVup5mubuxCc:8AmdBsimcLziXaCS4AcVUfPx7rkjeic7482dLbBkuZw6:109964:yHKBGMeuxyIqFb295gVNK6neRC+U0tmsX1Zed3TLjS3ZZHYYycE1piLcYsTKll4ifNVp6rm+hd/CLdHYB+29CA==",
- "BncjgJeFpGsMCCsUfzNLEexjsbuX3V2mg9P67ov2LkwK:DyBUBNpzpfvjtwYYSaVMM6ST6t2DNg3NCE9CU9bRQFhF:105864:cJEGW9WxJwlMA2+4LNAK4YieyseUy1WIkFh1YLYD+JJtJEoCSnIQRXzhiAoRpGaj0bRz8sTpwI6PRkuVoDJJDQ=="
- ],
- "transactions": [
- {
- "version": 10,
- "currency": "g1",
- "locktime": 0,
- "hash": "80FE1E83DC4D0B722CA5F8363EFC6A3E29071032EBB71C1E0DF8D4FEA589C698",
- "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
- "blockstampTime": 0,
- "issuers": [
- "6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT"
- ],
- "inputs": [
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98284",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98519",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98779",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99054",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99326",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99599",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99884",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100174",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100469",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100746",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:101036",
- "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:101327"
- ],
- "outputs": [
- "12000:0:SIG(HmH5beJqKGMeotcQUrSW7Wo5tKvAksHmfYXfiSQ9EbWz)",
- "12:0:SIG(6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT)"
- ],
- "unlocks": [
- "0:SIG(0)",
- "1:SIG(0)",
- "2:SIG(0)",
- "3:SIG(0)",
- "4:SIG(0)",
- "5:SIG(0)",
- "6:SIG(0)",
- "7:SIG(0)",
- "8:SIG(0)",
- "9:SIG(0)",
- "10:SIG(0)",
- "11:SIG(0)"
- ],
- "signatures": [
- "MZxoKxYgwufh/s5mwLCsYEZXtIsP1hEKCyAzLipJsvCbR9xj7wXUw0C/ahwvZfBtR7+QVPIfLmwYEol1JcHjDw=="
- ],
- "comment": "Adhesion 2018"
- },
- {
- "version": 10,
- "currency": "g1",
- "locktime": 0,
- "hash": "B80507412B35BD5EB437AE0D3EB97E60E3A4974F5CDEA1AF7E2127C0E943481F",
- "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
- "blockstampTime": 0,
- "issuers": [
- "8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU"
- ],
- "inputs": [
- "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:91560",
- "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:91850",
- "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92111",
- "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92385",
- "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92635"
- ],
- "outputs": [
- "5000:0:SIG(BzHnbec1Gov7dLSt1EzJS7vikoQCECeuvZs4wamZAcT1)",
- "5:0:SIG(8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU)"
- ],
- "unlocks": [
- "0:SIG(0)",
- "1:SIG(0)",
- "2:SIG(0)",
- "3:SIG(0)",
- "4:SIG(0)"
- ],
- "signatures": [
- "A+ukwRvLWs1gZQ0KAqAnknEgmRQHdrnOvNuBx/WZqje17BAPrVxSxKpqwU6MiajU+ppigsYp6Bu0FdPf/tGnCQ=="
- ],
- "comment": ""
- },
- {
- "version": 10,
- "currency": "g1",
- "locktime": 0,
- "hash": "D8970E6629C0381A78534EEDD86803E9215A7EC4C494BAEA79EB19425F9B4D31",
- "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
- "blockstampTime": 0,
- "issuers": [
- "FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg"
- ],
- "inputs": [
- "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:36597",
- "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:36880",
- "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:37082"
- ],
- "outputs": [
- "3000:0:SIG(BBC8Rnh4CWN1wBrPLevK7GRFFVDVw7Lu24YNMUmhqoHU)"
- ],
- "unlocks": [
- "0:SIG(0)",
- "1:SIG(0)",
- "2:SIG(0)"
- ],
- "signatures": [
- "OpiF/oQfIigOeAtsteukU0w9FPSELE+BVTxhmsQ8bEeYGlwovG2VF8ZFiJkLLPi6vFuKgwzULJfjNGd97twZCw=="
- ],
- "comment": "1 billet pour une seance.pour un chouette film"
- }
- ],
- });
- let mut block: BlockDocument =
- parse_json_block(&json_block).expect("Fail to parse test json block !");
- assert_eq!(
- block
- .inner_hash
- .expect("Try to get inner_hash of an uncompleted or reduce block !")
- .to_hex(),
- "61F02B1A6AE2E4B9A1FD66CE673258B4B21C0076795571EE3C9DC440DD06C46C"
- );
- block.compute_hash();
- assert_eq!(
- block
- .hash
- .expect("Try to get hash of an uncompleted or reduce block !")
- .0
- .to_hex(),
- "000000EF5B2AA849F4C3AF3D35E1284EA1F34A9F617EA806CE8371619023DC74"
- );
- }
-
- #[test]
- fn endpoint_db_tests() {
- let test_db_path = PathBuf::from("test.db");
- if test_db_path.as_path().exists() {
- fs::remove_file(&test_db_path).unwrap();
- }
- let db = WS2PModuleDatas::open_db(&test_db_path).unwrap();
-
- let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
-
- let mut endpoint = EndpointV1::parse_from_raw(
- "WS2P cb06a19b g1.imirhil.fr 53012 /",
- PubKey::Ed25519(
- ed25519::PublicKey::from_base58("5gJYnQp8v7bWwk7EWRoL8vCLof1r3y9c6VDdnGSM1GLv")
- .unwrap(),
- ),
- 1,
- current_time.as_secs(),
- )
- .expect("Failt to parse test endpoint !");
-
- ws2p_db::write_endpoint(&db, &endpoint, 1, current_time.as_secs());
- let mut written_endpoints =
- ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P")));
- assert_eq!(endpoint, written_endpoints.pop().unwrap());
-
- // Test status update
- endpoint.status = 3;
- ws2p_db::write_endpoint(&db, &endpoint, 3, current_time.as_secs());
- let mut written_endpoints =
- ws2p_db::get_endpoints_for_api(&db, &NetworkEndpointApi(String::from("WS2P")));
- assert_eq!(endpoint, written_endpoints.pop().unwrap());
- }
-
- #[test]
- fn ws2p_requests() {
- let module_id = WS2PModule::name();
- let request =
- OldNetworkRequest::GetBlocks(ModuleReqFullId(module_id, ModuleReqId(58)), 50, 0);
- assert_eq!(
- network_request_to_json(&request),
- json!({
- "reqId": format!("{:x}", 58),
- "body": {
- "name": "BLOCKS_CHUNK",
- "params": {
- "count": 50,
- "fromNumber": 0
- }
- }
- })
- );
- assert_eq!(
- network_request_to_json(&request).to_string(),
- "{\"body\":{\"name\":\"BLOCKS_CHUNK\",\"params\":{\"count\":50,\"fromNumber\":0}},\"reqId\":\"3a\"}"
- );
- }
-
- #[test]
- fn ws2p_parse_head() {
- let head = json!({
- "message": "WS2POTMIC:HEAD:1:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3",
- "sig": "trtK9GXvTdfND995ohWEderpO3NkIqi1X6mBeVvMcaHckq+lIGqjWvJ9t9Vccz5t+VGaSmGUihDl4q6eldIYBw==",
- "messageV2": "WS2POTMIC:HEAD:2:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3:25:22",
- "sigV2": "x6ehPMuYjGY+z7wEGnJGyMBxMKUdu01RWaF0b0XCtoVjg67cCvT4H0V/Qcxn4bAGqzy5ux2fA7NiI+81bBnqDw==",
- "step": 0
- });
- let mut heads_count = 0;
- if let Ok(head) = NetworkHead::from_json_value(&head) {
- if let NetworkHead::V2(ref head_v2) = head {
- heads_count += 1;
- assert_eq!(
- head_v2.message.to_string(),
- String::from("WS2POTMIC:HEAD:1:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3")
- );
- }
- assert_eq!(head.verify(), true);
- } else {
- panic!("Fail to parse head !")
- }
- assert_eq!(heads_count, 1);
- }
-}
diff --git a/lib/modules/ws2p-v1-legacy/ack_message.rs b/lib/modules/ws2p-v1-legacy/src/ack_message.rs
similarity index 67%
rename from lib/modules/ws2p-v1-legacy/ack_message.rs
rename to lib/modules/ws2p-v1-legacy/src/ack_message.rs
index e1fcdeed37934ec8ed568e98d33bad0ea166e74e..f18bf55e7e389f748ddbf0bf6c286c78daea6712 100644
--- a/lib/modules/ws2p-v1-legacy/ack_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ack_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
use dup_crypto::keys::*;
use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -11,20 +11,19 @@ pub struct WS2PAckMessageV1 {
}
impl WS2PMessage for WS2PAckMessageV1 {
- fn parse(v: &serde_json::Value, currency: String) -> Option {
+ fn parse(v: &serde_json::Value, currency: String) -> Result {
let pubkey = match v.get("pub") {
- Some(pubkey) => pubkey.as_str().unwrap().to_string(),
- None => return None,
+ Some(pubkey) => pubkey.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
let signature = match v.get("sig") {
- Some(signature) => signature.as_str().unwrap().to_string(),
- None => return None,
+ Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
- let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey).unwrap());
- let signature: Option = Some(Sig::Ed25519(
- ed25519::Signature::from_base64(&signature).unwrap(),
- ));
- Some(WS2PAckMessageV1 {
+ let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey)?);
+ let signature: Option =
+ Some(Sig::Ed25519(ed25519::Signature::from_base64(&signature)?));
+ Ok(WS2PAckMessageV1 {
currency,
pubkey,
challenge: "".to_string(),
@@ -38,8 +37,11 @@ impl WS2PMessage for WS2PAckMessageV1 {
)
}
fn verify(&self) -> bool {
- self.pubkey
- .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+ if let Some(sig) = self.signature {
+ self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+ } else {
+ false
+ }
}
}
diff --git a/lib/modules/ws2p-v1-legacy/connect_message.rs b/lib/modules/ws2p-v1-legacy/src/connect_message.rs
similarity index 66%
rename from lib/modules/ws2p-v1-legacy/connect_message.rs
rename to lib/modules/ws2p-v1-legacy/src/connect_message.rs
index 1f917aded01c469b82019f7af394407ecf343d67..e229cc1def5b603c1ee14e61ec092e0079366620 100644
--- a/lib/modules/ws2p-v1-legacy/connect_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/connect_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
use dup_crypto::keys::*;
use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -11,24 +11,22 @@ pub struct WS2PConnectMessageV1 {
}
impl WS2PMessage for WS2PConnectMessageV1 {
- fn parse(v: &serde_json::Value, currency: String) -> Option {
+ fn parse(v: &serde_json::Value, currency: String) -> Result {
let pubkey = match v.get("pub") {
- Some(pubkey) => pubkey.as_str().unwrap().to_string(),
- None => return None,
+ Some(pubkey) => pubkey.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
let challenge = match v.get("challenge") {
- Some(challenge) => challenge.as_str().unwrap().to_string(),
- None => return None,
+ Some(challenge) => challenge.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
let signature = match v.get("sig") {
- Some(signature) => signature.as_str().unwrap().to_string(),
- None => return None,
+ Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
- let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey).unwrap());
- let signature = Some(Sig::Ed25519(
- ed25519::Signature::from_base64(&signature).unwrap(),
- ));
- Some(WS2PConnectMessageV1 {
+ let pubkey = PubKey::Ed25519(ed25519::PublicKey::from_base58(&pubkey)?);
+ let signature = Some(Sig::Ed25519(ed25519::Signature::from_base64(&signature)?));
+ Ok(WS2PConnectMessageV1 {
currency,
pubkey,
challenge,
@@ -42,8 +40,11 @@ impl WS2PMessage for WS2PConnectMessageV1 {
)
}
fn verify(&self) -> bool {
- self.pubkey
- .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+ if let Some(sig) = self.signature {
+ self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+ } else {
+ false
+ }
}
}
diff --git a/lib/modules/ws2p-v1-legacy/src/constants.rs b/lib/modules/ws2p-v1-legacy/src/constants.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cdc14af73e1013607c3c924fc838e602d1cdb1a6
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/constants.rs
@@ -0,0 +1,55 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! WS2Pv1 constants
+
+/// API Name
+pub static WS2P_API: &'static str = "WS2P";
+
+/// Interval between to sequence of general actions
+pub static WS2P_GENERAL_STATE_INTERVAL: &'static u64 = &15;
+
+/// Connection wave interval at startup
+pub static WS2P_OUTCOMING_INTERVAL_AT_STARTUP: &'static u64 = &75;
+
+/// Interval of connection waves after the start-up phase
+pub static WS2P_OUTCOMING_INTERVAL: &'static u64 = &300;
+
+/// Default outgoing connection quota
+pub static WS2P_DEFAULT_OUTCOMING_QUOTA: &'static usize = &10;
+
+/// Maximum duration of a connection negotiation
+pub static WS2P_NEGOTIATION_TIMEOUT: &'static u64 = &15;
+
+/// Maximum waiting time for a response to a request
+//pub static WS2P_REQUEST_TIMEOUT : &'static u64 = &30;
+
+/// Maximum duration of inactivity of a connection (the connection will be closed after this delay)
+pub static WS2P_EXPIRE_TIMEOUT: &'static u64 = &120;
+
+/// Interval between 2 messages from which it''s perhaps a spam (in milliseconds)
+pub static WS2P_SPAM_INTERVAL_IN_MILLI_SECS: &'static u64 = &80;
+
+/// Number of consecutive closed messages from which messages will be considered as spam.
+pub static WS2P_SPAM_LIMIT: &'static usize = &6;
+
+/// Rest time in a situation of proven spam
+pub static WS2P_SPAM_SLEEP_TIME_IN_SEC: &'static u64 = &100;
+
+/// Duration between 2 endpoints saving
+pub static DURATION_BETWEEN_2_ENDPOINTS_SAVING: &'static u64 = &180;
+
+/// Duration between 2 requests from the pool of the wot data
+pub static PENDING_IDENTITIES_REQUEST_INTERVAL: &'static u64 = &40;
diff --git a/lib/modules/ws2p-v1-legacy/src/events/mod.rs b/lib/modules/ws2p-v1-legacy/src/events/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0e3731259de36e027add6106ac4b7d949cc746f4
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/mod.rs
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the events received and sent.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/events/received.rs b/lib/modules/ws2p-v1-legacy/src/events/received.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a8bb4f2785f185b944d75cf63ffce24243bd8d20
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/received.rs
@@ -0,0 +1,72 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing events received from other durs modules
+
+use crate::*;
+use dubp_documents::Document;
+use duniter_module::*;
+use durs_message::events::DursEvent;
+use std::ops::Deref;
+
+pub fn receive_event(
+ ws2p_module: &mut WS2PModule,
+ _event_type: ModuleEvent,
+ event_content: &DursEvent,
+) {
+ if let DursEvent::BlockchainEvent(ref bc_event) = *event_content {
+ match *bc_event.deref() {
+ BlockchainEvent::StackUpValidBlock(ref block) => {
+ ws2p_module.current_blockstamp = block.deref().blockstamp();
+ debug!(
+ "WS2PModule : current_blockstamp = {}",
+ ws2p_module.current_blockstamp
+ );
+ ws2p_module.my_head = Some(heads::generate_my_head(
+ &ws2p_module.key_pair,
+ ws2p_module.node_id,
+ ws2p_module.soft_name,
+ ws2p_module.soft_version,
+ &ws2p_module.current_blockstamp,
+ None,
+ ));
+ super::sent::send_network_event(
+ ws2p_module,
+ NetworkEvent::ReceiveHeads(vec![unwrap!(ws2p_module.my_head.clone())]),
+ );
+ // Send my head to all connections
+ let my_json_head = serializer::serialize_head(unwrap!(ws2p_module.my_head.clone()));
+ trace!("Send my HEAD: {:#?}", my_json_head);
+ let _results: Result<(), ws::Error> = ws2p_module
+ .websockets
+ .iter_mut()
+ .map(|ws| {
+ (ws.1).0.send(Message::text(
+ json!({
+ "name": "HEAD",
+ "body": {
+ "heads": [my_json_head]
+ }
+ })
+ .to_string(),
+ ))
+ })
+ .collect();
+ }
+ BlockchainEvent::RevertBlocks(ref _blocks) => {}
+ _ => {}
+ }
+ }
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/events/sent.rs b/lib/modules/ws2p-v1-legacy/src/events/sent.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bb5a49b6b86efbd31a3df4fdca1cd3f14e7dfa80
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/events/sent.rs
@@ -0,0 +1,59 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the events emitted by the blockchain module.
+
+use crate::WS2PModule;
+use duniter_module::{ModuleEvent, RouterThreadMessage};
+use duniter_network::documents::BlockchainDocument;
+use duniter_network::events::NetworkEvent;
+use durs_message::events::DursEvent;
+use durs_message::*;
+
+pub fn send_network_events(ws2p_module: &mut WS2PModule, events: Vec) {
+ for event in events {
+ send_network_event(ws2p_module, event);
+ }
+}
+
+pub fn send_network_event(ws2p_module: &mut WS2PModule, event: NetworkEvent) {
+ let module_event = match event {
+ NetworkEvent::ConnectionStateChange(_, _, _, _) => {
+ ModuleEvent::ConnectionsChangeNodeNetwork
+ }
+ NetworkEvent::ReceiveBlocks(_) => ModuleEvent::NewBlockFromNetwork,
+ NetworkEvent::ReceiveDocuments(ref network_docs) => {
+ if !network_docs.is_empty() {
+ match network_docs[0] {
+ BlockchainDocument::Block(_) => ModuleEvent::NewBlockFromNetwork,
+ BlockchainDocument::Transaction(_) => ModuleEvent::NewTxFromNetwork,
+ _ => ModuleEvent::NewWotDocFromNetwork,
+ }
+ } else {
+ return;
+ }
+ }
+ NetworkEvent::ReceiveHeads(_) => ModuleEvent::NewValidHeadFromNetwork,
+ NetworkEvent::ReceivePeers(_) => ModuleEvent::NewValidPeerFromNodeNetwork,
+ NetworkEvent::NewSelfPeer(_) => ModuleEvent::NewSelfPeer,
+ };
+ ws2p_module
+ .router_sender
+ .send(RouterThreadMessage::ModuleMessage(DursMsg::Event {
+ event_type: module_event,
+ event_content: DursEvent::NetworkEvent(event),
+ }))
+ .expect("Fail to send network event to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/heads.rs b/lib/modules/ws2p-v1-legacy/src/heads.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/heads.rs
rename to lib/modules/ws2p-v1-legacy/src/heads.rs
diff --git a/lib/modules/ws2p-v1-legacy/src/lib.rs b/lib/modules/ws2p-v1-legacy/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c19854b3f2a4dc6cd1960ff93bcd693f1bc69565
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/lib.rs
@@ -0,0 +1,1075 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! WebSocketToPeer API for the Durs project.
+
+#![deny(
+ missing_debug_implementations,
+ missing_copy_implementations,
+ trivial_casts,
+ unsafe_code,
+ unstable_features,
+ unused_import_braces,
+ unused_qualifications
+)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate serde_json;
+#[macro_use]
+extern crate structopt;
+
+mod ack_message;
+mod connect_message;
+pub mod constants;
+mod events;
+mod heads;
+mod ok_message;
+pub mod parsers;
+mod requests;
+mod responses;
+pub mod serializer;
+pub mod ws2p_db;
+pub mod ws_connections;
+
+use crate::ack_message::WS2PAckMessageV1;
+use crate::connect_message::WS2PConnectMessageV1;
+use crate::constants::*;
+use crate::ok_message::WS2POkMessageV1;
+use crate::parsers::blocks::parse_json_block;
+use crate::requests::sent::send_dal_request;
+use crate::ws2p_db::DbEndpoint;
+use crate::ws_connections::messages::WS2PConnectionMessage;
+use crate::ws_connections::states::WS2PConnectionState;
+use crate::ws_connections::*;
+use dubp_documents::Blockstamp;
+use duniter_conf::DuRsConf;
+use duniter_module::*;
+use duniter_network::cli::sync::SyncOpt;
+use duniter_network::documents::*;
+use duniter_network::events::*;
+use duniter_network::requests::*;
+use duniter_network::*;
+use dup_crypto::keys::*;
+use durs_common_tools::fatal_error;
+use durs_message::events::*;
+use durs_message::requests::*;
+use durs_message::responses::*;
+use durs_message::*;
+use durs_network_documents::network_endpoint::*;
+use durs_network_documents::network_head::*;
+use durs_network_documents::*;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::fs;
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::sync::mpsc;
+use std::thread;
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+use unwrap::unwrap;
+use ws::Message;
+
+#[inline]
+#[cfg(not(feature = "ssl"))]
+pub fn ssl() -> bool {
+ false
+}
+#[inline]
+#[cfg(feature = "ssl")]
+pub fn ssl() -> bool {
+ true
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// WS2P Configuration
+pub struct WS2PConf {
+ /// Limit of outcoming connections
+ pub outcoming_quota: usize,
+ /// Default WS2P endpoints provides by configuration file
+ pub sync_endpoints: Vec,
+}
+
+impl Default for WS2PConf {
+ fn default() -> Self {
+ WS2PConf {
+ outcoming_quota: *WS2P_DEFAULT_OUTCOMING_QUOTA,
+ sync_endpoints: vec![
+ unwrap!(EndpointV1::parse_from_raw(
+ "WS2P c1c39a0a ts.g1.librelois.fr 443 /ws2p",
+ PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
+ )),),
+ 0,
+ 0,
+ )),
+ unwrap!(EndpointV1::parse_from_raw(
+ "WS2P fb17fcd4 g1.duniter.fr 443 /ws2p",
+ PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "38MEAZN68Pz1DTvT3tqgxx4yQP6snJCQhPqEFxbDk4aE",
+ ))),
+ 0,
+ 0,
+ )),
+ unwrap!(EndpointV1::parse_from_raw(
+ "WS2P 7b33becd g1.nordstrom.duniter.org 443 /ws2p",
+ PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "DWoSCRLQyQ48dLxUGr1MDKg4NFcbPbC56LN2hJjCCPpZ",
+ ))),
+ 0,
+ 0,
+ )),
+ unwrap!(EndpointV1::parse_from_raw(
+ "WS2P dff60418 duniter.normandie-libre.fr 443 /ws2p",
+ PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "8t6Di3pLxxoTEfjXHjF49pNpjSTXuGEQ6BpkT75CkNb2",
+ ))),
+ 0,
+ 0,
+ )),
+ ],
+ }
+ }
+}
+
+#[derive(Debug)]
+/// Store a Signal receive from network (after message treatment)
+pub enum WS2PSignal {
+ /// Receive a websocket error from a connextion. `NodeFullId` store the identifier of connection.
+ WSError(NodeFullId),
+ /// A new connection is successfully established with `NodeFullId`.
+ ConnectionEstablished(NodeFullId),
+ NegociationTimeout(NodeFullId),
+ Timeout(NodeFullId),
+ DalRequest(NodeFullId, ModuleReqId, serde_json::Value),
+ PeerCard(NodeFullId, serde_json::Value, Vec),
+ Heads(NodeFullId, Vec),
+ Document(NodeFullId, BlockchainDocument),
+ ReqResponse(
+ ModuleReqId,
+ OldNetworkRequest,
+ NodeFullId,
+ serde_json::Value,
+ ),
+ Empty,
+ NoConnection,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum NetworkConsensusError {
+ InsufficientData(usize),
+ Fork,
+}
+
+#[derive(Debug)]
+pub enum SendRequestError {
+ RequestTypeMustNotBeTransmitted(),
+ WSError(usize, Vec),
+}
+
+#[derive(Debug)]
+pub struct WS2PModule {
+ pub conf: WS2PConf,
+ pub count_dal_requests: u32,
+ pub currency: Option,
+ pub current_blockstamp: Blockstamp,
+ pub ep_file_path: PathBuf,
+ pub heads_cache: HashMap,
+ pub key_pair: KeyPairEnum,
+ pub main_thread_channel: (
+ mpsc::Sender,
+ mpsc::Receiver,
+ ),
+ pub my_head: Option,
+ pub next_receiver: usize,
+ pub node_id: NodeId,
+ pub requests_awaiting_response:
+ HashMap,
+ pub router_sender: mpsc::Sender>,
+ pub soft_name: &'static str,
+ pub soft_version: &'static str,
+ pub ssl: bool,
+ pub websockets: HashMap,
+ pub ws2p_endpoints: HashMap,
+ pub uids_cache: HashMap,
+}
+
+impl WS2PModule {
+ pub fn new(
+ soft_meta_datas: &SoftwareMetaDatas,
+ conf: WS2PConf,
+ ep_file_path: PathBuf,
+ key_pair: KeyPairEnum,
+ router_sender: mpsc::Sender>,
+ ) -> WS2PModule {
+ WS2PModule {
+ router_sender,
+ key_pair,
+ currency: None,
+ current_blockstamp: Blockstamp::default(),
+ conf,
+ ep_file_path,
+ soft_name: soft_meta_datas.soft_name,
+ soft_version: soft_meta_datas.soft_version,
+ ssl: ssl(),
+ node_id: NodeId(soft_meta_datas.conf.my_node_id()),
+ main_thread_channel: mpsc::channel(),
+ next_receiver: 0,
+ ws2p_endpoints: HashMap::new(),
+ websockets: HashMap::new(),
+ requests_awaiting_response: HashMap::new(),
+ heads_cache: HashMap::new(),
+ my_head: None,
+ uids_cache: HashMap::new(),
+ count_dal_requests: 0,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum WS2PThreadSignal {
+ DursMsg(Box),
+ WS2PConnectionMessage(WS2PConnectionMessage),
+}
+
+#[derive(Copy, Clone, Debug)]
+/// Error when parsing WS2P message
+pub struct WS2PMsgParseErr {}
+
+impl From for WS2PMsgParseErr {
+ fn from(_: dup_crypto::bases::BaseConvertionError) -> Self {
+ WS2PMsgParseErr {}
+ }
+}
+
+pub trait WS2PMessage: Sized {
+ fn parse(v: &serde_json::Value, currency: String) -> Result;
+ fn to_raw(&self) -> String;
+ fn sign(&self, key_pair: KeyPairEnum) -> Sig {
+ key_pair.sign(self.to_raw().as_bytes())
+ }
+ fn verify(&self) -> bool;
+ //fn parse_and_verify(v: serde_json::Value, currency: String) -> bool;
+}
+
+#[derive(Debug)]
+/// WS2PFeaturesParseError
+pub enum WS2PFeaturesParseError {
+ /// UnknowApiFeature
+ UnknowApiFeature(String),
+}
+
+impl ApiModule for WS2PModule {
+ type ParseErr = WS2PFeaturesParseError;
+ /// Parse raw api features
+ fn parse_raw_api_features(str_features: &str) -> Result {
+ let str_features: Vec<&str> = str_features.split(' ').collect();
+ let mut api_features = Vec::with_capacity(0);
+ for str_feature in str_features {
+ match str_feature {
+ "DEF" => api_features[0] += 1u8,
+ "LOW" => api_features[0] += 2u8,
+ "ABF" => api_features[0] += 4u8,
+ _ => {
+ return Err(WS2PFeaturesParseError::UnknowApiFeature(String::from(
+ str_feature,
+ )));
+ }
+ }
+ }
+ Ok(ApiFeatures(api_features))
+ }
+}
+
+impl NetworkModule for WS2PModule {
+ fn sync(
+ _soft_meta_datas: &SoftwareMetaDatas,
+ _keys: RequiredKeysContent,
+ _conf: WS2PConf,
+ _main_sender: mpsc::Sender>,
+ _sync_params: SyncOpt,
+ ) -> Result<(), ModuleInitError> {
+ println!("Downlaod blockchain from network...");
+ println!("Error : not yet implemented !");
+ Ok(())
+ }
+}
+
+#[derive(StructOpt, Debug, Copy, Clone)]
+#[structopt(
+ name = "ws2p",
+ raw(setting = "structopt::clap::AppSettings::ColoredHelp")
+)]
+/// WS2Pv1 subcommand options
+pub struct WS2POpt {}
+
+impl DursModule for WS2PModule {
+ type ModuleConf = WS2PConf;
+ type ModuleOpt = WS2POpt;
+
+ fn name() -> ModuleStaticName {
+ ModuleStaticName("ws2p")
+ }
+ fn priority() -> ModulePriority {
+ ModulePriority::Essential()
+ }
+ fn ask_required_keys() -> RequiredKeys {
+ RequiredKeys::NetworkKeyPair()
+ }
+ fn have_subcommand() -> bool {
+ true
+ }
+ fn exec_subcommand(
+ _soft_meta_datas: &SoftwareMetaDatas,
+ _keys: RequiredKeysContent,
+ _module_conf: Self::ModuleConf,
+ _subcommand_args: WS2POpt,
+ ) {
+ println!("Succesfully exec ws2p subcommand !")
+ }
+ fn start(
+ soft_meta_datas: &SoftwareMetaDatas,
+ keys: RequiredKeysContent,
+ conf: WS2PConf,
+ router_sender: mpsc::Sender>,
+ load_conf_only: bool,
+ ) -> Result<(), ModuleInitError> {
+ // Get start time
+ let start_time = SystemTime::now();
+
+ // Get key_pair
+ let key_pair = if let RequiredKeysContent::NetworkKeyPair(key_pair) = keys {
+ key_pair
+ } else {
+ return Err(ModuleInitError::FailToLoadConf(
+ "WS2PModule fatal error at load_conf() : keys != NetworkKeyPair",
+ ));
+ };
+
+ // load conf
+ let mut ws2p_endpoints = HashMap::new();
+ for ep in &conf.sync_endpoints {
+ info!("Load sync endpoint {}", ep.raw_endpoint);
+ let node_full_id = ep
+ .node_full_id()
+ .expect("Fail to get endpoint node_full_id");
+ ws2p_endpoints.insert(
+ node_full_id,
+ DbEndpoint {
+ ep: ep.clone(),
+ state: WS2PConnectionState::Close,
+ last_check: 0,
+ },
+ );
+ }
+
+ // Get endpoints file path
+ let mut ep_file_path =
+ duniter_conf::datas_path(&soft_meta_datas.profile, &soft_meta_datas.conf.currency());
+ ep_file_path.push("ws2pv1");
+ if !ep_file_path.exists() {
+ fs::create_dir(ep_file_path.as_path()).expect("Impossible to create ws2pv1 dir !");
+ }
+ ep_file_path.push("endpoints.bin");
+
+ // Define WS2PModule
+ let mut ws2p_module = WS2PModule::new(
+ soft_meta_datas,
+ conf,
+ ep_file_path.clone(),
+ key_pair,
+ router_sender.clone(),
+ );
+ ws2p_module.currency = Some(soft_meta_datas.conf.currency().to_string());
+ ws2p_module.ws2p_endpoints = ws2p_endpoints;
+
+ // Create ws2p main thread channel
+ let ws2p_sender_clone = ws2p_module.main_thread_channel.0.clone();
+
+ // Get ws2p endpoints in file
+ info!("TMP: WS2P SSL={}", ssl());
+ let count;
+ match ws2p_db::get_endpoints(&ep_file_path) {
+ Ok(ws2p_enpoints) => {
+ let ws2p_enpoints = ws2p_enpoints
+ .into_iter()
+ .filter(|(_, dal_ep)| cfg!(feature = "ssl") || dal_ep.ep.port != 443)
+ .collect::>();
+ count = ws2p_enpoints.len();
+ ws2p_module.ws2p_endpoints.extend(ws2p_enpoints);
+ }
+ Err(err) => fatal_error!("WS2Pv1: fail to load endpoints from DB: {:?}", err),
+ }
+ info!("Load {} endpoints from DB !", count);
+
+ // Stop here in load_conf_only mode
+ if load_conf_only {
+ return Ok(());
+ }
+
+ // Create proxy channel
+ let (proxy_sender, proxy_receiver): (mpsc::Sender, mpsc::Receiver) =
+ mpsc::channel();
+ let proxy_sender_clone = proxy_sender.clone();
+
+ // Launch a proxy thread that transform DursMsg to WS2PThreadSignal(DursMsg)
+ thread::spawn(move || {
+ // Send proxy sender to main
+ router_sender
+ .send(RouterThreadMessage::ModuleRegistration(
+ WS2PModule::name(),
+ proxy_sender_clone,
+ vec![ModuleRole::InterNodesNetwork],
+ vec![
+ ModuleEvent::NewValidBlock,
+ ModuleEvent::NewWotDocInPool,
+ ModuleEvent::NewTxinPool,
+ ],
+ vec![],
+ vec![],
+ ))
+ .expect("Fatal error : ws2p module fail to send is sender channel !");
+ debug!("Send ws2p sender to main thread.");
+ loop {
+ match proxy_receiver.recv() {
+ Ok(message) => {
+ let stop = if let DursMsg::Stop = message {
+ true
+ } else {
+ false
+ };
+ ws2p_sender_clone
+ .send(WS2PThreadSignal::DursMsg(Box::new(message)))
+ .expect(
+ "Fatal error : fail to relay DursMsgContent to ws2p main thread !",
+ );
+ if stop {
+ break;
+ };
+ }
+ Err(e) => panic!(format!("{}", e)),
+ }
+ }
+ });
+
+ // Request current blockstamp
+ send_dal_request(&mut ws2p_module, &BlockchainRequest::CurrentBlockstamp());
+
+ // Start
+ connect_to_know_endpoints(&mut ws2p_module);
+ ws2p_module.main_loop(start_time, soft_meta_datas);
+
+ Ok(())
+ }
+}
+
+impl WS2PModule {
+ fn main_loop(mut self, start_time: SystemTime, soft_meta_datas: &SoftwareMetaDatas) {
+ // Initialize variables
+ let key_pair = self.key_pair;
+ let mut last_ws2p_connecting_wave = SystemTime::now();
+ let mut last_ws2p_state_print = SystemTime::now();
+ let mut last_ws2p_endpoints_write = SystemTime::now();
+ let mut endpoints_to_update_status: HashMap = HashMap::new();
+ let mut last_identities_request = UNIX_EPOCH;
+
+ loop {
+ match self
+ .main_thread_channel
+ .1
+ .recv_timeout(Duration::from_millis(200))
+ {
+ Ok(message) => match message {
+ WS2PThreadSignal::DursMsg(ref durs_mesage) => {
+ match *durs_mesage.deref() {
+ DursMsg::Stop => break,
+ DursMsg::Request {
+ ref req_content, ..
+ } => requests::received::receive_req(&mut self, req_content),
+ DursMsg::Event {
+ ref event_type,
+ ref event_content,
+ ..
+ } => events::received::receive_event(
+ &mut self,
+ *event_type,
+ event_content,
+ ),
+ DursMsg::Response {
+ ref res_content, ..
+ } => {
+ if let DursResContent::BlockchainResponse(ref bc_res) = *res_content
+ {
+ match *bc_res.deref() {
+ BlockchainResponse::CurrentBlockstamp(
+ ref _requester_id,
+ ref current_blockstamp_,
+ ) => {
+ debug!(
+ "WS2PModule : receive DALResBc::CurrentBlockstamp({})",
+ self.current_blockstamp
+ );
+ self.current_blockstamp = *current_blockstamp_;
+ if self.my_head.is_none() {
+ self.my_head = Some(heads::generate_my_head(
+ &key_pair,
+ NodeId(soft_meta_datas.conf.my_node_id()),
+ soft_meta_datas.soft_name,
+ soft_meta_datas.soft_version,
+ &self.current_blockstamp,
+ None,
+ ));
+ }
+ let event =
+ NetworkEvent::ReceiveHeads(vec![unwrap!(self
+ .my_head
+ .clone())]);
+ events::sent::send_network_event(&mut self, event);
+ }
+ BlockchainResponse::UIDs(ref _req_id, ref uids) => {
+ // Add uids to heads
+ for head in self.heads_cache.values_mut() {
+ if let Some(uid_option) = uids.get(&head.pubkey()) {
+ if let Some(ref uid) = *uid_option {
+ head.set_uid(uid);
+ self.uids_cache
+ .insert(head.pubkey(), uid.to_string());
+ } else {
+ self.uids_cache.remove(&head.pubkey());
+ }
+ }
+ }
+ // Resent heads to other modules
+ let event = NetworkEvent::ReceiveHeads(
+ self.heads_cache.values().cloned().collect(),
+ );
+ events::sent::send_network_event(&mut self, event);
+ // Resent to other modules connections that match receive uids
+ let events = self.ws2p_endpoints
+ .iter()
+ .filter_map(|(node_full_id, DbEndpoint { ep, state, .. })| {
+ if let Some(uid_option) = uids.get(&node_full_id.1) {
+ Some(NetworkEvent::ConnectionStateChange(
+ *node_full_id,
+ *state as u32,
+ uid_option.clone(),
+ ep.get_url(false, false)
+ .expect("Endpoint unreachable !"),
+ ))
+ } else {
+ None
+ }
+ })
+ .collect();
+ events::sent::send_network_events(&mut self, events);
+ }
+ _ => {} // Others BlockchainResponse variants
+ }
+ }
+ }
+ _ => {} // Others DursMsg variants
+ }
+ }
+ WS2PThreadSignal::WS2PConnectionMessage(ws2p_conn_message) => {
+ match crate::ws_connections::messages::ws2p_conn_message_pretreatment(
+ &mut self,
+ ws2p_conn_message,
+ ) {
+ WS2PSignal::NoConnection => {
+ warn!("WS2PSignal::NoConnection");
+ }
+ WS2PSignal::ConnectionEstablished(ws2p_full_id) => {
+ let req_id =
+ ModuleReqId(self.requests_awaiting_response.len() as u32);
+ let module_id = WS2PModule::name();
+ debug!("WS2P: send req to: ({:?})", ws2p_full_id);
+ let _current_request_result =
+ ws_connections::requests::sent::send_request_to_specific_node(
+ &mut self,
+ &ws2p_full_id,
+ &OldNetworkRequest::GetCurrent(ModuleReqFullId(
+ module_id, req_id,
+ )),
+ );
+ if self.uids_cache.get(&ws2p_full_id.1).is_none() {
+ send_dal_request(
+ &mut self,
+ &BlockchainRequest::UIDs(vec![ws2p_full_id.1]),
+ );
+ }
+ let event = NetworkEvent::ConnectionStateChange(
+ ws2p_full_id,
+ WS2PConnectionState::Established as u32,
+ self.uids_cache.get(&ws2p_full_id.1).cloned(),
+ self.ws2p_endpoints[&ws2p_full_id]
+ .ep
+ .get_url(false, false)
+ .expect("Endpoint unreachable !"),
+ );
+ events::sent::send_network_event(&mut self, event);
+ }
+ WS2PSignal::WSError(ws2p_full_id) => {
+ endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+ close_connection(
+ &mut self,
+ &ws2p_full_id,
+ WS2PCloseConnectionReason::WsError,
+ );
+ let event = NetworkEvent::ConnectionStateChange(
+ ws2p_full_id,
+ WS2PConnectionState::WSError as u32,
+ self.uids_cache.get(&ws2p_full_id.1).cloned(),
+ self.ws2p_endpoints[&ws2p_full_id]
+ .ep
+ .get_url(false, false)
+ .expect("Endpoint unreachable !"),
+ );
+ events::sent::send_network_event(&mut self, event);
+ }
+ WS2PSignal::NegociationTimeout(ws2p_full_id) => {
+ endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+ let event = NetworkEvent::ConnectionStateChange(
+ ws2p_full_id,
+ WS2PConnectionState::Denial as u32,
+ self.uids_cache.get(&ws2p_full_id.1).cloned(),
+ self.ws2p_endpoints[&ws2p_full_id]
+ .ep
+ .get_url(false, false)
+ .expect("Endpoint unreachable !"),
+ );
+ events::sent::send_network_event(&mut self, event);
+ }
+ WS2PSignal::Timeout(ws2p_full_id) => {
+ endpoints_to_update_status.insert(ws2p_full_id, SystemTime::now());
+ let event = NetworkEvent::ConnectionStateChange(
+ ws2p_full_id,
+ WS2PConnectionState::Close as u32,
+ self.uids_cache.get(&ws2p_full_id.1).cloned(),
+ self.ws2p_endpoints[&ws2p_full_id]
+ .ep
+ .get_url(false, false)
+ .expect("Endpoint unreachable !"),
+ );
+ events::sent::send_network_event(&mut self, event);
+ }
+ WS2PSignal::PeerCard(_ws2p_full_id, _peer_card, ws2p_endpoints) => {
+ //trace!("WS2PSignal::PeerCard({})", ws2p_full_id);
+ //self.send_network_event(NetworkEvent::ReceivePeers(_));
+ for ep in ws2p_endpoints {
+ match self.ws2p_endpoints.get(
+ &ep.node_full_id()
+ .expect("WS2P: Fail to get ep.node_full_id() !"),
+ ) {
+ Some(_) => {}
+ None => {
+ if let Some(_api) =
+ ws2p_db::string_to_api(&ep.api.0.clone())
+ {
+ endpoints_to_update_status.insert(
+ ep.node_full_id().expect(
+ "WS2P: Fail to get ep.node_full_id() !",
+ ),
+ SystemTime::now(),
+ );
+ }
+ if cfg!(feature = "ssl") || ep.port != 443 {
+ connect_to(&mut self, &ep);
+ }
+ }
+ };
+ }
+ }
+ WS2PSignal::Heads(ws2p_full_id, heads) => {
+ trace!("WS2PSignal::Heads({}, {:?})", ws2p_full_id, heads.len());
+ send_dal_request(
+ &mut self,
+ &BlockchainRequest::UIDs(
+ heads.iter().map(NetworkHead::pubkey).collect(),
+ ),
+ );
+ let event = NetworkEvent::ReceiveHeads(
+ heads
+ .iter()
+ .map(|head| {
+ let mut new_head = head.clone();
+ if let Some(uid) = self.uids_cache.get(&head.pubkey()) {
+ new_head.set_uid(uid);
+ }
+ new_head
+ })
+ .collect(),
+ );
+ events::sent::send_network_event(&mut self, event);
+ }
+ WS2PSignal::Document(ws2p_full_id, network_doc) => {
+ trace!("WS2PSignal::Document({})", ws2p_full_id);
+ events::sent::send_network_event(
+ &mut self,
+ NetworkEvent::ReceiveDocuments(vec![network_doc]),
+ );
+ }
+ WS2PSignal::ReqResponse(req_id, req, recipient_full_id, response) => {
+ match req {
+ OldNetworkRequest::GetCurrent(ref _req_id) => {
+ info!(
+ "WS2PSignal::ReceiveCurrent({}, {:?})",
+ req_id.0, req
+ );
+ if let Some(block) = parse_json_block(&response) {
+ crate::responses::sent::send_network_req_response(
+ &self,
+ req.get_req_full_id().0,
+ req.get_req_full_id().1,
+ NetworkResponse::CurrentBlock(
+ ModuleReqFullId(WS2PModule::name(), req_id),
+ recipient_full_id,
+ Box::new(block),
+ ),
+ );
+ }
+ }
+ OldNetworkRequest::GetBlocks(ref _req_id, count, from) => {
+ info!(
+ "WS2PSignal::ReceiveChunk({}, {} blocks from {})",
+ req_id.0, count, from
+ );
+ if response.is_array() {
+ let mut chunk = Vec::new();
+ for json_block in unwrap!(response.as_array()) {
+ if let Some(block) = parse_json_block(json_block) {
+ chunk.push(block);
+ } else {
+ warn!("WS2PModule: Error : fail to parse one json block !");
+ }
+ }
+ debug!("Send chunk to followers : {}", from);
+ events::sent::send_network_event(
+ &mut self,
+ NetworkEvent::ReceiveBlocks(chunk),
+ );
+ }
+ }
+ OldNetworkRequest::GetRequirementsPending(
+ _req_id,
+ min_cert,
+ ) => {
+ info!(
+ "WS2PSignal::ReceiveRequirementsPending({}, {})",
+ req_id.0, min_cert
+ );
+ debug!("----------------------------------------");
+ debug!("- BEGIN IDENTITIES PENDING -");
+ debug!("----------------------------------------");
+ debug!("{:#?}", response);
+ debug!("----------------------------------------");
+ debug!("- END IDENTITIES PENDING -");
+ debug!("----------------------------------------");
+ }
+ _ => {}
+ }
+ }
+ WS2PSignal::Empty => {}
+ _ => {}
+ }
+ }
+ },
+ Err(e) => match e {
+ mpsc::RecvTimeoutError::Disconnected => {
+ panic!("Disconnected ws2p module !");
+ }
+ mpsc::RecvTimeoutError::Timeout => {}
+ },
+ }
+ if unwrap!(SystemTime::now().duration_since(last_ws2p_endpoints_write))
+ > Duration::new(*DURATION_BETWEEN_2_ENDPOINTS_SAVING, 0)
+ {
+ last_ws2p_endpoints_write = SystemTime::now();
+ if let Err(err) = ws2p_db::write_endpoints(&self.ep_file_path, &self.ws2p_endpoints)
+ {
+ fatal_error!("WS2P1: Fail to write endpoints in DB : {:?}", err);
+ }
+ }
+ if unwrap!(SystemTime::now().duration_since(last_ws2p_state_print))
+ > Duration::new(*WS2P_GENERAL_STATE_INTERVAL, 0)
+ {
+ last_ws2p_state_print = SystemTime::now();
+ let mut connected_nodes = Vec::new();
+ for (k, DbEndpoint { state, .. }) in self.ws2p_endpoints.clone() {
+ if let WS2PConnectionState::Established = state {
+ connected_nodes.push(k);
+ }
+ }
+ // Print current_blockstamp
+ info!(
+ "WS2PModule : current_blockstamp() = {:?}",
+ self.current_blockstamp
+ );
+ // New WS2P connection wave
+ if connected_nodes.len() < self.conf.clone().outcoming_quota
+ && (unwrap!(SystemTime::now().duration_since(last_ws2p_connecting_wave))
+ > Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)
+ || (unwrap!(SystemTime::now().duration_since(last_ws2p_connecting_wave))
+ > Duration::new(*WS2P_OUTCOMING_INTERVAL_AT_STARTUP, 0)
+ && unwrap!(SystemTime::now().duration_since(start_time))
+ < Duration::new(*WS2P_OUTCOMING_INTERVAL, 0)))
+ {
+ last_ws2p_connecting_wave = SystemTime::now();
+ info!("Connected to know endpoints...");
+ connect_to_know_endpoints(&mut self);
+ }
+ // Request pending_identities from network
+ if unwrap!(SystemTime::now().duration_since(last_identities_request))
+ > Duration::new(*PENDING_IDENTITIES_REQUEST_INTERVAL, 0)
+ && unwrap!(SystemTime::now().duration_since(start_time)) > Duration::new(10, 0)
+ {
+ /*info!("get pending_identities from all connections...");
+ let _blocks_request_result = self.send_request_to_all_connections(
+ &OldNetworkRequest::GetRequirementsPending(ModuleReqId(0 as u32), 5),
+ );*/
+ last_identities_request = SystemTime::now();
+ }
+ // ..
+ // Request current blockstamp
+ send_dal_request(&mut self, &BlockchainRequest::CurrentBlockstamp());
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::parsers::blocks::parse_json_block;
+ use super::*;
+ use crate::ws_connections::requests::sent::network_request_to_json;
+ use dubp_documents::documents::block::BlockDocument;
+ use duniter_module::DursModule;
+
+ #[test]
+ fn test_parse_json_block() {
+ let json_block = json!({
+ "fork": false,
+ "version": 10,
+ "nonce": 10500000059239 as u64,
+ "number": 109966,
+ "powMin": 88,
+ "time": 1523300656,
+ "medianTime": 1523295259,
+ "membersCount": 933,
+ "monetaryMass": 146881563,
+ "unitbase": 0,
+ "issuersCount": 44,
+ "issuersFrame": 221,
+ "issuersFrameVar": 0,
+ "currency": "g1",
+ "issuer": "GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4",
+ "signature": "GCg2Lti3TdxWlhA8JF8pRI+dRQ0XZVtcC4BqO/COTpjTQFdWG6qmUNVvdeYCtR/lu1JQe3N/IhrbyV6L/6I+Cg==",
+ "hash": "000000EF5B2AA849F4C3AF3D35E1284EA1F34A9F617EA806CE8371619023DC74",
+ "parameters": "",
+ "previousHash": "000004C00602F8A27AE078DE6351C0DDA1EA0974A78D2BEFA7DFBE7B7C3146FD",
+ "previousIssuer": "5SwfQubSat5SunNafCsunEGTY93nVM4kLSsuprNqQb6S",
+ "inner_hash": "61F02B1A6AE2E4B9A1FD66CE673258B4B21C0076795571EE3C9DC440DD06C46C",
+ "dividend": null,
+ "identities": [],
+ "joiners": [],
+ "actives": [],
+ "leavers": [],
+ "revoked": [],
+ "excluded": [],
+ "certifications": [
+ "Hm5qjaNuHogNRdGZ4vgnLA9DMZVUu5YWzVup5mubuxCc:8AmdBsimcLziXaCS4AcVUfPx7rkjeic7482dLbBkuZw6:109964:yHKBGMeuxyIqFb295gVNK6neRC+U0tmsX1Zed3TLjS3ZZHYYycE1piLcYsTKll4ifNVp6rm+hd/CLdHYB+29CA==",
+ "BncjgJeFpGsMCCsUfzNLEexjsbuX3V2mg9P67ov2LkwK:DyBUBNpzpfvjtwYYSaVMM6ST6t2DNg3NCE9CU9bRQFhF:105864:cJEGW9WxJwlMA2+4LNAK4YieyseUy1WIkFh1YLYD+JJtJEoCSnIQRXzhiAoRpGaj0bRz8sTpwI6PRkuVoDJJDQ=="
+ ],
+ "transactions": [
+ {
+ "version": 10,
+ "currency": "g1",
+ "locktime": 0,
+ "hash": "80FE1E83DC4D0B722CA5F8363EFC6A3E29071032EBB71C1E0DF8D4FEA589C698",
+ "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
+ "blockstampTime": 0,
+ "issuers": [
+ "6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT"
+ ],
+ "inputs": [
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98284",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98519",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:98779",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99054",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99326",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99599",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:99884",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100174",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100469",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:100746",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:101036",
+ "1001:0:D:6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT:101327"
+ ],
+ "outputs": [
+ "12000:0:SIG(HmH5beJqKGMeotcQUrSW7Wo5tKvAksHmfYXfiSQ9EbWz)",
+ "12:0:SIG(6PiqcuUWhyiBF3Lgcht8c1yfk6gMfQzcUc46CqrJfeLT)"
+ ],
+ "unlocks": [
+ "0:SIG(0)",
+ "1:SIG(0)",
+ "2:SIG(0)",
+ "3:SIG(0)",
+ "4:SIG(0)",
+ "5:SIG(0)",
+ "6:SIG(0)",
+ "7:SIG(0)",
+ "8:SIG(0)",
+ "9:SIG(0)",
+ "10:SIG(0)",
+ "11:SIG(0)"
+ ],
+ "signatures": [
+ "MZxoKxYgwufh/s5mwLCsYEZXtIsP1hEKCyAzLipJsvCbR9xj7wXUw0C/ahwvZfBtR7+QVPIfLmwYEol1JcHjDw=="
+ ],
+ "comment": "Adhesion 2018"
+ },
+ {
+ "version": 10,
+ "currency": "g1",
+ "locktime": 0,
+ "hash": "B80507412B35BD5EB437AE0D3EB97E60E3A4974F5CDEA1AF7E2127C0E943481F",
+ "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
+ "blockstampTime": 0,
+ "issuers": [
+ "8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU"
+ ],
+ "inputs": [
+ "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:91560",
+ "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:91850",
+ "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92111",
+ "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92385",
+ "1001:0:D:8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU:92635"
+ ],
+ "outputs": [
+ "5000:0:SIG(BzHnbec1Gov7dLSt1EzJS7vikoQCECeuvZs4wamZAcT1)",
+ "5:0:SIG(8gundJEbfm73Kx3jjw8YivJyz8qD2igjf6baCBLFCxPU)"
+ ],
+ "unlocks": [
+ "0:SIG(0)",
+ "1:SIG(0)",
+ "2:SIG(0)",
+ "3:SIG(0)",
+ "4:SIG(0)"
+ ],
+ "signatures": [
+ "A+ukwRvLWs1gZQ0KAqAnknEgmRQHdrnOvNuBx/WZqje17BAPrVxSxKpqwU6MiajU+ppigsYp6Bu0FdPf/tGnCQ=="
+ ],
+ "comment": ""
+ },
+ {
+ "version": 10,
+ "currency": "g1",
+ "locktime": 0,
+ "hash": "D8970E6629C0381A78534EEDD86803E9215A7EC4C494BAEA79EB19425F9B4D31",
+ "blockstamp": "109964-00000168105D4A8A8BC8C0DC70033F45ABE472782C75A7F2074D0F4D4A3B7B2B",
+ "blockstampTime": 0,
+ "issuers": [
+ "FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg"
+ ],
+ "inputs": [
+ "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:36597",
+ "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:36880",
+ "1000:0:D:FnSXE7QyBfs4ozoYAt5NEewWhHEPorf38cNXu3kX9xsg:37082"
+ ],
+ "outputs": [
+ "3000:0:SIG(BBC8Rnh4CWN1wBrPLevK7GRFFVDVw7Lu24YNMUmhqoHU)"
+ ],
+ "unlocks": [
+ "0:SIG(0)",
+ "1:SIG(0)",
+ "2:SIG(0)"
+ ],
+ "signatures": [
+ "OpiF/oQfIigOeAtsteukU0w9FPSELE+BVTxhmsQ8bEeYGlwovG2VF8ZFiJkLLPi6vFuKgwzULJfjNGd97twZCw=="
+ ],
+ "comment": "1 billet pour une seance.pour un chouette film"
+ }
+ ],
+ });
+ let mut block: BlockDocument =
+ parse_json_block(&json_block).expect("Fail to parse test json block !");
+ assert_eq!(
+ block
+ .inner_hash
+ .expect("Try to get inner_hash of an uncompleted or reduce block !")
+ .to_hex(),
+ "61F02B1A6AE2E4B9A1FD66CE673258B4B21C0076795571EE3C9DC440DD06C46C"
+ );
+ block.compute_hash();
+ assert_eq!(
+ block
+ .hash
+ .expect("Try to get hash of an uncompleted or reduce block !")
+ .0
+ .to_hex(),
+ "000000EF5B2AA849F4C3AF3D35E1284EA1F34A9F617EA806CE8371619023DC74"
+ );
+ }
+
+ #[test]
+ fn ws2p_requests() {
+ let module_id = WS2PModule::name();
+ let request =
+ OldNetworkRequest::GetBlocks(ModuleReqFullId(module_id, ModuleReqId(58)), 50, 0);
+ assert_eq!(
+ network_request_to_json(&request),
+ json!({
+ "reqId": format!("{:x}", 58),
+ "body": {
+ "name": "BLOCKS_CHUNK",
+ "params": {
+ "count": 50,
+ "fromNumber": 0
+ }
+ }
+ })
+ );
+ assert_eq!(
+ network_request_to_json(&request).to_string(),
+ "{\"body\":{\"name\":\"BLOCKS_CHUNK\",\"params\":{\"count\":50,\"fromNumber\":0}},\"reqId\":\"3a\"}"
+ );
+ }
+
+ #[test]
+ fn ws2p_parse_head() {
+ let head = json!({
+ "message": "WS2POTMIC:HEAD:1:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3",
+ "sig": "trtK9GXvTdfND995ohWEderpO3NkIqi1X6mBeVvMcaHckq+lIGqjWvJ9t9Vccz5t+VGaSmGUihDl4q6eldIYBw==",
+ "messageV2": "WS2POTMIC:HEAD:2:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3:25:22",
+ "sigV2": "x6ehPMuYjGY+z7wEGnJGyMBxMKUdu01RWaF0b0XCtoVjg67cCvT4H0V/Qcxn4bAGqzy5ux2fA7NiI+81bBnqDw==",
+ "step": 0
+ });
+ let mut heads_count = 0;
+ if let Ok(head) = NetworkHead::from_json_value(&head) {
+ if let NetworkHead::V2(ref head_v2) = head {
+ heads_count += 1;
+ assert_eq!(
+ head_v2.message.to_string(),
+ String::from("WS2POTMIC:HEAD:1:D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx:104512-0000051B9CE9C1CA89F269375A6751FB88B9E88DE47A36506057E5BFBCFBB276:c1c39a0a:duniter:1.6.21:3")
+ );
+ }
+ assert_eq!(head.verify(), true);
+ } else {
+ panic!("Fail to parse head !")
+ }
+ assert_eq!(heads_count, 1);
+ }
+}
diff --git a/lib/modules/ws2p-v1-legacy/ok_message.rs b/lib/modules/ws2p-v1-legacy/src/ok_message.rs
similarity index 59%
rename from lib/modules/ws2p-v1-legacy/ok_message.rs
rename to lib/modules/ws2p-v1-legacy/src/ok_message.rs
index 95a63c9dbae39afd26c44fb2919ebe1dbe12e67a..5d5660343ce6ac847fbf90d64f2fe75aa989ab5e 100644
--- a/lib/modules/ws2p-v1-legacy/ok_message.rs
+++ b/lib/modules/ws2p-v1-legacy/src/ok_message.rs
@@ -1,4 +1,4 @@
-use super::WS2PMessage;
+use crate::*;
use dup_crypto::keys::*;
use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -11,23 +11,18 @@ pub struct WS2POkMessageV1 {
}
impl WS2PMessage for WS2POkMessageV1 {
- fn parse(v: &serde_json::Value, currency: String) -> Option {
+ fn parse(v: &serde_json::Value, currency: String) -> Result {
let signature = match v.get("sig") {
- Some(signature) => signature
- .as_str()
- .expect("Parsing of OK message : fail to convert sig to str")
- .to_string(),
- None => return None,
+ Some(signature) => signature.as_str().ok_or(WS2PMsgParseErr {})?.to_string(),
+ None => return Err(WS2PMsgParseErr {}),
};
- let pubkey: PubKey = PubKey::Ed25519(
- ed25519::PublicKey::from_base58("969qRJs8KhsnkyzqarpL4RKZGMdVKNbZgu8fhsigM7Lj")
- .expect("fail to create default pubkey !"),
- );
- let signature: Option = Some(Sig::Ed25519(
- dup_crypto::keys::Signature::from_base64(&signature)
- .expect("fail to parse signature of OK message !"),
- ));
- Some(WS2POkMessageV1 {
+ let pubkey: PubKey = PubKey::Ed25519(ed25519::PublicKey::from_base58(
+ "969qRJs8KhsnkyzqarpL4RKZGMdVKNbZgu8fhsigM7Lj",
+ )?);
+ let signature: Option = Some(Sig::Ed25519(dup_crypto::keys::Signature::from_base64(
+ &signature,
+ )?));
+ Ok(WS2POkMessageV1 {
currency,
pubkey,
challenge: "".to_string(),
@@ -41,8 +36,11 @@ impl WS2PMessage for WS2POkMessageV1 {
)
}
fn verify(&self) -> bool {
- self.pubkey
- .verify(self.to_raw().as_bytes(), &self.signature.unwrap())
+ if let Some(sig) = self.signature {
+ self.pubkey.verify(self.to_raw().as_bytes(), &sig)
+ } else {
+ false
+ }
}
}
diff --git a/lib/modules/ws2p-v1-legacy/parsers/blocks.rs b/lib/modules/ws2p-v1-legacy/src/parsers/blocks.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/parsers/blocks.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/blocks.rs
diff --git a/lib/modules/ws2p-v1-legacy/parsers/excluded.rs b/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
similarity index 54%
rename from lib/modules/ws2p-v1-legacy/parsers/excluded.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
index 8e7dd84b6676ca6dae072635bdabd6a4a6e9cb18..aff225c31fa79fe7ef72c658b496973006f3d37d 100644
--- a/lib/modules/ws2p-v1-legacy/parsers/excluded.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/excluded.rs
@@ -1,13 +1,14 @@
use dup_crypto::keys::ed25519;
use dup_crypto::keys::*;
+use unwrap::unwrap;
pub fn parse_exclusions(json_datas: &str) -> Option> {
- let raw_exclusions: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+ let raw_exclusions: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
if raw_exclusions.is_array() {
- Some(parse_exclusions_from_json_value(
- raw_exclusions.as_array().unwrap(),
- ))
+ Some(parse_exclusions_from_json_value(unwrap!(
+ raw_exclusions.as_array()
+ )))
} else {
None
}
@@ -16,9 +17,9 @@ pub fn parse_exclusions(json_datas: &str) -> Option> {
pub fn parse_exclusions_from_json_value(array_exclusions: &[serde_json::Value]) -> Vec {
let mut exclusions: Vec = Vec::new();
for exclusion in array_exclusions.iter() {
- exclusions.push(PubKey::Ed25519(
- ed25519::PublicKey::from_base58(exclusion.as_str().unwrap()).unwrap(),
- ));
+ exclusions.push(PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ unwrap!(exclusion.as_str())
+ ))));
}
exclusions
}
diff --git a/lib/modules/ws2p-v1-legacy/parsers/identities.rs b/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
similarity index 78%
rename from lib/modules/ws2p-v1-legacy/parsers/identities.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
index 02aab9a9f82b9c130b5453e69fe3677ec5c3c7b4..254214a3fa58208c267ad0a57f527bbe11564045 100644
--- a/lib/modules/ws2p-v1-legacy/parsers/identities.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/identities.rs
@@ -2,6 +2,7 @@ use dubp_documents::documents::identity::*;
use dubp_documents::Blockstamp;
use dubp_documents::DocumentBuilder;
use dup_crypto::keys::*;
+use unwrap::unwrap;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum IdentityParseError {
@@ -9,10 +10,10 @@ pub enum IdentityParseError {
}
pub fn parse_identities(currency: &str, json_datas: &str) -> Option> {
- let raw_idties: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+ let raw_idties: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
if raw_idties.is_array() {
return Some(
- parse_identities_from_json_value(currency, raw_idties.as_array().unwrap())
+ parse_identities_from_json_value(currency, unwrap!(raw_idties.as_array()))
.iter()
.map(|i| {
i.clone()
@@ -31,18 +32,18 @@ pub fn parse_identities_from_json_value(
array_identities
.iter()
.map(|idty| {
- let idty_datas: Vec<&str> = idty.as_str().unwrap().split(':').collect();
+ let idty_datas: Vec<&str> = unwrap!(idty.as_str()).split(':').collect();
if idty_datas.len() == 4 {
let idty_doc_builder = IdentityDocumentBuilder {
currency,
- issuer: &PubKey::Ed25519(
- ed25519::PublicKey::from_base58(idty_datas[0]).unwrap(),
- ),
- blockstamp: &Blockstamp::from_string(idty_datas[2]).unwrap(),
+ issuer: &PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ idty_datas[0]
+ ))),
+ blockstamp: &unwrap!(Blockstamp::from_string(idty_datas[2])),
username: idty_datas[3],
};
let idty_sig =
- Sig::Ed25519(ed25519::Signature::from_base64(idty_datas[1]).unwrap());
+ Sig::Ed25519(unwrap!(ed25519::Signature::from_base64(idty_datas[1])));
//memberships.push(membership_doc_builder.build_with_signature(vec![membership_sig]));
Ok(idty_doc_builder.build_with_signature(vec![idty_sig]))
} else {
@@ -57,7 +58,7 @@ pub fn parse_compact_identity(
source: &serde_json::Value,
) -> Option {
if source.is_string() {
- let idty_elements: Vec<&str> = source.as_str().unwrap().split(':').collect();
+ let idty_elements: Vec<&str> = unwrap!(source.as_str()).split(':').collect();
let issuer = match ed25519::PublicKey::from_base58(idty_elements[0]) {
Ok(pubkey) => PubKey::Ed25519(pubkey),
Err(_) => return None,
diff --git a/lib/modules/ws2p-v1-legacy/parsers/memberships.rs b/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
similarity index 68%
rename from lib/modules/ws2p-v1-legacy/parsers/memberships.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
index a04d2d99b24ae6b7951322c8609fbc458b4d21b1..3fb2cf2a9b6e7d9724ec71588ffe6cd5305ea8c1 100644
--- a/lib/modules/ws2p-v1-legacy/parsers/memberships.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/memberships.rs
@@ -2,6 +2,7 @@ use dubp_documents::documents::membership::*;
use dubp_documents::Blockstamp;
use dubp_documents::DocumentBuilder;
use dup_crypto::keys::*;
+use unwrap::unwrap;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MembershipParseError {
@@ -13,13 +14,13 @@ pub fn parse_memberships(
membership_type: MembershipType,
json_datas: &str,
) -> Option> {
- let raw_memberships: serde_json::Value = serde_json::from_str(json_datas).unwrap();
+ let raw_memberships: serde_json::Value = unwrap!(serde_json::from_str(json_datas));
if raw_memberships.is_array() {
return Some(
parse_memberships_from_json_value(
currency,
membership_type,
- raw_memberships.as_array().unwrap(),
+ unwrap!(raw_memberships.as_array()),
)
.iter()
.map(|m| {
@@ -41,20 +42,21 @@ pub fn parse_memberships_from_json_value(
array_memberships
.iter()
.map(|membership| {
- let membership_datas: Vec<&str> = membership.as_str().unwrap().split(':').collect();
+ let membership_datas: Vec<&str> = unwrap!(membership.as_str()).split(':').collect();
if membership_datas.len() == 5 {
let membership_doc_builder = MembershipDocumentBuilder {
currency,
- issuer: &PubKey::Ed25519(
- ed25519::PublicKey::from_base58(membership_datas[0]).unwrap(),
- ),
- blockstamp: &Blockstamp::from_string(membership_datas[2]).unwrap(),
+ issuer: &PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ membership_datas[0]
+ ))),
+ blockstamp: &unwrap!(Blockstamp::from_string(membership_datas[2])),
membership: membership_type,
identity_username: membership_datas[4],
- identity_blockstamp: &Blockstamp::from_string(membership_datas[3]).unwrap(),
+ identity_blockstamp: &unwrap!(Blockstamp::from_string(membership_datas[3])),
};
- let membership_sig =
- Sig::Ed25519(ed25519::Signature::from_base64(membership_datas[1]).unwrap());
+ let membership_sig = Sig::Ed25519(unwrap!(ed25519::Signature::from_base64(
+ membership_datas[1]
+ )));
Ok(membership_doc_builder.build_with_signature(vec![membership_sig]))
} else {
Err(MembershipParseError::WrongFormat())
diff --git a/lib/modules/ws2p-v1-legacy/parsers/mod.rs b/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
similarity index 74%
rename from lib/modules/ws2p-v1-legacy/parsers/mod.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
index ca9a42a80f33ac97d570c0caeb1eeb1d33b14022..7c9c1edc3c5ea907901cef92df3c89ba288a5628 100644
--- a/lib/modules/ws2p-v1-legacy/parsers/mod.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/mod.rs
@@ -27,6 +27,7 @@ mod tests {
use dubp_documents::DocumentBuilder;
use dup_crypto::keys::*;
use std::str::FromStr;
+ use unwrap::unwrap;
#[test]
fn parse_json_tx() {
@@ -57,28 +58,24 @@ mod tests {
let tx_builder = TransactionDocumentBuilder {
currency: "g1",
- blockstamp: &Blockstamp::from_string(
+ blockstamp: &unwrap!(Blockstamp::from_string(
"112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
- )
- .unwrap(),
+ )),
locktime: &0,
- issuers: &vec![PubKey::Ed25519(
- ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
- .unwrap(),
- )],
- inputs: &vec![TransactionInput::from_str(
+ issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2"
+ )))],
+ inputs: &vec![unwrap!(TransactionInput::from_str(
"1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
- )
- .unwrap()],
- outputs: &vec![TransactionOutput::from_str(
+ ))],
+ outputs: &vec![unwrap!(TransactionOutput::from_str(
"1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
- )
- .unwrap()],
- unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+ ))],
+ unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
comment: "Merci pour la calligraphie ;) de Liam",
hash: None,
};
- let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(ed25519::Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==").unwrap())]);
+ let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(unwrap!(ed25519::Signature::from_base64("5olrjFylTCsVq8I5Yr7FpXeviynICyvIwe1yG5N0RJF+VZb+bCFBnLAMpmMCU2qzUvK7z41UXOrMRybXiLa2Dw==")))]);
tx_doc.compute_hash();
assert_eq!(
parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
@@ -116,32 +113,29 @@ mod tests {
let tx_builder = TransactionDocumentBuilder {
currency: "g1",
- blockstamp: &Blockstamp::from_string(
+ blockstamp: &unwrap!(Blockstamp::from_string(
"58-00005B9167EBA1E32C6EAD42AE7F72D8F14B765D3C9E47D233B553D47C5AEE0C",
- )
- .unwrap(),
+ )),
locktime: &0,
- issuers: &vec![PubKey::Ed25519(
- ed25519::PublicKey::from_base58("FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD")
- .unwrap(),
- )],
- inputs: &vec![TransactionInput::from_str(
+ issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD"
+ )))],
+ inputs: &vec![unwrap!(TransactionInput::from_str(
"1000:0:D:FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD:1",
- )
- .unwrap()],
+ ))],
outputs: &vec![
- TransactionOutput::from_str("3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)")
- .unwrap(),
- TransactionOutput::from_str(
+ unwrap!(TransactionOutput::from_str(
+ "3:0:SIG(7vU9BMDhN6fBuRa2iK3JRbC6pqQKb4qDMGsFcQuT5cz)"
+ )),
+ unwrap!(TransactionOutput::from_str(
"997:0:SIG(FVUFRrk1K5TQGsY7PRLwqHgdHRoHrwb1hcucp4C2N5tD)",
- )
- .unwrap(),
+ )),
],
- unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+ unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
comment: "Un petit cafe ;-)",
hash: None,
};
- let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(ed25519::Signature::from_base64("VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg==").unwrap())]);
+ let mut tx_doc = tx_builder.build_with_signature(vec![Sig::Ed25519(unwrap!(ed25519::Signature::from_base64("VWbvsiybM4L2X5+o+6lIiuKNw5KrD1yGZqmV+lHtA28XoRUFzochSIgfoUqBsTAaYEHY45vSX917LDXudTEzBg==")))]);
tx_doc.compute_hash();
assert_eq!(
parse_transaction("g1", &tx_json).expect("Fail to parse transaction !"),
diff --git a/lib/modules/ws2p-v1-legacy/parsers/transactions.rs b/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
similarity index 88%
rename from lib/modules/ws2p-v1-legacy/parsers/transactions.rs
rename to lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
index f979aa73d19353710d94f0dd884a3aba18edb951..5beacc276a4c13908d207a57cd5c480ef3b045a4 100644
--- a/lib/modules/ws2p-v1-legacy/parsers/transactions.rs
+++ b/lib/modules/ws2p-v1-legacy/src/parsers/transactions.rs
@@ -96,6 +96,7 @@ pub fn parse_transaction(
#[cfg(test)]
mod tests {
use super::*;
+ use unwrap::unwrap;
#[test]
fn parse_compact_tx() {
@@ -110,24 +111,20 @@ Merci pour la calligraphie ;) de Liam$\
let _tx_builder = TransactionDocumentBuilder {
currency: "g1",
- blockstamp: &Blockstamp::from_string(
+ blockstamp: &unwrap!(Blockstamp::from_string(
"112533-000002150F2E805E604D9B31212D079570AAD8D3A4D8BB75F2C15A94A345B6B1",
- )
- .unwrap(),
+ )),
locktime: &0,
- issuers: &vec![PubKey::Ed25519(
- ed25519::PublicKey::from_base58("51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2")
- .unwrap(),
- )],
- inputs: &vec![TransactionInput::from_str(
+ issuers: &vec![PubKey::Ed25519(unwrap!(ed25519::PublicKey::from_base58(
+ "51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2"
+ )))],
+ inputs: &vec![unwrap!(TransactionInput::from_str(
"1000:0:D:51EFVNZwpfmTXU7BSLpeh3PZFgfdmm5hq5MzCDopdH2:46496",
- )
- .unwrap()],
- outputs: &vec![TransactionOutput::from_str(
+ ))],
+ outputs: &vec![unwrap!(TransactionOutput::from_str(
"1000:0:SIG(2yN8BRSkARcqE8NCxKMBiHfTpx1EvwULFn56Myf6qRmy)",
- )
- .unwrap()],
- unlocks: &vec![TransactionInputUnlocks::from_str("0:SIG(0)").unwrap()],
+ ))],
+ unlocks: &vec![unwrap!(TransactionInputUnlocks::from_str("0:SIG(0)"))],
comment: "Merci pour la calligraphie ;) de Liam",
hash: None,
};
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/mod.rs b/lib/modules/ws2p-v1-legacy/src/requests/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f245617818e5144e6abe8e56576027bdb39bf901
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/mod.rs
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules requests sent and received.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/received.rs b/lib/modules/ws2p-v1-legacy/src/requests/received.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab9c2d0edc5c53e7a071b1a3b706078a9e832435
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/received.rs
@@ -0,0 +1,66 @@
+// Copyright (C) 2018 The Duniter Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules requests received.
+
+use crate::ws2p_db::DbEndpoint;
+use crate::ws_connections::states::WS2PConnectionState;
+use crate::WS2PModule;
+use duniter_network::requests::OldNetworkRequest;
+use durs_message::requests::DursReqContent;
+
+pub fn receive_req(ws2p_module: &mut WS2PModule, req_content: &DursReqContent) {
+ if let DursReqContent::OldNetworkRequest(ref old_net_request) = *req_content {
+ match *old_net_request {
+ OldNetworkRequest::GetBlocks(ref req_id, ref count, ref from) => {
+ let mut receiver_index = 0;
+ let mut real_receiver = None;
+ for (ws2p_full_id, DbEndpoint { state, .. }) in ws2p_module.ws2p_endpoints.clone() {
+ if let WS2PConnectionState::Established = state {
+ if receiver_index == ws2p_module.next_receiver {
+ real_receiver = Some(ws2p_full_id);
+ break;
+ }
+ receiver_index += 1;
+ }
+ }
+ if real_receiver.is_none() {
+ ws2p_module.next_receiver = 0;
+ for (ws2p_full_id, DbEndpoint { state, .. }) in &ws2p_module.ws2p_endpoints {
+ if let WS2PConnectionState::Established = *state {
+ real_receiver = Some(*ws2p_full_id);
+ break;
+ }
+ }
+ } else {
+ ws2p_module.next_receiver += 1;
+ }
+ if let Some(real_receiver) = real_receiver {
+ debug!("WS2P: send req to: ({:?})", real_receiver);
+ let _blocks_request_result =
+ crate::ws_connections::requests::sent::send_request_to_specific_node(
+ ws2p_module,
+ &real_receiver,
+ &OldNetworkRequest::GetBlocks(*req_id, *count, *from),
+ );
+ } else {
+ warn!("WS2P: not found peer to send request !");
+ }
+ }
+ OldNetworkRequest::GetEndpoints(ref _request) => {}
+ _ => {}
+ }
+ }
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/requests/sent.rs b/lib/modules/ws2p-v1-legacy/src/requests/sent.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e07093a98f866de4c6a000d15d6f033bd99c1c08
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/requests/sent.rs
@@ -0,0 +1,37 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules requests sent.
+
+use crate::WS2PModule;
+use duniter_module::{DursModule, ModuleReqId, ModuleRole, RouterThreadMessage};
+use durs_message::requests::{BlockchainRequest, DursReqContent};
+use durs_message::*;
+
+pub fn send_dal_request(ws2p_module: &mut WS2PModule, req: &BlockchainRequest) {
+ ws2p_module.count_dal_requests += 1;
+ if ws2p_module.count_dal_requests == std::u32::MAX {
+ ws2p_module.count_dal_requests = 0;
+ }
+ ws2p_module
+ .router_sender
+ .send(RouterThreadMessage::ModuleMessage(DursMsg::Request {
+ req_from: WS2PModule::name(),
+ req_to: ModuleRole::BlockchainDatas,
+ req_id: ModuleReqId(ws2p_module.count_dal_requests),
+ req_content: DursReqContent::BlockchainRequest(req.clone()),
+ }))
+ .expect("Fail to send message to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/mod.rs b/lib/modules/ws2p-v1-legacy/src/responses/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..516f7af7e549f4127da05b1b019695a6c127e704
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/mod.rs
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules responses sent and received.
+
+pub mod received;
+pub mod sent;
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/received.rs b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
new file mode 100644
index 0000000000000000000000000000000000000000..64e0f4874ad6423479942df4288f3653b6ee8227
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/received.rs
@@ -0,0 +1,16 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules responses received.
diff --git a/lib/modules/ws2p-v1-legacy/src/responses/sent.rs b/lib/modules/ws2p-v1-legacy/src/responses/sent.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f102489cbd94ef75a7846a9c122f1e56cfa98e51
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/responses/sent.rs
@@ -0,0 +1,36 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Sub-module managing the inter-modules responses sent.
+
+use crate::*;
+use durs_message::*;
+
+pub fn send_network_req_response(
+ ws2p_module: &WS2PModule,
+ requester: ModuleStaticName,
+ req_id: ModuleReqId,
+ response: NetworkResponse,
+) {
+ ws2p_module
+ .router_sender
+ .send(RouterThreadMessage::ModuleMessage(DursMsg::Response {
+ res_from: WS2PModule::name(),
+ res_to: requester,
+ req_id,
+ res_content: DursResContent::NetworkResponse(response),
+ }))
+ .expect("Fail to send message to router !");
+}
diff --git a/lib/modules/ws2p-v1-legacy/serializer.rs b/lib/modules/ws2p-v1-legacy/src/serializer.rs
similarity index 100%
rename from lib/modules/ws2p-v1-legacy/serializer.rs
rename to lib/modules/ws2p-v1-legacy/src/serializer.rs
diff --git a/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs b/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0b09fb1f1c79e29d91d712f66b9c5ea20d47062c
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws2p_db.rs
@@ -0,0 +1,97 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! Manage WS2Pv1 storage.
+
+use crate::ws_connections::states::WS2PConnectionState;
+use durs_network_documents::network_endpoint::EndpointV1;
+use durs_network_documents::NodeFullId;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+use std::fs::File;
+use std::path::Path;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum EndpointApi {
+ WS2P,
+ //WS2PS,
+ //WS2PTOR,
+ //DASA,
+ //BMA,
+ //BMAS,
+}
+
+pub fn string_to_api(api: &str) -> Option {
+ match api {
+ "WS2P" => Some(EndpointApi::WS2P),
+ //"WS2PS" => Some(EndpointApi::WS2PS),
+ //"WS2PTOR" => Some(EndpointApi::WS2PTOR),
+ //"DASA" => Some(EndpointApi::DASA),
+ //"BASIC_MERKLED_API" => Some(EndpointApi::BMA),
+ //"BMAS" => Some(EndpointApi::BMAS),
+ &_ => None,
+ }
+}
+
+#[derive(Debug)]
+pub enum Ws2pPeersDbError {
+ IoErr(std::io::Error),
+ SerdeErr(bincode::Error),
+}
+
+impl From for Ws2pPeersDbError {
+ fn from(e: std::io::Error) -> Self {
+ Ws2pPeersDbError::IoErr(e)
+ }
+}
+
+impl From for Ws2pPeersDbError {
+ fn from(e: bincode::Error) -> Self {
+ Ws2pPeersDbError::SerdeErr(e)
+ }
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct DbEndpoint {
+ pub ep: EndpointV1,
+ pub state: WS2PConnectionState,
+ pub last_check: u64,
+}
+
+pub fn get_endpoints(
+ file_path: &Path,
+) -> Result, Ws2pPeersDbError> {
+ if file_path.exists() {
+ let bin_endpoints = durs_common_tools::read_bin_file(file_path)?;
+ if bin_endpoints.is_empty() {
+ Ok(HashMap::new())
+ } else {
+ Ok(bincode::deserialize(&bin_endpoints[..])?)
+ }
+ } else {
+ File::create(file_path)?;
+ Ok(HashMap::new())
+ }
+}
+
+pub fn write_endpoints(
+ file_path: &Path,
+ endpoints: &HashMap,
+) -> Result<(), Ws2pPeersDbError> {
+ let bin_endpoints = bincode::serialize(&endpoints)?;
+ durs_common_tools::write_bin_file(file_path, &bin_endpoints)?;
+
+ Ok(())
+}
diff --git a/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d53b59eab09adab0ed3fc7be570f24c68b429875
--- /dev/null
+++ b/lib/modules/ws2p-v1-legacy/src/ws_connections/handler.rs
@@ -0,0 +1,241 @@
+// Copyright (C) 2018 The Durs Project Developers.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+//! WS2P connections handler.
+
+use super::messages::*;
+use super::meta_datas::WS2PConnectionMetaDatas;
+use super::states::WS2PConnectionState;
+use crate::constants::*;
+use crate::*;
+use dup_crypto::keys::*;
+use std::sync::mpsc;
+#[allow(deprecated)]
+use ws::util::{Timeout, Token};
+use ws::{CloseCode, Frame, Handler, Handshake, Message, Sender};
+
+const CONNECT: Token = Token(1);
+const EXPIRE: Token = Token(2);
+
+// Our Handler struct.
+// Here we explicity indicate that the Client needs a Sender,
+// whereas a closure captures the Sender for us automatically.
+#[allow(deprecated)]
+#[derive(Debug)]
+pub struct Client {
+ ws: Sender,
+ conductor_sender: mpsc::Sender,
+ currency: String,
+ key_pair: KeyPairEnum,
+ connect_message: Message,
+ conn_meta_datas: WS2PConnectionMetaDatas,
+ last_mess_time: SystemTime,
+ spam_interval: bool,
+ spam_counter: usize,
+ timeout: Option,
+}
+
+pub fn connect_to_ws2p_endpoint(
+ endpoint: &EndpointV1,
+ conductor_sender: &mpsc::Sender,
+ currency: &str,
+ key_pair: KeyPairEnum,
+) -> ws::Result<()> {
+ // Get endpoint url
+ let ws_url = endpoint.get_url(true, false).expect("Endpoint unreachable");
+
+ // Create WS2PConnectionMetaDatass
+ let mut conn_meta_datas = WS2PConnectionMetaDatas::new(
+ "b60a14fd-0826-4ae0-83eb-1a92cd59fd5308535fd3-78f2-4678-9315-cd6e3b7871b1".to_string(),
+ );
+ conn_meta_datas.remote_pubkey = Some(endpoint.issuer);
+ conn_meta_datas.remote_uuid = Some(
+ endpoint
+ .node_id
+ .expect("WS2P: Fail to get ep.node_uuid() !"),
+ );
+
+ // Generate connect message
+ let connect_message =
+ generate_connect_message(currency, key_pair, conn_meta_datas.challenge.clone());
+
+ // Log
+ info!("WS2P: Try connection to {} ...", ws_url);
+
+ // Connect to websocket
+ ws::connect(ws_url, |ws| Client {
+ ws,
+ conductor_sender: conductor_sender.clone(),
+ currency: String::from(currency),
+ key_pair,
+ connect_message: connect_message.clone(),
+ conn_meta_datas: conn_meta_datas.clone(),
+ last_mess_time: SystemTime::now(),
+ spam_interval: false,
+ spam_counter: 0,
+ timeout: None,
+ })
+}
+
+// We implement the Handler trait for Client so that we can get more
+// fine-grained control of the connection.
+impl Handler for Client {
+ // `on_open` will be called only after the WebSocket handshake is successful
+ // so at this point we know that the connection is ready to send/receive messages.
+ // We ignore the `Handshake` for now, but you could also use this method to setup
+ // Handler state or reject the connection based on the details of the Request
+ // or Response, such as by checking cookies or Auth headers.
+ fn on_open(&mut self, _: Handshake) -> ws::Result<()> {
+ // Define timeouts
+ self.ws.timeout(WS2P_NEGOTIATION_TIMEOUT * 1_000, CONNECT)?;
+ self.ws.timeout(WS2P_EXPIRE_TIMEOUT * 1_000, EXPIRE)?;
+ // Send ws::Sender to WS2PConductor
+ let result = self
+ .conductor_sender
+ .send(WS2PThreadSignal::WS2PConnectionMessage(
+ WS2PConnectionMessage(
+ self.conn_meta_datas.node_full_id(),
+ WS2PConnectionMessagePayload::WebsocketOk(WsSender(self.ws.clone())),
+ ),
+ ));
+ // If WS2PConductor is unrechable, close connection.
+ if result.is_err() {
+ debug!("Close ws2p connection because ws2p main thread is unrechable !");
+ self.ws.close(CloseCode::Normal)
+ } else {
+ // Send CONNECT Message
+ self.ws.send(self.connect_message.clone())
+ }
+ }
+
+ // `on_message` is roughly equivalent to the Handler closure. It takes a `Message`
+ // and returns a `Result<()>`.
+ fn on_message(&mut self, msg: Message) -> ws::Result<()> {
+ // Spam ?
+ if unwrap!(SystemTime::now().duration_since(self.last_mess_time))
+ > Duration::new(*WS2P_SPAM_INTERVAL_IN_MILLI_SECS, 0)
+ {
+ if self.spam_interval {
+ self.spam_counter += 1;
+ } else {
+ self.spam_interval = true;
+ self.spam_counter = 2;
+ }
+ } else {
+ self.spam_interval = false;
+ self.spam_counter = 0;
+ }
+ // Spam ?
+ if self.spam_counter >= *WS2P_SPAM_LIMIT {
+ thread::sleep(Duration::from_millis(*WS2P_SPAM_SLEEP_TIME_IN_SEC));
+ self.last_mess_time = SystemTime::now();
+ return Ok(());
+ }
+ self.last_mess_time = SystemTime::now();
+
+ // Parse and check incoming message
+ if msg.is_text() {
+ let s: String = msg
+ .into_text()
+ .expect("WS2P: Fail to convert message payload to String !");
+ trace!("WS2P: receive mess: {}", s);
+ let json_message: serde_json::Value = serde_json::from_str(&s)
+ .expect("WS2P: Fail to convert string message ton json value !");
+ let result = self
+ .conductor_sender
+ .send(WS2PThreadSignal::WS2PConnectionMessage(
+ WS2PConnectionMessage(
+ self.conn_meta_datas.node_full_id(),
+ self.conn_meta_datas.parse_and_check_incoming_message(
+ &self.currency,
+ self.key_pair,
+ &json_message,
+ ),
+ ),
+ ));
+ if result.is_err() {
+ info!("Close ws2p connection because ws2p main thread is unrechable !");
+ self.ws.close(CloseCode::Normal)?;
+ }
+ }
+ Ok(())
+ }
+ fn on_timeout(&mut self, event: Token) -> ws::Result<()> {
+ match event {
+ CONNECT => {
+ if self.conn_meta_datas.state != WS2PConnectionState::Established {
+ let _result =
+ self.conductor_sender
+ .send(WS2PThreadSignal::WS2PConnectionMessage(
+ WS2PConnectionMessage(
+ self.conn_meta_datas.node_full_id(),
+ WS2PConnectionMessagePayload::NegociationTimeout,
+ ),
+ ));
+ self.ws.close(CloseCode::Away)
+ } else {
+ Ok(())
+ }
+ }
+ EXPIRE => {
+ let _result = self
+ .conductor_sender
+ .send(WS2PThreadSignal::WS2PConnectionMessage(
+ WS2PConnectionMessage(
+ self.conn_meta_datas.node_full_id(),
+ WS2PConnectionMessagePayload::Timeout,
+ ),
+ ));
+ self.ws.close(CloseCode::Away)
+ }
+ _ => Ok(()),
+ }
+ }
+ #[allow(deprecated)]
+ fn on_new_timeout(&mut self, event: Token, timeout: Timeout) -> ws::Result<()> {
+ if event == EXPIRE {
+ if let Some(t) = self.timeout.take() {
+ self.ws.cancel(t)?;
+ }
+ self.timeout = Some(timeout)
+ }
+ Ok(())
+ }
+ fn on_frame(&mut self, frame: Frame) -> ws::Result