Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 803850be74 | |||
| 3dc62a9a60 | |||
| 5753b79997 | |||
| 2a6aa13ecd | |||
| d5c9e1d8cb | |||
| 87751894d9 | |||
| c8c3928575 | |||
| 2fa8da8117 | |||
| 4548ef4d05 | |||
| 7f147ee2b0 | |||
| 48bcd7e802 | |||
| aad028be3f | |||
| 6db3b34bcb |
@@ -56,7 +56,7 @@ jobs:
|
||||
echo $OUTPUT_DIR
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
run: sudo apt update && sudo apt install libudev-dev
|
||||
run: sudo apt-get update && sudo apt-get -y install libudev-dev
|
||||
|
||||
- name: Sets env vars for tokio if set in manual dispatch inputs
|
||||
run: |
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
name: ci-nym-wallet-rust
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
- 'common/**'
|
||||
- 'contracts/vesting/**'
|
||||
- 'nym-api/nym-api-requests/**'
|
||||
- '.github/workflows/ci-nym-wallet-rust.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'nym-wallet/**'
|
||||
|
||||
@@ -4,6 +4,82 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2024.11-wedel] (2024-09-23)
|
||||
|
||||
- Backport #4894 to fix ci ([#4899])
|
||||
- Bugfix/ticketbook false double spending ([#4892])
|
||||
- fix: allow updating globally stored signatures ([#4891])
|
||||
- [DOCs/operators]: Document changelog for patch/2024.10-caramello ([#4886])
|
||||
- [DOCs/operators]: Post release docs updates ([#4874])
|
||||
- Bump defguard to github latest version ([#4872])
|
||||
- chore: removed completed queued mixnet migration ([#4865])
|
||||
- Disable push trigger and add missing paths in ci-build ([#4864])
|
||||
- Fix linux conditional in ci-build.yml ([#4863])
|
||||
- Remove golang workaround in ci-sdk-wasm ([#4858])
|
||||
- Revert runner for ci-docs ([#4855])
|
||||
- Move credential verification into common crate ([#4853])
|
||||
- Fix test failure in ipr request size ([#4844])
|
||||
- Start switching over jobs to arc-ubuntu-20.04 ([#4843])
|
||||
- Use ecash credential type for bandwidth value ([#4840])
|
||||
- Create nym-repo-setup debian package and nym-vpn meta package ([#4837])
|
||||
- Remove serde_crate named import ([#4832])
|
||||
- Run cargo autoinherit following last weeks dependabot updates ([#4831])
|
||||
- revamped ticketbook serialisation and exposed additional cli methods ([#4827])
|
||||
- Expose wireguard details on self described endpoint ([#4825])
|
||||
- Remove unused wireguard flag from SDK ([#4823])
|
||||
- Add `axum` server to `nym-api` ([#4803])
|
||||
- Run cargo-autoinherit for a few new crates ([#4801])
|
||||
- Update dependabot ([#4796])
|
||||
- Fix clippy for unwrap_or_default ([#4783])
|
||||
- Enable dependabot version upgrades for root rust workspace ([#4778])
|
||||
- Persist used wireguard private IPs ([#4771])
|
||||
- Avoid race on ip and registration structures ([#4766])
|
||||
- docs/hotfix ([#4765])
|
||||
- chore: remove repetitive words ([#4763])
|
||||
- Make gateway latency check generic ([#4759])
|
||||
- Remove duplicate stat count for retransmissions ([#4756])
|
||||
- Update peer refresh value ([#4754])
|
||||
- Remove deprecated mark_as_success and use new disarm ([#4751])
|
||||
- Add get_mixnodes_described to validator_client ([#4725])
|
||||
- New Network Monitor ([#4610])
|
||||
|
||||
[#4899]: https://github.com/nymtech/nym/pull/4899
|
||||
[#4892]: https://github.com/nymtech/nym/pull/4892
|
||||
[#4891]: https://github.com/nymtech/nym/pull/4891
|
||||
[#4886]: https://github.com/nymtech/nym/pull/4886
|
||||
[#4874]: https://github.com/nymtech/nym/pull/4874
|
||||
[#4872]: https://github.com/nymtech/nym/pull/4872
|
||||
[#4865]: https://github.com/nymtech/nym/pull/4865
|
||||
[#4864]: https://github.com/nymtech/nym/pull/4864
|
||||
[#4863]: https://github.com/nymtech/nym/pull/4863
|
||||
[#4858]: https://github.com/nymtech/nym/pull/4858
|
||||
[#4855]: https://github.com/nymtech/nym/pull/4855
|
||||
[#4853]: https://github.com/nymtech/nym/pull/4853
|
||||
[#4844]: https://github.com/nymtech/nym/pull/4844
|
||||
[#4843]: https://github.com/nymtech/nym/pull/4843
|
||||
[#4840]: https://github.com/nymtech/nym/pull/4840
|
||||
[#4837]: https://github.com/nymtech/nym/pull/4837
|
||||
[#4832]: https://github.com/nymtech/nym/pull/4832
|
||||
[#4831]: https://github.com/nymtech/nym/pull/4831
|
||||
[#4827]: https://github.com/nymtech/nym/pull/4827
|
||||
[#4825]: https://github.com/nymtech/nym/pull/4825
|
||||
[#4823]: https://github.com/nymtech/nym/pull/4823
|
||||
[#4803]: https://github.com/nymtech/nym/pull/4803
|
||||
[#4801]: https://github.com/nymtech/nym/pull/4801
|
||||
[#4796]: https://github.com/nymtech/nym/pull/4796
|
||||
[#4783]: https://github.com/nymtech/nym/pull/4783
|
||||
[#4778]: https://github.com/nymtech/nym/pull/4778
|
||||
[#4771]: https://github.com/nymtech/nym/pull/4771
|
||||
[#4766]: https://github.com/nymtech/nym/pull/4766
|
||||
[#4765]: https://github.com/nymtech/nym/pull/4765
|
||||
[#4763]: https://github.com/nymtech/nym/pull/4763
|
||||
[#4759]: https://github.com/nymtech/nym/pull/4759
|
||||
[#4756]: https://github.com/nymtech/nym/pull/4756
|
||||
[#4754]: https://github.com/nymtech/nym/pull/4754
|
||||
[#4751]: https://github.com/nymtech/nym/pull/4751
|
||||
[#4725]: https://github.com/nymtech/nym/pull/4725
|
||||
[#4610]: https://github.com/nymtech/nym/pull/4610
|
||||
|
||||
## [2024.10-caramello] (2024-09-10)
|
||||
|
||||
- Backport 4844 and 4845 ([#4857])
|
||||
|
||||
Generated
+41
-22
@@ -1862,11 +1862,10 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "defguard_wireguard_rs"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba16f17698d4b389907310af018b0c3a80b025bba9c38d947cbc6dd70921743"
|
||||
version = "0.4.7"
|
||||
source = "git+https://github.com/DefGuard/wireguard-rs.git?rev=v0.4.7#ef1cf3714629bf5016fb38cbb7320451dc69fb09"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"libc",
|
||||
"log",
|
||||
"netlink-packet-core",
|
||||
@@ -1875,7 +1874,7 @@ dependencies = [
|
||||
"netlink-packet-utils",
|
||||
"netlink-packet-wireguard",
|
||||
"netlink-sys",
|
||||
"nix 0.27.1",
|
||||
"nix 0.29.0",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -2225,7 +2224,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.39"
|
||||
version = "1.1.40"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.5.17",
|
||||
@@ -4010,14 +4009,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "netlink-packet-route"
|
||||
version = "0.17.1"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66"
|
||||
checksum = "55e5bda7ca0f9ac5e75b5debac3b75e29a8ac8e2171106a2c3bb466389a8dd83"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.5.0",
|
||||
"byteorder",
|
||||
"libc",
|
||||
"log",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-utils",
|
||||
]
|
||||
@@ -4077,7 +4077,6 @@ dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4090,6 +4089,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4220,7 +4220,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.43"
|
||||
version = "1.1.44"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4453,7 +4453,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.41"
|
||||
version = "1.1.42"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
@@ -4534,7 +4534,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.41"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.17",
|
||||
@@ -4910,7 +4910,7 @@ dependencies = [
|
||||
"nym-network-defaults",
|
||||
"rand",
|
||||
"serde",
|
||||
"strum 0.26.3",
|
||||
"strum 0.25.0",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
@@ -5500,7 +5500,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.41"
|
||||
version = "1.1.42"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
@@ -5551,7 +5551,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "1.1.7"
|
||||
version = "1.1.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bip39",
|
||||
@@ -5827,7 +5827,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.41"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"clap 4.5.17",
|
||||
@@ -6186,7 +6186,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"strum 0.26.3",
|
||||
"strum 0.25.0",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"ts-rs",
|
||||
@@ -6356,7 +6356,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nymvisor"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -8576,14 +8576,20 @@ version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||
dependencies = [
|
||||
"strum_macros 0.25.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros 0.26.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
@@ -8611,6 +8617,19 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
|
||||
+3
-2
@@ -210,7 +210,8 @@ ctr = "0.9.1"
|
||||
cupid = "0.6.1"
|
||||
curve25519-dalek = "4.1"
|
||||
dashmap = "5.5.3"
|
||||
defguard_wireguard_rs = "0.4.2"
|
||||
# We want https://github.com/DefGuard/wireguard-rs/pull/64 , but there's no crates.io release being pushed out anymore
|
||||
defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs.git", rev = "v0.4.7" }
|
||||
digest = "0.10.7"
|
||||
dirs = "5.0"
|
||||
doc-comment = "0.3"
|
||||
@@ -288,7 +289,7 @@ sha2 = "0.10.8"
|
||||
si-scale = "0.2.3"
|
||||
sphinx-packet = "0.1.1"
|
||||
sqlx = "0.6.3"
|
||||
strum = "0.26"
|
||||
strum = "0.25"
|
||||
subtle-encoding = "0.5"
|
||||
syn = "1"
|
||||
sysinfo = "0.30.12"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.41"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.40"
|
||||
version = "1.1.41"
|
||||
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"
|
||||
|
||||
@@ -2,21 +2,37 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use si_scale::helpers::bibytes2;
|
||||
use std::sync::atomic::{AtomicI64, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct BandwidthClaimGuard {
|
||||
inner: Arc<ClientBandwidthInner>,
|
||||
}
|
||||
|
||||
impl Drop for BandwidthClaimGuard {
|
||||
fn drop(&mut self) {
|
||||
let old = self.inner.claiming_more.swap(false, Ordering::SeqCst);
|
||||
assert!(
|
||||
old,
|
||||
"critical failure: there were multiple BandwidthClaimGuard existing"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientBandwidth {
|
||||
inner: Arc<ClientBandwidthInner>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ClientBandwidthInner {
|
||||
/// the actual bandwidth amount (in bytes) available
|
||||
available: AtomicI64,
|
||||
|
||||
/// flag to indicate whether this client is currently in the process of claiming additional bandwidth
|
||||
claiming_more: AtomicBool,
|
||||
|
||||
/// defines the timestamp when the bandwidth information has been logged to the logs stream
|
||||
last_logged_ts: AtomicI64,
|
||||
|
||||
@@ -29,11 +45,28 @@ impl ClientBandwidth {
|
||||
ClientBandwidth {
|
||||
inner: Arc::new(ClientBandwidthInner {
|
||||
available: AtomicI64::new(0),
|
||||
claiming_more: AtomicBool::new(false),
|
||||
last_logged_ts: AtomicI64::new(0),
|
||||
last_updated_ts: AtomicI64::new(0),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn begin_bandwidth_claim(&self) -> Option<BandwidthClaimGuard> {
|
||||
if self
|
||||
.inner
|
||||
.claiming_more
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
||||
.is_ok()
|
||||
{
|
||||
Some(BandwidthClaimGuard {
|
||||
inner: self.inner.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn remaining(&self) -> i64 {
|
||||
self.inner.available.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
@@ -598,6 +598,11 @@ impl<C, St> GatewayClient<C, St> {
|
||||
return Err(GatewayClientError::NoBandwidthControllerAvailable);
|
||||
}
|
||||
|
||||
let Some(_claim_guard) = self.bandwidth.begin_bandwidth_claim() else {
|
||||
debug!("there's already an existing bandwidth claim ongoing");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
warn!("Not enough bandwidth. Trying to get more bandwidth, this might take a while");
|
||||
if !self.cfg.bandwidth.require_tickets {
|
||||
info!("The client is running in disabled credentials mode - attempting to claim bandwidth without a credential");
|
||||
|
||||
@@ -171,10 +171,20 @@ impl SqliteEcashTicketbookManager {
|
||||
data: &[u8],
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO master_verification_key(epoch_id, serialised_key, serialization_revision) VALUES (?, ?, ?)",
|
||||
r#"
|
||||
INSERT OR IGNORE INTO master_verification_key(epoch_id, serialised_key, serialization_revision) VALUES (?, ?, ?);
|
||||
UPDATE master_verification_key
|
||||
SET
|
||||
serialised_key = ?,
|
||||
serialization_revision = ?
|
||||
WHERE epoch_id = ?
|
||||
"#,
|
||||
epoch_id,
|
||||
data,
|
||||
serialisation_revision
|
||||
serialisation_revision,
|
||||
data,
|
||||
serialisation_revision,
|
||||
epoch_id
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
@@ -204,10 +214,20 @@ impl SqliteEcashTicketbookManager {
|
||||
data: &[u8],
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO coin_indices_signatures(epoch_id, serialised_signatures, serialization_revision) VALUES (?, ?, ?)",
|
||||
r#"
|
||||
INSERT OR IGNORE INTO coin_indices_signatures(epoch_id, serialised_signatures, serialization_revision) VALUES (?, ?, ?);
|
||||
UPDATE coin_indices_signatures
|
||||
SET
|
||||
serialised_signatures = ?,
|
||||
serialization_revision = ?
|
||||
WHERE epoch_id = ?
|
||||
"#,
|
||||
epoch_id,
|
||||
data,
|
||||
serialisation_revision
|
||||
serialisation_revision,
|
||||
data,
|
||||
serialisation_revision,
|
||||
epoch_id,
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
@@ -240,13 +260,21 @@ impl SqliteEcashTicketbookManager {
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO expiration_date_signatures(expiration_date, epoch_id, serialised_signatures, serialization_revision)
|
||||
VALUES (?, ?, ?, ?)
|
||||
INSERT OR IGNORE INTO expiration_date_signatures(expiration_date, epoch_id, serialised_signatures, serialization_revision)
|
||||
VALUES (?, ?, ?, ?);
|
||||
UPDATE expiration_date_signatures
|
||||
SET
|
||||
serialised_signatures = ?,
|
||||
serialization_revision = ?
|
||||
WHERE expiration_date = ?
|
||||
"#,
|
||||
expiration_date,
|
||||
epoch_id,
|
||||
data,
|
||||
serialisation_revision
|
||||
serialisation_revision,
|
||||
data,
|
||||
serialisation_revision,
|
||||
expiration_date
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::*;
|
||||
use crate::BandwidthFlushingBehaviourConfig;
|
||||
use crate::ClientBandwidth;
|
||||
use nym_credentials::ecash::utils::ecash_today;
|
||||
use nym_credentials_interface::Bandwidth;
|
||||
use nym_gateway_requests::ServerResponse;
|
||||
@@ -9,10 +12,6 @@ use si_scale::helpers::bibytes2;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::*;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::BandwidthFlushingBehaviourConfig;
|
||||
use crate::ClientBandwidth;
|
||||
|
||||
const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new_unchecked(64 * 1024 * 1024 * 1024); // 64GB
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -43,7 +42,7 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
|
||||
async fn sync_expiration(&mut self) -> Result<()> {
|
||||
self.storage
|
||||
.set_expiration(self.client_id, self.client_bandwidth.bandwidth.expiration)
|
||||
.set_expiration(self.client_id, self.client_bandwidth.expiration().await)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -57,17 +56,17 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
|
||||
self.increase_bandwidth(FREE_TESTNET_BANDWIDTH_VALUE, ecash_today())
|
||||
.await?;
|
||||
let available_total = self.client_bandwidth.bandwidth.bytes;
|
||||
let available_total = self.client_bandwidth.available().await;
|
||||
|
||||
Ok(ServerResponse::Bandwidth { available_total })
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn try_use_bandwidth(&mut self, required_bandwidth: i64) -> Result<i64> {
|
||||
if self.client_bandwidth.bandwidth.expired() {
|
||||
if self.client_bandwidth.expired().await {
|
||||
self.expire_bandwidth().await?;
|
||||
}
|
||||
let available_bandwidth = self.client_bandwidth.bandwidth.bytes;
|
||||
let available_bandwidth = self.client_bandwidth.available().await;
|
||||
|
||||
if available_bandwidth < required_bandwidth {
|
||||
return Err(Error::OutOfBandwidth {
|
||||
@@ -86,8 +85,7 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
|
||||
async fn expire_bandwidth(&mut self) -> Result<()> {
|
||||
self.storage.reset_bandwidth(self.client_id).await?;
|
||||
self.client_bandwidth.bandwidth = Default::default();
|
||||
self.client_bandwidth.update_sync_data();
|
||||
self.client_bandwidth.expire_bandwidth().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -97,31 +95,31 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
///
|
||||
/// * `amount`: amount to decrease the available bandwidth by.
|
||||
async fn consume_bandwidth(&mut self, amount: i64) -> Result<()> {
|
||||
self.client_bandwidth.bandwidth.bytes -= amount;
|
||||
self.client_bandwidth.bytes_delta_since_sync -= amount;
|
||||
self.client_bandwidth.decrease_bandwidth(amount).await;
|
||||
|
||||
// since we're going to be operating on a fair use policy anyway, even if we crash and let extra few packets
|
||||
// through, that's completely fine
|
||||
if self.client_bandwidth.should_sync(self.bandwidth_cfg) {
|
||||
self.sync_bandwidth().await?;
|
||||
if self.client_bandwidth.should_sync(self.bandwidth_cfg).await {
|
||||
self.sync_storage_bandwidth().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
async fn sync_bandwidth(&mut self) -> Result<()> {
|
||||
async fn sync_storage_bandwidth(&mut self) -> Result<()> {
|
||||
trace!("syncing client bandwidth with the underlying storage");
|
||||
let updated = self
|
||||
.storage
|
||||
.increase_bandwidth(self.client_id, self.client_bandwidth.bytes_delta_since_sync)
|
||||
.increase_bandwidth(
|
||||
self.client_id,
|
||||
self.client_bandwidth.delta_since_sync().await,
|
||||
)
|
||||
.await?;
|
||||
|
||||
trace!(updated);
|
||||
|
||||
self.client_bandwidth.bandwidth.bytes = updated;
|
||||
|
||||
self.client_bandwidth.update_sync_data();
|
||||
self.client_bandwidth
|
||||
.resync_bandwidth_with_storage(updated)
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -136,13 +134,14 @@ impl<S: Storage + Clone + 'static> BandwidthStorageManager<S> {
|
||||
bandwidth: Bandwidth,
|
||||
expiration: OffsetDateTime,
|
||||
) -> Result<()> {
|
||||
self.client_bandwidth.bandwidth.bytes += bandwidth.value() as i64;
|
||||
self.client_bandwidth.bytes_delta_since_sync += bandwidth.value() as i64;
|
||||
self.client_bandwidth.bandwidth.expiration = expiration;
|
||||
self.client_bandwidth
|
||||
.increase_bandwidth(bandwidth.value() as i64, expiration)
|
||||
.await;
|
||||
|
||||
// any increases to bandwidth should get flushed immediately
|
||||
// (we don't want to accidentally miss somebody claiming a gigabyte voucher)
|
||||
self.sync_expiration().await?;
|
||||
self.sync_bandwidth().await
|
||||
self.sync_storage_bandwidth().await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use nym_credentials::ecash::utils::ecash_today;
|
||||
use nym_credentials_interface::AvailableBandwidth;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct BandwidthFlushingBehaviourConfig {
|
||||
@@ -15,10 +17,15 @@ pub struct BandwidthFlushingBehaviourConfig {
|
||||
pub client_bandwidth_max_delta_flushing_amount: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientBandwidth {
|
||||
inner: Arc<RwLock<ClientBandwidthInner>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClientBandwidthInner {
|
||||
pub(crate) bandwidth: AvailableBandwidth,
|
||||
pub(crate) last_flushed: OffsetDateTime,
|
||||
pub(crate) last_synced: OffsetDateTime,
|
||||
|
||||
/// the number of bytes the client had during the last sync.
|
||||
/// it is used to determine whether the current value should be synced with the storage
|
||||
@@ -30,28 +37,74 @@ pub struct ClientBandwidth {
|
||||
impl ClientBandwidth {
|
||||
pub fn new(bandwidth: AvailableBandwidth) -> ClientBandwidth {
|
||||
ClientBandwidth {
|
||||
bandwidth,
|
||||
last_flushed: OffsetDateTime::now_utc(),
|
||||
bytes_at_last_sync: bandwidth.bytes,
|
||||
bytes_delta_since_sync: 0,
|
||||
inner: Arc::new(RwLock::new(ClientBandwidthInner {
|
||||
bandwidth,
|
||||
last_synced: OffsetDateTime::now_utc(),
|
||||
bytes_at_last_sync: bandwidth.bytes,
|
||||
bytes_delta_since_sync: 0,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn should_sync(&self, cfg: BandwidthFlushingBehaviourConfig) -> bool {
|
||||
if self.bytes_delta_since_sync.abs() >= cfg.client_bandwidth_max_delta_flushing_amount {
|
||||
pub(crate) async fn should_sync(&self, cfg: BandwidthFlushingBehaviourConfig) -> bool {
|
||||
let guard = self.inner.read().await;
|
||||
|
||||
if guard.bytes_delta_since_sync.abs() >= cfg.client_bandwidth_max_delta_flushing_amount {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.last_flushed + cfg.client_bandwidth_max_flushing_rate < OffsetDateTime::now_utc() {
|
||||
if guard.last_synced + cfg.client_bandwidth_max_flushing_rate < OffsetDateTime::now_utc() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn update_sync_data(&mut self) {
|
||||
self.last_flushed = OffsetDateTime::now_utc();
|
||||
self.bytes_at_last_sync = self.bandwidth.bytes;
|
||||
self.bytes_delta_since_sync = 0;
|
||||
pub(crate) async fn available(&self) -> i64 {
|
||||
self.inner.read().await.bandwidth.bytes
|
||||
}
|
||||
|
||||
pub(crate) async fn delta_since_sync(&self) -> i64 {
|
||||
self.inner.read().await.bytes_delta_since_sync
|
||||
}
|
||||
pub(crate) async fn expiration(&self) -> OffsetDateTime {
|
||||
self.inner.read().await.bandwidth.expiration
|
||||
}
|
||||
|
||||
pub(crate) async fn expired(&self) -> bool {
|
||||
self.expiration().await < ecash_today()
|
||||
}
|
||||
|
||||
pub(crate) async fn decrease_bandwidth(&self, decrease: i64) {
|
||||
let mut guard = self.inner.write().await;
|
||||
|
||||
guard.bandwidth.bytes -= decrease;
|
||||
guard.bytes_delta_since_sync -= decrease;
|
||||
}
|
||||
|
||||
pub(crate) async fn increase_bandwidth(&self, increase: i64, new_expiration: OffsetDateTime) {
|
||||
let mut guard = self.inner.write().await;
|
||||
|
||||
guard.bandwidth.bytes += increase;
|
||||
guard.bandwidth.expiration = new_expiration;
|
||||
guard.bytes_delta_since_sync += increase;
|
||||
}
|
||||
|
||||
pub(crate) async fn expire_bandwidth(&self) {
|
||||
let mut guard = self.inner.write().await;
|
||||
|
||||
guard.bandwidth = AvailableBandwidth::default();
|
||||
guard.last_synced = OffsetDateTime::now_utc();
|
||||
guard.bytes_at_last_sync = 0;
|
||||
guard.bytes_delta_since_sync = 0;
|
||||
}
|
||||
|
||||
pub(crate) async fn resync_bandwidth_with_storage(&self, stored: i64) {
|
||||
let mut guard = self.inner.write().await;
|
||||
|
||||
guard.bandwidth.bytes = stored;
|
||||
guard.bytes_at_last_sync = stored;
|
||||
guard.bytes_delta_since_sync = 0;
|
||||
guard.last_synced = OffsetDateTime::now_utc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ impl<S: Storage + Clone + 'static> CredentialVerifier<S> {
|
||||
Ok(self
|
||||
.bandwidth_storage_manager
|
||||
.client_bandwidth
|
||||
.bandwidth
|
||||
.bytes)
|
||||
.available()
|
||||
.await)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
CREATE TABLE clients (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
client_type TEXT NOT NULL CHECK(client_type IN ('entry_mixnet', 'exit_mixnet', 'entry_wireguard', 'exit_wireguard'))
|
||||
);
|
||||
|
||||
INSERT INTO clients (id, client_type)
|
||||
SELECT id, 'entry_mixnet'
|
||||
FROM shared_keys;
|
||||
|
||||
CREATE TABLE shared_keys_tmp (
|
||||
client_id INTEGER NOT NULL PRIMARY KEY REFERENCES clients(id),
|
||||
client_address_bs58 TEXT NOT NULL UNIQUE,
|
||||
derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO shared_keys_tmp (client_id, client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58)
|
||||
SELECT id as client_id, client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58 FROM shared_keys;
|
||||
|
||||
CREATE TABLE available_bandwidth_tmp (
|
||||
client_id INTEGER NOT NULL PRIMARY KEY REFERENCES clients(id),
|
||||
available INTEGER NOT NULL,
|
||||
expiration TIMESTAMP WITHOUT TIME ZONE
|
||||
);
|
||||
|
||||
INSERT INTO available_bandwidth_tmp
|
||||
SELECT * FROM available_bandwidth;
|
||||
|
||||
DROP TABLE available_bandwidth;
|
||||
ALTER TABLE available_bandwidth_tmp RENAME TO available_bandwidth;
|
||||
|
||||
CREATE TABLE received_ticket_tmp (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
client_id INTEGER NOT NULL REFERENCES clients(id),
|
||||
received_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
rejected BOOLEAN
|
||||
);
|
||||
|
||||
INSERT INTO received_ticket_tmp
|
||||
SELECT * FROM received_ticket;
|
||||
|
||||
DROP INDEX received_ticket_index;
|
||||
CREATE INDEX received_ticket_index ON received_ticket_tmp (received_at);
|
||||
|
||||
-- received tickets that are in the process of verifying
|
||||
CREATE TABLE ticket_data_tmp (
|
||||
ticket_id INTEGER NOT NULL PRIMARY KEY REFERENCES received_ticket_tmp(id),
|
||||
|
||||
-- serial_number, alongside the entire row, will get purged after redemption is complete
|
||||
serial_number BLOB NOT NULL UNIQUE,
|
||||
|
||||
-- data will get purged after 80% of signers verifies it
|
||||
data BLOB
|
||||
);
|
||||
|
||||
INSERT INTO ticket_data_tmp
|
||||
SELECT * FROM ticket_data;
|
||||
|
||||
DROP TABLE ticket_data;
|
||||
ALTER TABLE ticket_data_tmp RENAME TO ticket_data;
|
||||
|
||||
-- result of a verification from a single signer (API)
|
||||
CREATE TABLE ticket_verification_tmp (
|
||||
ticket_id INTEGER NOT NULL REFERENCES received_ticket_tmp(id),
|
||||
signer_id INTEGER NOT NULL,
|
||||
verified_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
accepted BOOLEAN NOT NULL,
|
||||
|
||||
PRIMARY KEY (ticket_id, signer_id)
|
||||
);
|
||||
|
||||
DROP INDEX ticket_verification_index;
|
||||
CREATE INDEX ticket_verification_index ON ticket_verification_tmp (ticket_id);
|
||||
|
||||
DROP TABLE ticket_verification;
|
||||
ALTER TABLE ticket_verification_tmp RENAME TO ticket_verification;
|
||||
|
||||
-- verified tickets that are yet to be redeemed
|
||||
CREATE TABLE verified_tickets_tmp (
|
||||
ticket_id INTEGER NOT NULL PRIMARY KEY REFERENCES received_ticket_tmp(id),
|
||||
proposal_id INTEGER REFERENCES redemption_proposals(proposal_id)
|
||||
);
|
||||
|
||||
DROP INDEX verified_tickets_index;
|
||||
CREATE INDEX verified_tickets_index ON verified_tickets_tmp (proposal_id);
|
||||
|
||||
DROP TABLE verified_tickets;
|
||||
ALTER TABLE verified_tickets_tmp RENAME TO verified_tickets;
|
||||
|
||||
DROP TABLE received_ticket;
|
||||
ALTER TABLE received_ticket_tmp RENAME TO received_ticket;
|
||||
|
||||
DROP TABLE shared_keys;
|
||||
ALTER TABLE shared_keys_tmp RENAME TO shared_keys;
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::models::Client;
|
||||
|
||||
#[derive(Debug, PartialEq, sqlx::Type)]
|
||||
#[sqlx(type_name = "TEXT")] // SQLite TEXT type
|
||||
pub enum ClientType {
|
||||
EntryMixnet,
|
||||
ExitMixnet,
|
||||
EntryWireguard,
|
||||
ExitWireguard,
|
||||
}
|
||||
|
||||
impl FromStr for ClientType {
|
||||
type Err = &'static str;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"entry_mixnet" => Ok(ClientType::EntryMixnet),
|
||||
"exit_mixnet" => Ok(ClientType::ExitMixnet),
|
||||
"entry_wireguard" => Ok(ClientType::EntryWireguard),
|
||||
"exit_wireguard" => Ok(ClientType::ExitWireguard),
|
||||
_ => Err("Invalid client type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ClientType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
ClientType::EntryMixnet => "entry_mixnet",
|
||||
ClientType::ExitMixnet => "exit_mixnet",
|
||||
ClientType::EntryWireguard => "entry_wireguard",
|
||||
ClientType::ExitWireguard => "exit_wireguard",
|
||||
};
|
||||
write!(f, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ClientManager {
|
||||
connection_pool: sqlx::SqlitePool,
|
||||
}
|
||||
|
||||
impl ClientManager {
|
||||
/// Creates new instance of the `ClientManager` with the provided sqlite connection pool.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `connection_pool`: database connection pool to use.
|
||||
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
|
||||
ClientManager { connection_pool }
|
||||
}
|
||||
|
||||
/// Inserts new client to the storage, specifying its type.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `client_type`: Type of the client that gets inserted
|
||||
pub(crate) async fn insert_client(&self, client_type: ClientType) -> Result<i64, sqlx::Error> {
|
||||
let client_id = sqlx::query!("INSERT INTO clients(client_type) VALUES (?)", client_type)
|
||||
.execute(&self.connection_pool)
|
||||
.await?
|
||||
.last_insert_rowid();
|
||||
Ok(client_id)
|
||||
}
|
||||
|
||||
/// Tries to retrieve a particular client.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id`: The client id
|
||||
pub(crate) async fn get_client(&self, id: i64) -> Result<Option<Client>, sqlx::Error> {
|
||||
sqlx::query_as!(
|
||||
Client,
|
||||
r#"
|
||||
SELECT id, client_type as "client_type: ClientType"
|
||||
FROM clients
|
||||
WHERE id = ?
|
||||
"#,
|
||||
id
|
||||
)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,11 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
use bandwidth::BandwidthManager;
|
||||
use clients::{ClientManager, ClientType};
|
||||
use error::StorageError;
|
||||
use inboxes::InboxManager;
|
||||
use models::{
|
||||
Client, PersistedBandwidth, PersistedSharedKeys, RedemptionProposal, StoredMessage,
|
||||
VerifiedTicket, WireguardPeer,
|
||||
PersistedBandwidth, PersistedSharedKeys, RedemptionProposal, StoredMessage, VerifiedTicket,
|
||||
WireguardPeer,
|
||||
};
|
||||
use nym_credentials_interface::ClientTicket;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
@@ -21,7 +20,6 @@ use time::OffsetDateTime;
|
||||
use tracing::{debug, error};
|
||||
|
||||
pub mod bandwidth;
|
||||
mod clients;
|
||||
pub mod error;
|
||||
mod inboxes;
|
||||
pub mod models;
|
||||
@@ -31,7 +29,7 @@ mod wireguard_peers;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Storage: Send + Sync {
|
||||
async fn get_mixnet_client_id(
|
||||
async fn get_client_id(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<i64, StorageError>;
|
||||
@@ -41,7 +39,7 @@ pub trait Storage: Send + Sync {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `client_address`: base58-encoded address of the client
|
||||
/// * `client_address`: address of the client
|
||||
/// * `shared_keys`: shared encryption (AES128CTR) and mac (hmac-blake3) derived shared keys to store.
|
||||
async fn insert_shared_keys(
|
||||
&self,
|
||||
@@ -72,14 +70,6 @@ pub trait Storage: Send + Sync {
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StorageError>;
|
||||
|
||||
/// Tries to retrieve a particular client.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `client_id`: id of the client
|
||||
#[allow(dead_code)]
|
||||
async fn get_client(&self, client_id: i64) -> Result<Option<Client>, StorageError>;
|
||||
|
||||
/// Inserts new message to the storage for an offline client for future retrieval.
|
||||
///
|
||||
/// # Arguments
|
||||
@@ -256,7 +246,6 @@ pub trait Storage: Send + Sync {
|
||||
// note that clone here is fine as upon cloning the same underlying pool will be used
|
||||
#[derive(Clone)]
|
||||
pub struct PersistentStorage {
|
||||
client_manager: ClientManager,
|
||||
shared_key_manager: SharedKeysManager,
|
||||
inbox_manager: InboxManager,
|
||||
bandwidth_manager: BandwidthManager,
|
||||
@@ -305,7 +294,6 @@ impl PersistentStorage {
|
||||
|
||||
// the cloning here are cheap as connection pool is stored behind an Arc
|
||||
Ok(PersistentStorage {
|
||||
client_manager: clients::ClientManager::new(connection_pool.clone()),
|
||||
wireguard_peer_manager: wireguard_peers::WgPeerManager::new(connection_pool.clone()),
|
||||
shared_key_manager: SharedKeysManager::new(connection_pool.clone()),
|
||||
inbox_manager: InboxManager::new(connection_pool.clone(), message_retrieval_limit),
|
||||
@@ -317,7 +305,7 @@ impl PersistentStorage {
|
||||
|
||||
#[async_trait]
|
||||
impl Storage for PersistentStorage {
|
||||
async fn get_mixnet_client_id(
|
||||
async fn get_client_id(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<i64, StorageError> {
|
||||
@@ -333,12 +321,8 @@ impl Storage for PersistentStorage {
|
||||
shared_keys: &SharedKeys,
|
||||
) -> Result<i64, StorageError> {
|
||||
let client_id = self
|
||||
.client_manager
|
||||
.insert_client(ClientType::EntryMixnet)
|
||||
.await?;
|
||||
self.shared_key_manager
|
||||
.shared_key_manager
|
||||
.insert_shared_keys(
|
||||
client_id,
|
||||
client_address.as_base58_string(),
|
||||
shared_keys.to_base58_string(),
|
||||
)
|
||||
@@ -368,11 +352,6 @@ impl Storage for PersistentStorage {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_client(&self, client_id: i64) -> Result<Option<Client>, StorageError> {
|
||||
let client = self.client_manager.get_client(client_id).await?;
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
async fn store_message(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
|
||||
@@ -6,14 +6,9 @@ use nym_credentials_interface::{AvailableBandwidth, ClientTicket, CredentialSpen
|
||||
use sqlx::FromRow;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
pub struct Client {
|
||||
pub id: i64,
|
||||
pub client_type: crate::clients::ClientType,
|
||||
}
|
||||
|
||||
pub struct PersistedSharedKeys {
|
||||
#[allow(dead_code)]
|
||||
pub client_id: i64,
|
||||
pub id: i64,
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub client_address_bs58: String,
|
||||
|
||||
@@ -20,12 +20,12 @@ impl SharedKeysManager {
|
||||
|
||||
pub(crate) async fn client_id(&self, client_address_bs58: &str) -> Result<i64, sqlx::Error> {
|
||||
let client_id = sqlx::query!(
|
||||
"SELECT client_id FROM shared_keys WHERE client_address_bs58 = ?",
|
||||
"SELECT id FROM shared_keys WHERE client_address_bs58 = ?",
|
||||
client_address_bs58
|
||||
)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await?
|
||||
.client_id;
|
||||
.id;
|
||||
Ok(client_id)
|
||||
}
|
||||
|
||||
@@ -34,30 +34,26 @@ impl SharedKeysManager {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `client_id`: The client id for which the shared keys are stored
|
||||
/// * `client_address_bs58`: base58-encoded address of the client
|
||||
/// * `derived_aes128_ctr_blake3_hmac_keys_bs58`: shared encryption (AES128CTR) and mac (hmac-blake3) derived shared keys to store.
|
||||
/// * `shared_keys`: shared encryption (AES128CTR) and mac (hmac-blake3) derived shared keys to store.
|
||||
pub(crate) async fn insert_shared_keys(
|
||||
&self,
|
||||
client_id: i64,
|
||||
client_address_bs58: String,
|
||||
derived_aes128_ctr_blake3_hmac_keys_bs58: String,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
// https://stackoverflow.com/a/20310838
|
||||
// we don't want to be using `INSERT OR REPLACE INTO` due to the foreign key on `available_bandwidth` if the entry already exists
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT OR IGNORE INTO shared_keys(client_id, client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58) VALUES (?, ?, ?);
|
||||
INSERT OR IGNORE INTO shared_keys(client_address_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58) VALUES (?, ?);
|
||||
UPDATE shared_keys SET derived_aes128_ctr_blake3_hmac_keys_bs58 = ? WHERE client_address_bs58 = ?
|
||||
"#,
|
||||
client_id,
|
||||
client_address_bs58,
|
||||
derived_aes128_ctr_blake3_hmac_keys_bs58,
|
||||
derived_aes128_ctr_blake3_hmac_keys_bs58,
|
||||
client_address_bs58,
|
||||
).execute(&self.connection_pool).await?;
|
||||
|
||||
Ok(())
|
||||
self.client_id(&client_address_bs58).await
|
||||
}
|
||||
|
||||
/// Tries to retrieve shared keys stored for the particular client.
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use std::fmt::{Display, Formatter};
|
||||
use strum::{Display, EnumString, VariantNames};
|
||||
use strum::{Display, EnumString, EnumVariantNames};
|
||||
|
||||
#[cfg(feature = "generate-ts")]
|
||||
use ts_rs::{Dependency, TS};
|
||||
@@ -28,7 +28,7 @@ use ts_rs::{Dependency, TS};
|
||||
Clone,
|
||||
Debug,
|
||||
EnumString,
|
||||
VariantNames,
|
||||
EnumVariantNames,
|
||||
PartialEq,
|
||||
Eq,
|
||||
JsonSchema,
|
||||
|
||||
@@ -115,6 +115,7 @@ pub async fn start_wireguard<St: nym_gateway_storage::Storage + 'static>(
|
||||
address: wireguard_data.inner.config().private_ip.to_string(),
|
||||
port: wireguard_data.inner.config().announced_port as u32,
|
||||
peers,
|
||||
mtu: None,
|
||||
};
|
||||
wg_api.configure_interface(&interface_config)?;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ This guide contains several variables. Substitute them with your own value, with
|
||||
| `<WSS_PORT>` | Port listening to WSS, default is `9001` | 9001 |
|
||||
| `<YOUR_WELCOME_TEXT>` | Any text you want to show on the landing page | Welcome to Nym Node, operator contact is example@email.me |
|
||||
| `<LANDING_PAGE_PATH>` | A sub-directory located at `/var/www/<HOSTNAME>` containing html configuration files | `/var/www/exit-gateway1.squad.nsl` |
|
||||
| `<ID>` | A local only `nym-node` identifier, specified by flag `--id`, default is `default-nym-node` | alice_super_node |
|
||||
| `<NODE_ID>` | A local only `nym-node` identifier, specified by flag `--id`, default is `default-nym-node` | alice_super_node |
|
||||
| `<PATH_TO>` | Specify a full path to the given file, directory or binary behind this variable | `/root/src/nym/target/release/` |
|
||||
|
||||
```admonish warning title=""
|
||||
@@ -309,7 +309,7 @@ Now your html page is configured.
|
||||
|
||||
### `nym-node` Configuration
|
||||
|
||||
When done with the customization, you'll need to make sure your `nym-node` uploads the file and reference to it. This is done by opening your node configuration file located at `~/.nym/nym-nodes/<ID>/config/config.toml` and changing the value of the line `landing_page_assets_path` on the `[http]` section:
|
||||
When done with the customization, you'll need to make sure your `nym-node` uploads the file and reference to it. This is done by opening your node configuration file located at `~/.nym/nym-nodes/<NODE_ID>/config/config.toml` and changing the value of the line `landing_page_assets_path` on the `[http]` section:
|
||||
```
|
||||
landing_page_assets_path = '<LANDING_PAGE_PATH>'
|
||||
```
|
||||
@@ -364,7 +364,7 @@ server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
server_name <HOSTNAME>;
|
||||
server_name nym-exit.<HOSTNAME>;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/<HOSTNAME>/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/<HOSTNAME>/privkey.pem;
|
||||
@@ -486,7 +486,7 @@ sudo chown -R $USER:$USER /var/www/<HOSTNAME>
|
||||
echo "<h1><YOUR_WELCOME_TEXT></h1>" | sudo tee /var/www/<HOSTNAME>/index.html
|
||||
```
|
||||
|
||||
4. When done with the customization, you'll need to make sure your `nym-node` uploads the file and reference to it. This is done by opening your node configuration file located at `~/.nym/nym-nodes/<ID>/config/config.toml` and changing the value of the line `landing_page_assets_path` on the `[http]` section:
|
||||
4. When done with the customization, you'll need to make sure your `nym-node` uploads the file and reference to it. This is done by opening your node configuration file located at `~/.nym/nym-nodes/<NODE_ID>/config/config.toml` and changing the value of the line `landing_page_assets_path` on the `[http]` section:
|
||||
```sh
|
||||
landing_page_assets_path = '<LANDING_PAGE_PATH>'
|
||||
|
||||
@@ -800,9 +800,14 @@ ln -s /etc/nginx/sites-available/<HOSTNAME> /etc/nginx/sites-enabled
|
||||
nginx -t
|
||||
```
|
||||
|
||||
6. Restart `nginx`:
|
||||
```sh
|
||||
systemctl daemon-reload && systemctl restart nginx
|
||||
```
|
||||
|
||||
#### SSL Setup using certbot
|
||||
|
||||
6. Get an `SSL` certificate using certbot:
|
||||
7. Get an `SSL` certificate using certbot:
|
||||
|
||||
```sh
|
||||
apt install certbot python3-certbot-nginx
|
||||
@@ -810,11 +815,6 @@ certbot renew --dry-run
|
||||
certbot --nginx -d <HOSTNAME>
|
||||
```
|
||||
|
||||
7. Restart `nginx`:
|
||||
```sh
|
||||
systemctl daemon-reload && systemctl restart nginx
|
||||
```
|
||||
|
||||
8. Restart your `nym-node` or if you're running your `nym-node` as a [`systemd` service](configuration.md#systemd), restart your service:
|
||||
```sh
|
||||
systemctl daemon-reload
|
||||
|
||||
+4
-7
@@ -11,16 +11,13 @@ STAKE_DENOM_DISPLAY=nyx
|
||||
DENOMS_EXPONENT=6
|
||||
|
||||
MIXNET_CONTRACT_ADDRESS=n1hm4y6fzgxgu688jgf7ek66px6xkrtmn3gyk8fax3eawhp68c2d5qujz296
|
||||
ECASH_CONTRACT_ADDRESS=n14y2x8a60knc5jjfeztt84kw8x8l5pwdgnqg256v0p9v4p7t2q6eswxyusw
|
||||
GROUP_CONTRACT_ADDRESS=n1qp35fcj0v9u3trhaps5v9q0lc42t4m6aty2wryss75ee8zuqnsqqdcreyq
|
||||
MULTISIG_CONTRACT_ADDRESS=n1qa4hswlcjmttulj0q9qa46jf64f93pecl6tydcsjldfe0hy5ju0sdmwzya
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n1ayrk6wp6w5lf6njtnfjwljmtcc9vevv5sxwkz7uq24rp2pw67t0qhmmxdd
|
||||
ECASH_CONTRACT_ADDRESS=n13xspq62y9gq6nueqmywxcdv2yep4p6nzv98w2889k25v3nhdy2dq2rkrk7
|
||||
GROUP_CONTRACT_ADDRESS=n13l7rwuwktklrwskc7m6lv70zws07en85uma28j7dxwsz9y5hvvhspl7a2t
|
||||
MULTISIG_CONTRACT_ADDRESS=n138c9pyf7f3hyx0j3t6vmsz7ultnw2wj0lu6hzndep9z5grgq9haqlc25k0
|
||||
COCONUT_DKG_CONTRACT_ADDRESS=n1pk8jgr6y4c5k93gz7qf3xc0hvygmp7csk88c2tf8l39tkq6834wq2a6dtr
|
||||
VESTING_CONTRACT_ADDRESS=n1jlzdxnyces4hrhqz68dqk28mrw5jgwtcfq0c2funcwrmw0dx9l9s8nnnvj
|
||||
REWARDING_VALIDATOR_ADDRESS=n1rfvpsynktze6wvn6ldskj8xgwfzzk5v6pnff39
|
||||
|
||||
EXPLORER_API=https://qa-network-explorer.qa.nymte.ch/api
|
||||
NYXD="https://qa-validator.qa.nymte.ch"
|
||||
NYM_API="https://qa-nym-api.qa.nymte.ch/api"
|
||||
|
||||
DKG_TIME_CONFIGURATION="600,300,300,60,60,1209600"
|
||||
EXIT_POLICY="https://nymtech.net/.wellknown/network-requester/exit-policy.txt"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.39"
|
||||
version = "1.1.40"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ use nym_gateway_storage::{error::StorageError, Storage};
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_task::TaskClient;
|
||||
use nym_validator_client::coconut::EcashApiError;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use rand::{random, CryptoRng, Rng};
|
||||
use std::{process, time::Duration};
|
||||
use thiserror::Error;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
@@ -217,11 +217,7 @@ where
|
||||
enc_credential: Vec<u8>,
|
||||
iv: Vec<u8>,
|
||||
) -> Result<ServerResponse, RequestHandlingError> {
|
||||
// TODO: change it into a span field instead once we move to tracing
|
||||
debug!(
|
||||
"handling e-cash bandwidth request from {}",
|
||||
self.client.address
|
||||
);
|
||||
debug!("handling e-cash bandwidth request");
|
||||
|
||||
let credential = ClientControlRequest::try_from_enc_ecash_credential(
|
||||
enc_credential,
|
||||
@@ -234,7 +230,11 @@ where
|
||||
self.bandwidth_storage_manager.clone(),
|
||||
);
|
||||
|
||||
let available_total = verifier.verify().await?;
|
||||
let available_total = verifier
|
||||
.verify()
|
||||
.await
|
||||
.inspect_err(|verification_failure| debug!("{verification_failure}"))?;
|
||||
trace!("available total bandwidth: {available_total}");
|
||||
|
||||
Ok(ServerResponse::Bandwidth { available_total })
|
||||
}
|
||||
@@ -297,40 +297,43 @@ where
|
||||
/// * `raw_request`: raw message to handle.
|
||||
async fn handle_text(&mut self, raw_request: String) -> Message {
|
||||
trace!("text request");
|
||||
match ClientControlRequest::try_from(raw_request) {
|
||||
Err(e) => RequestHandlingError::InvalidTextRequest(e).into_error_message(),
|
||||
Ok(request) => match request {
|
||||
ClientControlRequest::EcashCredential { enc_credential, iv } => self
|
||||
.handle_ecash_bandwidth(enc_credential, iv)
|
||||
.await
|
||||
.into_ws_message(),
|
||||
ClientControlRequest::BandwidthCredential { .. } => {
|
||||
RequestHandlingError::IllegalRequest {
|
||||
additional_context: "coconut credential are not longer supported".into(),
|
||||
}
|
||||
.into_error_message()
|
||||
}
|
||||
ClientControlRequest::BandwidthCredentialV2 { .. } => {
|
||||
RequestHandlingError::IllegalRequest {
|
||||
additional_context: "coconut credential are not longer supported".into(),
|
||||
}
|
||||
.into_error_message()
|
||||
}
|
||||
ClientControlRequest::ClaimFreeTestnetBandwidth => self
|
||||
.bandwidth_storage_manager
|
||||
.handle_claim_testnet_bandwidth()
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
.into_ws_message(),
|
||||
other => RequestHandlingError::IllegalRequest {
|
||||
additional_context: format!(
|
||||
"received illegal message of type {} in an authenticated client",
|
||||
other.name()
|
||||
),
|
||||
}
|
||||
.into_error_message(),
|
||||
},
|
||||
|
||||
let request = match ClientControlRequest::try_from(raw_request) {
|
||||
Ok(req) => {
|
||||
debug!("received request of type {}", req.name());
|
||||
req
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("request was malformed: {err}");
|
||||
return RequestHandlingError::InvalidTextRequest(err).into_error_message();
|
||||
}
|
||||
};
|
||||
|
||||
match request {
|
||||
ClientControlRequest::EcashCredential { enc_credential, iv } => {
|
||||
self.handle_ecash_bandwidth(enc_credential, iv).await
|
||||
}
|
||||
ClientControlRequest::BandwidthCredential { .. }
|
||||
| ClientControlRequest::BandwidthCredentialV2 { .. } => {
|
||||
Err(RequestHandlingError::IllegalRequest {
|
||||
additional_context: "coconut credential are not longer supported".into(),
|
||||
})
|
||||
}
|
||||
ClientControlRequest::ClaimFreeTestnetBandwidth => self
|
||||
.bandwidth_storage_manager
|
||||
.handle_claim_testnet_bandwidth()
|
||||
.await
|
||||
.map_err(|e| e.into()),
|
||||
other => Err(RequestHandlingError::IllegalRequest {
|
||||
additional_context: format!(
|
||||
"received illegal message of type {} in an authenticated client",
|
||||
other.name()
|
||||
),
|
||||
}),
|
||||
}
|
||||
.inspect(|res| debug!(response = ?res, "success"))
|
||||
.inspect_err(|err| debug!(error = %err, "failure"))
|
||||
.into_ws_message()
|
||||
}
|
||||
|
||||
/// Handles pong message received from the client.
|
||||
@@ -364,12 +367,13 @@ where
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `raw_request`: raw received websocket message.
|
||||
#[instrument(level = "debug", skip_all,
|
||||
fields(
|
||||
client = %self.client.address.as_base58_string()
|
||||
)
|
||||
)]
|
||||
async fn handle_request(&mut self, raw_request: Message) -> Option<Message> {
|
||||
// TODO: this should be added via tracing
|
||||
debug!(
|
||||
"handling request from {}",
|
||||
self.client.address.as_base58_string()
|
||||
);
|
||||
trace!("new request");
|
||||
|
||||
// apparently tungstenite auto-handles ping/pong/close messages so for now let's ignore
|
||||
// them and let's test that claim. If that's not the case, just copy code from
|
||||
@@ -390,8 +394,8 @@ where
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
{
|
||||
let tag: u64 = rand::thread_rng().gen();
|
||||
debug!("Got request to ping our connection: {}", tag);
|
||||
let tag: u64 = random();
|
||||
debug!("got request to ping our connection: {tag}");
|
||||
self.inner
|
||||
.send_websocket_message(Message::Ping(tag.to_be_bytes().to_vec()))
|
||||
.await?;
|
||||
|
||||
@@ -419,7 +419,7 @@ where
|
||||
// we can't handle clients with higher protocol than ours
|
||||
// (perhaps we could try to negotiate downgrade on our end? sounds like a nice future improvement)
|
||||
if client_protocol_version <= CURRENT_PROTOCOL_VERSION {
|
||||
info!("the client is using exactly the same (or older) protocol version as we are. We're good to continue!");
|
||||
debug!("the client is using exactly the same (or older) protocol version as we are. We're good to continue!");
|
||||
Ok(CURRENT_PROTOCOL_VERSION)
|
||||
} else {
|
||||
let err = InitialAuthenticationError::IncompatibleProtocol {
|
||||
@@ -570,11 +570,7 @@ where
|
||||
return Ok(InitialAuthResult::new_failed(Some(negotiated_protocol)));
|
||||
};
|
||||
|
||||
let client_id = self
|
||||
.shared_state
|
||||
.storage
|
||||
.get_mixnet_client_id(address)
|
||||
.await?;
|
||||
let client_id = self.shared_state.storage.get_client_id(address).await?;
|
||||
|
||||
let available_bandwidth: AvailableBandwidth = self
|
||||
.shared_state
|
||||
|
||||
@@ -102,7 +102,7 @@ where
|
||||
.await
|
||||
{
|
||||
Err(timeout_err) => {
|
||||
warn!("websocket handshake timedout: {timeout_err}");
|
||||
warn!("websocket handshake timed out: {timeout_err}");
|
||||
return;
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-api"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.43"
|
||||
version = "1.1.44"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node"
|
||||
version = "1.1.7"
|
||||
version = "1.1.8"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
Generated
+8
-14
@@ -2209,12 +2209,6 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
@@ -3201,7 +3195,7 @@ dependencies = [
|
||||
"nym-network-defaults",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"strum 0.26.3",
|
||||
"strum 0.25.0",
|
||||
"thiserror",
|
||||
"time",
|
||||
]
|
||||
@@ -3409,7 +3403,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"strum 0.26.3",
|
||||
"strum 0.25.0",
|
||||
"thiserror",
|
||||
"ts-rs",
|
||||
"url",
|
||||
@@ -5194,11 +5188,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||
dependencies = [
|
||||
"strum_macros 0.26.4",
|
||||
"strum_macros 0.25.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5216,11 +5210,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-network-requester"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.41"
|
||||
version = "1.1.42"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version = "1.70"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-cli"
|
||||
version = "1.1.41"
|
||||
version = "1.1.42"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nymvisor"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
Reference in New Issue
Block a user