mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-28 09:11:34 +00:00
fix(gossipsub): prevent erroneously duplicate message IDs
Previously, we only mutably borrowed the `last_seq_no` in the current scope but did not modify the underlying number. This is because `u64` is copy and calling `wrapping_add` consumes `self` so the compiler just copied it. We introduce a new-type instead that is not `Copy`. Additionally, `wrapping_add` and initializing with a random u64 might actually warp the number and thus not give us sequential numbers as intended in #3551. To solve this, we initialize with the current unix timestamp in nanoseconds. This allows a node to publish 1000000 messages a second and still not reuse sequence numbers even after a restart / re-initialization of the configuration. This is also what the go implementation does. Resolves #3714. Co-authored-by: Thomas Eizinger <thomas@eizinger.io> Pull-Request: #3716.
This commit is contained in:
@ -64,6 +64,7 @@ use crate::types::{
|
||||
use crate::types::{PeerConnections, PeerKind, Rpc};
|
||||
use crate::{rpc_proto::proto, TopicScoreParams};
|
||||
use crate::{PublishError, SubscriptionError, ValidationError};
|
||||
use instant::SystemTime;
|
||||
use quick_protobuf::{MessageWrite, Writer};
|
||||
use std::{cmp::Ordering::Equal, fmt::Debug};
|
||||
use wasm_timer::Interval;
|
||||
@ -149,20 +150,44 @@ pub enum Event {
|
||||
/// A data structure for storing configuration for publishing messages. See [`MessageAuthenticity`]
|
||||
/// for further details.
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone)]
|
||||
enum PublishConfig {
|
||||
Signing {
|
||||
keypair: Keypair,
|
||||
author: PeerId,
|
||||
inline_key: Option<Vec<u8>>,
|
||||
last_seq_no: u64, // This starts from a random number and increases then overflows (if
|
||||
// required)
|
||||
last_seq_no: SequenceNumber,
|
||||
},
|
||||
Author(PeerId),
|
||||
RandomAuthor,
|
||||
Anonymous,
|
||||
}
|
||||
|
||||
/// A strictly linearly increasing sequence number.
|
||||
///
|
||||
/// We start from the current time as unix timestamp in milliseconds.
|
||||
#[derive(Debug)]
|
||||
struct SequenceNumber(u64);
|
||||
|
||||
impl SequenceNumber {
|
||||
fn new() -> Self {
|
||||
let unix_timestamp = SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.expect("time to be linear")
|
||||
.as_nanos();
|
||||
|
||||
Self(unix_timestamp as u64)
|
||||
}
|
||||
|
||||
fn next(&mut self) -> u64 {
|
||||
self.0 = self
|
||||
.0
|
||||
.checked_add(1)
|
||||
.expect("to not exhaust u64 space for sequence numbers");
|
||||
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PublishConfig {
|
||||
pub fn get_own_id(&self) -> Option<&PeerId> {
|
||||
match self {
|
||||
@ -192,7 +217,7 @@ impl From<MessageAuthenticity> for PublishConfig {
|
||||
keypair,
|
||||
author: public_key.to_peer_id(),
|
||||
inline_key: key,
|
||||
last_seq_no: rand::random(),
|
||||
last_seq_no: SequenceNumber::new(),
|
||||
}
|
||||
}
|
||||
MessageAuthenticity::Author(peer_id) => PublishConfig::Author(peer_id),
|
||||
@ -2757,12 +2782,9 @@ where
|
||||
ref keypair,
|
||||
author,
|
||||
inline_key,
|
||||
mut last_seq_no,
|
||||
last_seq_no,
|
||||
} => {
|
||||
// Increment the last sequence number
|
||||
last_seq_no = last_seq_no.wrapping_add(1);
|
||||
|
||||
let sequence_number = last_seq_no;
|
||||
let sequence_number = last_seq_no.next();
|
||||
|
||||
let signature = {
|
||||
let message = proto::Message {
|
||||
|
Reference in New Issue
Block a user