Compare commits

...

3 Commits

Author SHA1 Message Date
benedettadavico 9d3314470f update changelog 2025-10-16 13:25:23 +02:00
Jędrzej Stuczyński 4a07ea623f Bugfix/bloomfilters purge (#6089)
* remove all old bloomfilters upon starting binary

* remove old bloomfilter file upon purging secondary data
2025-10-16 13:25:22 +02:00
benedettadavico 269dba5281 bump versions 2025-10-16 13:23:54 +02:00
12 changed files with 124 additions and 33 deletions
+44
View File
@@ -4,6 +4,50 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2025.18-jarlsberg] (2025-10-14)
- ns-api: add descriptions to dVPN gateway responses ([#6102])
- NS API: use new probe download filesize and milliseconds field ([#6097])
- ns-api: use download files size from probes instead of parsing filenames ([#6095])
- ns-api: add new fields for probe output for query_metadata and download file size and duration in ms ([#6091])
- Bugfix/bloomfilters purge ([#6089])
- Hotfix: Update API source in node ping tester script ([#6082])
- Get wireguard keypair as arg instead of reading it from disk ([#6078])
- Feature: Ping probe all nodes /described nodes from a server ([#6074])
- Node Status API: add bridge information to dVPN endpoint ([#6069])
- frontdoor typo fix ([#6067])
- Feature: Node rewards tracker ([#6064])
- [chore] Clippy fix ([#6060])
- Registration Client ([#6059])
- Bugfix: Nym node CLI download nym-node exception ([#6058])
- Feature: Nym node html landing page ([#6053])
- feat: DKG contract method for updating announce address ([#6050])
- feat: NS ticket faucet ([#6047])
- Bridge proto client params in Self-Described ([#6035])
- Node Status API: remove sqlite support ([#6004])
- Benny/ci contract fix ([#5962])
[#6102]: https://github.com/nymtech/nym/pull/6102
[#6097]: https://github.com/nymtech/nym/pull/6097
[#6095]: https://github.com/nymtech/nym/pull/6095
[#6091]: https://github.com/nymtech/nym/pull/6091
[#6089]: https://github.com/nymtech/nym/pull/6089
[#6082]: https://github.com/nymtech/nym/pull/6082
[#6078]: https://github.com/nymtech/nym/pull/6078
[#6074]: https://github.com/nymtech/nym/pull/6074
[#6069]: https://github.com/nymtech/nym/pull/6069
[#6067]: https://github.com/nymtech/nym/pull/6067
[#6064]: https://github.com/nymtech/nym/pull/6064
[#6060]: https://github.com/nymtech/nym/pull/6060
[#6059]: https://github.com/nymtech/nym/pull/6059
[#6058]: https://github.com/nymtech/nym/pull/6058
[#6053]: https://github.com/nymtech/nym/pull/6053
[#6050]: https://github.com/nymtech/nym/pull/6050
[#6047]: https://github.com/nymtech/nym/pull/6047
[#6035]: https://github.com/nymtech/nym/pull/6035
[#6004]: https://github.com/nymtech/nym/pull/6004
[#5962]: https://github.com/nymtech/nym/pull/5962
## [2025.17-isabirra] (2025-09-29)
- Bugfix | Fix the registration handshake ([#6062])
Generated
+9 -9
View File
@@ -2262,7 +2262,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.1",
"windows-sys 0.59.0",
]
[[package]]
@@ -4824,7 +4824,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.66"
version = "1.1.67"
dependencies = [
"anyhow",
"async-trait",
@@ -5050,7 +5050,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.63"
version = "1.1.64"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -5133,7 +5133,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.63"
version = "1.1.64"
dependencies = [
"bs58",
"clap",
@@ -6354,7 +6354,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.64"
version = "1.1.65"
dependencies = [
"addr",
"anyhow",
@@ -6404,7 +6404,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.16.0"
version = "1.19.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -6929,7 +6929,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.63"
version = "1.1.64"
dependencies = [
"bs58",
"clap",
@@ -7668,7 +7668,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.28"
version = "0.1.29"
dependencies = [
"anyhow",
"bytes",
@@ -8777,7 +8777,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom 0.2.16",
"libredox",
"thiserror 2.0.17",
"thiserror 2.0.12",
]
[[package]]
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.63"
version = "1.1.64"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.63"
version = "1.1.64"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
+1 -1
View File
@@ -4,7 +4,7 @@
[package]
name = "nym-api"
license = "GPL-3.0"
version = "1.1.66"
version = "1.1.67"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
+1 -1
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-node"
version = "1.16.0"
version = "1.19.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -1,10 +1,8 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::persistence::DEFAULT_RD_BLOOMFILTER_FLUSH_FILE_EXT;
use crate::config::Config;
use crate::config::persistence::{
DEFAULT_RD_BLOOMFILTER_FILE_EXT, DEFAULT_RD_BLOOMFILTER_FLUSH_FILE_EXT,
};
use crate::error::NymNodeError;
use crate::node::replay_protection::bloomfilter::RotationFilter;
use crate::node::replay_protection::helpers::parse_rotation_id_from_filename;
@@ -24,7 +22,6 @@ use tracing::{debug, error, info, trace, warn};
// background task responsible for periodically flushing the bloomfilters to disk
pub struct ReplayProtectionDiskFlush {
bloomfilters_directory: PathBuf,
disk_flushing_rate: Duration,
filters_manager: ReplayProtectionBloomfiltersManager,
@@ -124,8 +121,23 @@ impl ReplayProtectionDiskFlush {
None
};
// if we have any other stored bloomfilters that are neither primary nor secondary,
// remove them - they are an artifact from an old version that had a bug in purging code
for (rotation_id, path) in filter_files {
if rotation_id == primary_key_rotation_id {
continue;
}
if let Some(secondary_key_rotation_id) = secondary_key_rotation_id {
if secondary_key_rotation_id == rotation_id {
continue;
}
}
info!("stale bloomfilter for rotation {rotation_id} found at: {path:?}. it is going to get removed");
fs::remove_file(&path)
.map_err(|source| NymNodeError::BloomfilterIoFailure { source, path })?;
}
Ok(ReplayProtectionDiskFlush {
bloomfilters_directory,
disk_flushing_rate: config
.mixnet
.replay_protection
@@ -142,15 +154,12 @@ impl ReplayProtectionDiskFlush {
}
fn bloomfilter_filepath(&self, rotation_id: u32) -> PathBuf {
self.bloomfilters_directory
.join(format!("rot-{rotation_id}"))
.with_extension(DEFAULT_RD_BLOOMFILTER_FILE_EXT)
self.filters_manager.bloomfilter_filepath(rotation_id)
}
fn current_bloomfilter_being_flushed_filepath(&self, rotation_id: u32) -> PathBuf {
self.bloomfilters_directory
.join(format!("rot-{rotation_id}"))
.with_extension(DEFAULT_RD_BLOOMFILTER_FLUSH_FILE_EXT)
self.filters_manager
.current_bloomfilter_being_flushed_filepath(rotation_id)
}
pub(crate) fn bloomfilters_manager(&self) -> ReplayProtectionBloomfiltersManager {
@@ -213,7 +222,7 @@ impl ReplayProtectionDiskFlush {
}
async fn flush_filters_to_disk(&self) -> Result<(), NymNodeError> {
if let Some(parent) = self.bloomfilters_directory.parent() {
if let Some(parent) = self.filters_manager.bloomfilters_directory().parent() {
fs::create_dir_all(parent).map_err(|source| NymNodeError::BloomfilterIoFailure {
source,
path: parent.to_path_buf(),
@@ -4,6 +4,7 @@
use crate::error::NymNodeError;
use bloomfilter::Bloom;
use nym_sphinx_types::REPLAY_TAG_SIZE;
use nym_validator_client::models::KeyRotationId;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
@@ -12,7 +13,6 @@ use std::path::Path;
use std::sync::{Arc, Mutex, PoisonError, TryLockError};
use time::OffsetDateTime;
use tracing::{error, info, warn};
// auxiliary data associated with the bloomfilter to get some statistics from the time of its creation
// this is needed in order to more accurately resize it upon reset
@@ -180,15 +180,16 @@ impl ReplayProtectionBloomfilters {
Ok(())
}
pub(crate) fn purge_secondary(&self) -> Result<(), NymNodeError> {
pub(crate) fn purge_secondary(&self) -> Result<Option<KeyRotationId>, NymNodeError> {
let mut guard = self
.inner
.lock()
.map_err(|_| NymNodeError::BloomfilterFailure {
message: "mutex got poisoned",
})?;
guard.overlap = None;
Ok(())
let id = guard.overlap.take().map(|f| f.metadata.rotation_id);
Ok(id)
}
pub(crate) fn primary_metadata(
+38 -1
View File
@@ -1,6 +1,9 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::persistence::{
DEFAULT_RD_BLOOMFILTER_FILE_EXT, DEFAULT_RD_BLOOMFILTER_FLUSH_FILE_EXT,
};
use crate::config::Config;
use crate::error::NymNodeError;
use crate::node::replay_protection::bloomfilter::{ReplayProtectionBloomfilters, RotationFilter};
@@ -8,12 +11,16 @@ use crate::node::replay_protection::items_in_bloomfilter;
use human_repr::HumanCount;
use nym_node_metrics::NymNodeMetrics;
use std::cmp::max;
use std::fs;
use std::path::PathBuf;
use std::time::Duration;
use time::OffsetDateTime;
use tracing::info;
#[derive(Clone)]
pub(crate) struct ReplayProtectionBloomfiltersManager {
bloomfilters_directory: PathBuf,
target_fp_p: f64,
minimum_bloomfilter_packets_per_second: usize,
bloomfilter_size_multiplier: f64,
@@ -26,6 +33,7 @@ impl ReplayProtectionBloomfiltersManager {
pub(crate) fn new_disabled(metrics: NymNodeMetrics) -> Self {
// the exact config values are irrelevant as the filters will never be recreated
ReplayProtectionBloomfiltersManager {
bloomfilters_directory: Default::default(),
target_fp_p: 0.001,
minimum_bloomfilter_packets_per_second: 1,
bloomfilter_size_multiplier: 1.0,
@@ -41,6 +49,12 @@ impl ReplayProtectionBloomfiltersManager {
metrics: NymNodeMetrics,
) -> Self {
ReplayProtectionBloomfiltersManager {
bloomfilters_directory: config
.mixnet
.replay_protection
.storage_paths
.current_bloomfilters_directory
.clone(),
target_fp_p: config.mixnet.replay_protection.debug.false_positive_rate,
minimum_bloomfilter_packets_per_second: config
.mixnet
@@ -57,6 +71,22 @@ impl ReplayProtectionBloomfiltersManager {
}
}
pub(crate) fn bloomfilters_directory(&self) -> &PathBuf {
&self.bloomfilters_directory
}
pub(crate) fn bloomfilter_filepath(&self, rotation_id: u32) -> PathBuf {
self.bloomfilters_directory
.join(format!("rot-{rotation_id}"))
.with_extension(DEFAULT_RD_BLOOMFILTER_FILE_EXT)
}
pub(crate) fn current_bloomfilter_being_flushed_filepath(&self, rotation_id: u32) -> PathBuf {
self.bloomfilters_directory
.join(format!("rot-{rotation_id}"))
.with_extension(DEFAULT_RD_BLOOMFILTER_FLUSH_FILE_EXT)
}
pub(crate) fn bloomfilters(&self) -> ReplayProtectionBloomfilters {
self.filters.clone()
}
@@ -70,7 +100,14 @@ impl ReplayProtectionBloomfiltersManager {
}
pub(crate) fn purge_secondary(&self) -> Result<(), NymNodeError> {
self.filters.purge_secondary()
// remove data in memory
if let Some(secondary_id) = self.filters.purge_secondary()? {
// remove data on disk (if applicable)
let path = self.bloomfilter_filepath(secondary_id);
fs::remove_file(&path)
.map_err(|source| NymNodeError::BloomfilterIoFailure { source, path })?;
}
Ok(())
}
pub(crate) fn promote_pre_announced(&self) -> Result<(), NymNodeError> {
@@ -4,7 +4,7 @@
[package]
name = "nym-network-requester"
license = "GPL-3.0"
version = "1.1.64"
version = "1.1.65"
authors.workspace = true
edition.workspace = true
rust-version = "1.85"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-cli"
version = "1.1.63"
version = "1.1.64"
authors.workspace = true
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nymvisor"
version = "0.1.28"
version = "0.1.29"
authors.workspace = true
repository.workspace = true
homepage.workspace = true