diff --git a/Cargo.lock b/Cargo.lock index c10d04a25..02a220349 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2208,7 +2208,7 @@ dependencies = [ [[package]] name = "darkirc" -version = "0.5.0" +version = "0.5.1" dependencies = [ "async-trait", "bcrypt", @@ -7091,7 +7091,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "taud" -version = "0.4.1" +version = "0.4.2" dependencies = [ "async-trait", "blake3 1.5.4", diff --git a/bin/darkirc/Cargo.toml b/bin/darkirc/Cargo.toml index b02e5754d..bbe871243 100644 --- a/bin/darkirc/Cargo.toml +++ b/bin/darkirc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "darkirc" description = "P2P IRC daemon" -version = "0.5.0" +version = "0.5.1" edition = "2021" authors = ["Dyne.org foundation "] license = "AGPL-3.0-only" diff --git a/bin/darkirc/src/irc/client.rs b/bin/darkirc/src/irc/client.rs index d54621427..a994c3d49 100644 --- a/bin/darkirc/src/irc/client.rs +++ b/bin/darkirc/src/irc/client.rs @@ -190,7 +190,30 @@ impl Client { } // Otherwise, broadcast it - self.server.darkirc.p2p.broadcast(&EventPut(event)).await; + let self_version = self.server.darkirc.p2p.settings().read().await.app_version.clone(); + let connected_peers = self.server.darkirc.p2p.hosts().peers(); + let mut peers_with_matched_version = vec![]; + let mut peers_with_different_version = vec![]; + for peer in connected_peers { + let peer_version = peer.version.lock().await.clone(); + if let Some(ref peer_version) = peer_version { + if self_version == peer_version.version { + peers_with_matched_version.push(peer) + } else { + peers_with_different_version.push(peer) + } + } + } + + if !peers_with_matched_version.is_empty() { + self.server.darkirc.p2p.broadcast_to(&EventPut(event.clone()), &peers_with_matched_version).await; + } + if !peers_with_different_version.is_empty() { + let mut event = event; + event.timestamp /= 1000; + self.server.darkirc.p2p.broadcast_to(&EventPut(event), &peers_with_different_version).await; + } + // self.server.darkirc.p2p.broadcast(&EventPut(event)).await; } } } diff --git a/bin/tau/taud/Cargo.toml b/bin/tau/taud/Cargo.toml index e6f8ee6ee..71d231dc1 100644 --- a/bin/tau/taud/Cargo.toml +++ b/bin/tau/taud/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "taud" description = "Encrypted tasks management app using peer-to-peer network and Event Graph." -version = "0.4.1" +version = "0.4.2" edition = "2021" authors = ["Dyne.org foundation "] license = "AGPL-3.0-only" diff --git a/bin/tau/taud/src/main.rs b/bin/tau/taud/src/main.rs index c05d4349d..1d4fd43ba 100644 --- a/bin/tau/taud/src/main.rs +++ b/bin/tau/taud/src/main.rs @@ -318,7 +318,30 @@ async fn start_sync_loop( error!(target: "taud", "Failed inserting new event to DAG: {}", e); } else { // Otherwise, broadcast it - p2p.broadcast(&EventPut(event)).await; + let self_version = p2p.settings().read().await.app_version.clone(); + let connected_peers = p2p.hosts().peers(); + let mut peers_with_matched_version = vec![]; + let mut peers_with_different_version = vec![]; + for peer in connected_peers { + let peer_version = peer.version.lock().await.clone(); + if let Some(ref peer_version) = peer_version { + if self_version == peer_version.version { + peers_with_matched_version.push(peer) + } else { + peers_with_different_version.push(peer) + } + } + } + + if !peers_with_matched_version.is_empty() { + p2p.broadcast_to(&EventPut(event.clone()), &peers_with_matched_version).await; + } + if !peers_with_different_version.is_empty() { + let mut event = event; + event.timestamp /= 1000; + p2p.broadcast_to(&EventPut(event), &peers_with_different_version).await; + } + // p2p.broadcast(&EventPut(event)).await; } } } diff --git a/src/event_graph/event.rs b/src/event_graph/event.rs index 5de355ad3..677d83eb2 100644 --- a/src/event_graph/event.rs +++ b/src/event_graph/event.rs @@ -49,13 +49,20 @@ impl Event { /// of the codebase. pub async fn new(data: Vec, event_graph: &EventGraph) -> Self { let (layer, parents) = event_graph.get_next_layer_with_parents().await; - Self { timestamp: UNIX_EPOCH.elapsed().unwrap().as_secs(), content: data, parents, layer } + Self { + timestamp: UNIX_EPOCH.elapsed().unwrap().as_millis() as u64, + content: data, + parents, + layer, + } } /// Hash the [`Event`] to retrieve its ID pub fn id(&self) -> blake3::Hash { let mut hasher = blake3::Hasher::new(); - self.timestamp.encode(&mut hasher).unwrap(); + let timestamp = + if self.timestamp > 1e10 as u64 { self.timestamp / 1000 } else { self.timestamp }; + timestamp.encode(&mut hasher).unwrap(); self.content.encode(&mut hasher).unwrap(); self.parents.encode(&mut hasher).unwrap(); self.layer.encode(&mut hasher).unwrap(); @@ -91,7 +98,7 @@ impl Event { } // Check if the event timestamp is after genesis timestamp - if self.timestamp < genesis_timestamp - EVENT_TIME_DRIFT { + if self.timestamp < genesis_timestamp - EVENT_TIME_DRIFT / 1000 { return Ok(false) } @@ -99,7 +106,7 @@ impl Event { // is after the next genesis timestamp if days_rotation > 0 { let next_genesis_timestamp = next_rotation_timestamp(INITIAL_GENESIS, days_rotation); - if self.timestamp > next_genesis_timestamp + EVENT_TIME_DRIFT { + if self.timestamp > next_genesis_timestamp + EVENT_TIME_DRIFT / 1000 { return Ok(false) } } @@ -159,19 +166,28 @@ impl Event { /// assuming some possibility for a time drift. /// Note: This validation does *NOT* check for recursive references(circles), /// and should be used as a first quick check. - pub fn validate_new(&self) -> bool { + pub fn validate_new(&self, is_ver_match: bool) -> bool { // Let's not bother with empty events if self.content.is_empty() { return false } - // Check if the event is too old or too new - let now = UNIX_EPOCH.elapsed().unwrap().as_secs(); - let too_old = self.timestamp < now - EVENT_TIME_DRIFT; - let too_new = self.timestamp > now + EVENT_TIME_DRIFT; - - if too_old || too_new { - return false + if is_ver_match { + // Check if the event is too old or too new + let now = UNIX_EPOCH.elapsed().unwrap().as_millis() as u64; + let too_old = self.timestamp < now - EVENT_TIME_DRIFT; + let too_new = self.timestamp > now + EVENT_TIME_DRIFT; + if too_old || too_new { + return false + } + } else { + // Check if the event is too old or too new + let now = UNIX_EPOCH.elapsed().unwrap().as_secs(); + let too_old = self.timestamp < (now - (EVENT_TIME_DRIFT / 1000)); + let too_new = self.timestamp > (now + (EVENT_TIME_DRIFT / 1000)); + if too_old || too_new { + return false + } } // Validate the parents. We have to check that at least one parent diff --git a/src/event_graph/mod.rs b/src/event_graph/mod.rs index ceb7e309b..515711fad 100644 --- a/src/event_graph/mod.rs +++ b/src/event_graph/mod.rs @@ -35,7 +35,7 @@ use tinyjson::JsonValue::{self}; use crate::{ event_graph::util::{replayer_log, seconds_until_next_rotation}, - net::P2pPtr, + net::{channel::Channel, P2pPtr}, rpc::{ jsonrpc::{JsonResponse, JsonResult}, util::json_map, @@ -66,16 +66,16 @@ use deg::DegEvent; #[cfg(test)] mod tests; -/// Initial genesis timestamp (07 Sep 2023, 00:00:00 UTC) +/// Initial genesis timestamp in millis (07 Sep 2023, 00:00:00 UTC) /// Must always be UTC midnight. -const INITIAL_GENESIS: u64 = 1694044800; +const INITIAL_GENESIS: u64 = 1_694_044_800_000; /// Genesis event contents const GENESIS_CONTENTS: &[u8] = &[0x47, 0x45, 0x4e, 0x45, 0x53, 0x49, 0x53]; /// The number of parents an event is supposed to have. const N_EVENT_PARENTS: usize = 5; -/// Allowed timestamp drift in seconds -const EVENT_TIME_DRIFT: u64 = 60; +/// Allowed timestamp drift in milliseconds +const EVENT_TIME_DRIFT: u64 = 60_000; /// Null event ID pub const NULL_ID: blake3::Hash = blake3::Hash::from_bytes([0x00; blake3::OUT_LEN]); @@ -872,4 +872,18 @@ impl EventGraph { Ok(result) } + + /// Check if the our version matches the connected peer's + /// return true if they are, false otherwise + async fn check_version_match(&self, channel: &Arc) -> bool { + let self_version = self.p2p.settings().read().await.app_version.clone(); + let peer_version = channel.version.lock().await.clone(); + if let Some(ref peer_version) = peer_version { + if self_version == peer_version.version { + return true + } + } + + false + } } diff --git a/src/event_graph/proto.rs b/src/event_graph/proto.rs index d544e2db4..e698e0cb6 100644 --- a/src/event_graph/proto.rs +++ b/src/event_graph/proto.rs @@ -203,7 +203,8 @@ impl ProtocolEventGraph { // Validate the new event first. If we do not consider it valid, we // will just drop it and stay quiet. If the malicious threshold // is reached, we will stop the connection. - if !event.validate_new() { + let is_ver_match = self.event_graph.check_version_match(&self.channel).await; + if !event.validate_new(is_ver_match) { self.clone().increase_malicious_count().await?; continue } diff --git a/src/event_graph/util.rs b/src/event_graph/util.rs index 96236be51..d23051b5f 100644 --- a/src/event_graph/util.rs +++ b/src/event_graph/util.rs @@ -39,14 +39,14 @@ use crate::{ Result, }; -/// Seconds in a day -pub(super) const DAY: i64 = 86400; +/// MilliSeconds in a day +pub(super) const DAY: i64 = 86_400_000; /// Calculate the midnight timestamp given a number of days. /// If `days` is 0, calculate the midnight timestamp of today. pub(super) fn midnight_timestamp(days: i64) -> u64 { // Get current time - let now = UNIX_EPOCH.elapsed().unwrap().as_secs() as i64; + let now = UNIX_EPOCH.elapsed().unwrap().as_millis() as i64; // Find the timestamp for the midnight of the current day let cur_midnight = (now / DAY) * DAY; @@ -58,7 +58,7 @@ pub(super) fn midnight_timestamp(days: i64) -> u64 { /// Calculate the number of days since a given midnight timestamp. pub(super) fn days_since(midnight_ts: u64) -> u64 { // Get current time - let now = UNIX_EPOCH.elapsed().unwrap().as_secs(); + let now = UNIX_EPOCH.elapsed().unwrap().as_millis() as u64; // Calculate the difference between the current timestamp // and the given midnight timestamp @@ -96,14 +96,14 @@ pub(super) fn next_rotation_timestamp(starting_timestamp: u64, rotation_period: midnight_timestamp(days_until_next_rotation) } -/// Calculate the time in seconds until the next_rotation, given +/// Calculate the time in milliseconds until the next_rotation, given /// as a timestamp. /// `next_rotation` here represents a timestamp in UNIX epoch format. pub(super) fn seconds_until_next_rotation(next_rotation: u64) -> u64 { // Store `now` in a variable in order to avoid a TOCTOU error. // There may be a drift of one second between this panic check and // the return value if we get unlucky. - let now = UNIX_EPOCH.elapsed().unwrap().as_secs(); + let now = UNIX_EPOCH.elapsed().unwrap().as_millis() as u64; if next_rotation < now { panic!("Next rotation timestamp is in the past"); } @@ -126,7 +126,7 @@ pub(super) fn generate_genesis(days_rotation: u64) -> Event { INITIAL_GENESIS + (rotations_since_genesis * days_rotation * DAY as u64) }; Event { - timestamp, + timestamp: timestamp / 1000, // to keep the genesis hash equal to old nodes. content: GENESIS_CONTENTS.to_vec(), parents: [NULL_ID; N_EVENT_PARENTS], layer: 0, @@ -225,7 +225,7 @@ mod tests { // we should get tomorrow's timestamp. // This is a special case. let midnight_today: u64 = midnight_timestamp(0); - let midnight_tomorrow = midnight_today + 86400u64; // add a day, in seconds + let midnight_tomorrow = midnight_today + 86_400_000u64; // add a day, in milliseconds assert_eq!(midnight_tomorrow, next_rotation_timestamp(midnight_today, 1)); } @@ -245,7 +245,7 @@ mod tests { fn test_seconds_until_next_rotation_is_within_rotation_interval() { let days_rotation = 1u64; // The amount of time in seconds between rotations. - let rotation_interval = days_rotation * 86400u64; + let rotation_interval = days_rotation * 86_400_000u64; let next_rotation_timestamp = next_rotation_timestamp(INITIAL_GENESIS, days_rotation); let s = seconds_until_next_rotation(next_rotation_timestamp); assert!(s < rotation_interval); diff --git a/src/net/channel.rs b/src/net/channel.rs index a9888d9c8..8344efa61 100644 --- a/src/net/channel.rs +++ b/src/net/channel.rs @@ -93,7 +93,7 @@ pub struct Channel { /// The version message of the node we are connected to. /// Some if the version exchange has already occurred, None /// otherwise. - version: Mutex>>, + pub version: Mutex>>, /// Channel debug info pub info: ChannelInfo, }