Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a19a6e3348 | |||
| e9135d54fc | |||
| 32f1ebebf9 | |||
| 12f7f7b669 | |||
| f3f75ae751 | |||
| 20c1717a65 | |||
| 6ae78d9f4d | |||
| afb2467afc | |||
| 44a7df511a | |||
| c89ca8075f | |||
| 5f9f4fb1ab | |||
| 75e146c301 | |||
| 2ed1a0000b | |||
| ee138fe751 | |||
| 6b988e591d | |||
| 6cc12a4aad | |||
| e1398f4422 | |||
| 20b0be351d | |||
| af824b7043 | |||
| d32332a82e | |||
| 5e8f402c5d | |||
| ad4ae0d00d | |||
| aed16fcacd | |||
| 14f983c481 | |||
| 587e2f4b53 | |||
| 4d8348b304 | |||
| 750df1e0bd | |||
| 94614e9d90 | |||
| 002055cb9f | |||
| a117d9089b | |||
| ed8ca4e4ea | |||
| 587f6bf8a8 | |||
| 55a7f67407 | |||
| e5c88e30b4 | |||
| dd4945e269 | |||
| 0adeb6e677 | |||
| b7b399d71c | |||
| 65b5c258e8 | |||
| da1463924f | |||
| 749ceec727 | |||
| c639a7e1c1 | |||
| e0876a6238 | |||
| 89f5ab11a5 | |||
| 4063071e08 | |||
| 99a0f4ea30 | |||
| dfa969d754 | |||
| 428dd0543f | |||
| b90088148c | |||
| 08a45c188d | |||
| 806e8629fe | |||
| c22bb99da6 | |||
| 91ee54e5a7 | |||
| 572fc331b0 | |||
| c5590bddc5 | |||
| c9aed048d0 | |||
| b8f7d54f18 | |||
| c04e173ee6 | |||
| 34143f1d58 | |||
| 47b88737e6 | |||
| 76ddef285c | |||
| 89fe17f19c | |||
| 57d2824521 | |||
| b8058dd7ba | |||
| 95d08c7f21 | |||
| a29df08463 | |||
| 6a028417ad | |||
| 4cd4dc2d1c | |||
| 983cba21ba | |||
| eeb0278d13 | |||
| 8d28016e08 | |||
| fb0b55d540 | |||
| 1bb973e4a7 | |||
| aa1cad4422 |
@@ -17,7 +17,7 @@ jobs:
|
||||
build:
|
||||
# since it's going to be compiled into wasm, there's absolutely
|
||||
# no point in running CI on different OS-es
|
||||
runs-on: arc-linux-latest
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_PERMIT_COPY_RENAME: 1
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: arc-linux-latest
|
||||
- os: arc-ubuntu-22.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -30,13 +30,11 @@ jobs:
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
|
||||
nymvisor_hash: ${{ steps.binary-hashes.outputs.nymvisor_hash }}
|
||||
nymnode_hash: ${{ steps.binary-hashes.outputs.nymnode_hash }}
|
||||
socks5_hash: ${{ steps.binary-hashes.outputs.socks5_hash }}
|
||||
netreq_hash: ${{ steps.binary-hashes.outputs.netreq_hash }}
|
||||
cli_hash: ${{ steps.binary-hashes.outputs.cli_hash }}
|
||||
client_version: ${{ steps.binary-versions.outputs.client_version }}
|
||||
nymvisor_version: ${{ steps.binary-versions.outputs.nymvisor_version }}
|
||||
nymnode_version: ${{ steps.binary-versions.outputs.nymnode_version }}
|
||||
socks5_version: ${{ steps.binary-versions.outputs.socks5_version }}
|
||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
@@ -76,7 +74,6 @@ jobs:
|
||||
target/release/nym-network-requester
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
retention-days: 30
|
||||
|
||||
- id: create-release
|
||||
@@ -91,7 +88,6 @@ jobs:
|
||||
target/release/nym-network-requester
|
||||
target/release/nym-cli
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
|
||||
push-release-data-client:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
@@ -8,7 +8,7 @@ env:
|
||||
|
||||
jobs:
|
||||
build-container:
|
||||
runs-on: arc-linux-latest-dind
|
||||
runs-on: arc-ubuntu-22.04-dind
|
||||
steps:
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v3
|
||||
|
||||
@@ -69,6 +69,6 @@ jobs:
|
||||
|
||||
- name: BuildAndPushImageOnHarbor
|
||||
run: |
|
||||
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile-pg . -t harbor.nymte.ch/nym/${{ env.IMAGE_NAME_AND_TAGS }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
|
||||
docker build -f ${{ env.WORKING_DIRECTORY }}/Dockerfile . -t harbor.nymte.ch/nym/${{ env.IMAGE_NAME_AND_TAGS }} -t harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }}:latest
|
||||
docker push harbor.nymte.ch/nym/${{ env.CONTAINER_NAME }} --all-tags
|
||||
|
||||
|
||||
@@ -4,84 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.17-isabirra] (2025-09-29)
|
||||
|
||||
- Bugfix | Fix the registration handshake ([#6062])
|
||||
- Convenience for ShutdownTracker ([#6038])
|
||||
- chore: made http-api-client-macro doctest compile ([#6037])
|
||||
- feat: refresh mixnet contract on epoch progression ([#6023])
|
||||
- chore: remove legacy nodes from nym api [and kinda-ish from node status api] ([#6021])
|
||||
- Feature/credential proxy crate ([#6018])
|
||||
- Moving clients crate from vpn-client repo to here ([#6015])
|
||||
- Feature/cancellation migration ([#6014])
|
||||
- Use default value for the ports until api is deployed ([#6007])
|
||||
- bugfix: return from MixTrafficController if client request channel has closed ([#6002])
|
||||
- Revert "Create an axum_test client for more integrated unit testing (… ([#5999])
|
||||
- chore: upgraded syn to 2.0 and removed nym-execute ([#5998])
|
||||
- feat: use `ShutdownToken` (`CancellationToken` inside) for nym-api ([#5997])
|
||||
- bugfix: Recipient deserialisation for deserialisers missing bytes specialisation ([#5991])
|
||||
- chore: use updated version of simulate endpoint ([#5988])
|
||||
- chore: purge temp databases on build ([#5984])
|
||||
- Bump sha.js from 2.4.11 to 2.4.12 ([#5983])
|
||||
- Feature: Delegation program stake checker and adjuster ([#5980])
|
||||
- build(deps): bump actions/setup-java from 4 to 5 ([#5975])
|
||||
- Domain fronting integration ([#5974])
|
||||
- chore: internal hidden command to force advance nyx epoch ([#5964])
|
||||
- Create an axum_test client for more integrated unit testing ([#5956])
|
||||
- feat: shared library for attempting to retrieve update mode attestation ([#5954])
|
||||
- Bump slab from 0.4.10 to 0.4.11 ([#5952])
|
||||
- build(deps): bump actions/first-interaction from 1 to 3 ([#5950])
|
||||
- fix: use WASM compatible time API in client ([#5948])
|
||||
- feat: credential proxy deposit pool ([#5945])
|
||||
- build(deps): bump actions/download-artifact from 4 to 5 ([#5939])
|
||||
- feat: nym signers monitor ([#5933])
|
||||
- Bump console from 0.15.11 to 0.16.0 ([#5931])
|
||||
- Bump mock_instant from 0.5.3 to 0.6.0 ([#5930])
|
||||
- Bump tokio from 1.46.1 to 1.47.1 ([#5929])
|
||||
- Bump defguard_wireguard_rs from v0.4.7 to v0.7.5 ([#5928])
|
||||
- Bump indicatif from 0.17.11 to 0.18.0 ([#5924])
|
||||
- Feature: Nym node autorun CLI ([#5916])
|
||||
- build(deps): bump mikefarah/yq from 4.45.4 to 4.47.1 ([#5911])
|
||||
- build(deps): bump pbkdf2 from 3.1.2 to 3.1.3 ([#5869])
|
||||
|
||||
[#6062]: https://github.com/nymtech/nym/pull/6062
|
||||
[#6038]: https://github.com/nymtech/nym/pull/6038
|
||||
[#6037]: https://github.com/nymtech/nym/pull/6037
|
||||
[#6023]: https://github.com/nymtech/nym/pull/6023
|
||||
[#6021]: https://github.com/nymtech/nym/pull/6021
|
||||
[#6018]: https://github.com/nymtech/nym/pull/6018
|
||||
[#6015]: https://github.com/nymtech/nym/pull/6015
|
||||
[#6014]: https://github.com/nymtech/nym/pull/6014
|
||||
[#6007]: https://github.com/nymtech/nym/pull/6007
|
||||
[#6002]: https://github.com/nymtech/nym/pull/6002
|
||||
[#5999]: https://github.com/nymtech/nym/pull/5999
|
||||
[#5998]: https://github.com/nymtech/nym/pull/5998
|
||||
[#5997]: https://github.com/nymtech/nym/pull/5997
|
||||
[#5991]: https://github.com/nymtech/nym/pull/5991
|
||||
[#5988]: https://github.com/nymtech/nym/pull/5988
|
||||
[#5984]: https://github.com/nymtech/nym/pull/5984
|
||||
[#5983]: https://github.com/nymtech/nym/pull/5983
|
||||
[#5980]: https://github.com/nymtech/nym/pull/5980
|
||||
[#5975]: https://github.com/nymtech/nym/pull/5975
|
||||
[#5974]: https://github.com/nymtech/nym/pull/5974
|
||||
[#5964]: https://github.com/nymtech/nym/pull/5964
|
||||
[#5956]: https://github.com/nymtech/nym/pull/5956
|
||||
[#5954]: https://github.com/nymtech/nym/pull/5954
|
||||
[#5952]: https://github.com/nymtech/nym/pull/5952
|
||||
[#5950]: https://github.com/nymtech/nym/pull/5950
|
||||
[#5948]: https://github.com/nymtech/nym/pull/5948
|
||||
[#5945]: https://github.com/nymtech/nym/pull/5945
|
||||
[#5939]: https://github.com/nymtech/nym/pull/5939
|
||||
[#5933]: https://github.com/nymtech/nym/pull/5933
|
||||
[#5931]: https://github.com/nymtech/nym/pull/5931
|
||||
[#5930]: https://github.com/nymtech/nym/pull/5930
|
||||
[#5929]: https://github.com/nymtech/nym/pull/5929
|
||||
[#5928]: https://github.com/nymtech/nym/pull/5928
|
||||
[#5924]: https://github.com/nymtech/nym/pull/5924
|
||||
[#5916]: https://github.com/nymtech/nym/pull/5916
|
||||
[#5911]: https://github.com/nymtech/nym/pull/5911
|
||||
[#5869]: https://github.com/nymtech/nym/pull/5869
|
||||
|
||||
## [2025.16-halloumi] (2025-09-16)
|
||||
|
||||
- Backport metadata endpoint ([#6010])
|
||||
|
||||
Generated
+890
-938
File diff suppressed because it is too large
Load Diff
+8
-3
@@ -292,8 +292,11 @@ nix = "0.27.1"
|
||||
notify = "5.1.0"
|
||||
okapi = "0.7.0"
|
||||
once_cell = "1.21.3"
|
||||
opentelemetry = "0.19.0"
|
||||
opentelemetry-jaeger = "0.18.0"
|
||||
opentelemetry = "0.30.0"
|
||||
opentelemetry-otlp = "0.30.0"
|
||||
opentelemetry-semantic-conventions = "0.30.0"
|
||||
opentelemetry_sdk = "0.30.0"
|
||||
opentelemetry-stdout = "0.30.0"
|
||||
parking_lot = "0.12.3"
|
||||
pem = "0.8"
|
||||
petgraph = "0.6.5"
|
||||
@@ -351,8 +354,10 @@ toml = "0.8.22"
|
||||
tower = "0.5.2"
|
||||
tower-http = "0.5.2"
|
||||
tracing = "0.1.41"
|
||||
tracing-core = "0.1.33"
|
||||
tracing-log = "0.2"
|
||||
tracing-opentelemetry = "0.19.0"
|
||||
tracing-opentelemetry = "0.31.0"
|
||||
tracing-serde = "0.2.0"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-tree = "0.2.2"
|
||||
tracing-indicatif = "0.3.9"
|
||||
|
||||
@@ -46,7 +46,6 @@ nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
"basic_tracing",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_tracing_logger};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_no_otel_logger};
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
pub mod client;
|
||||
@@ -20,7 +20,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
if !args.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
setup_tracing_logger();
|
||||
setup_no_otel_logger().expect("failed to initialize logging");
|
||||
|
||||
if let Err(err) = commands::execute(args).await {
|
||||
log::error!("{err}");
|
||||
|
||||
@@ -184,7 +184,7 @@ impl Handler {
|
||||
});
|
||||
|
||||
// the ack control is now responsible for chunking, etc.
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type, None);
|
||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||
if !self.shutdown_token.is_cancelled() {
|
||||
error!("Failed to send message to the input buffer: {err}");
|
||||
@@ -217,7 +217,7 @@ impl Handler {
|
||||
});
|
||||
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type, None);
|
||||
if let Err(err) = self.msg_input.send(input_msg).await {
|
||||
if !self.shutdown_token.is_cancelled() {
|
||||
error!("Failed to send anonymous message to the input buffer: {err}");
|
||||
|
||||
@@ -27,7 +27,6 @@ zeroize = { workspace = true }
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"output_format",
|
||||
"clap",
|
||||
"basic_tracing",
|
||||
] }
|
||||
nym-client-core = { path = "../../common/client-core", features = [
|
||||
"fs-credentials-storage",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::error::Error;
|
||||
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_tracing_logger};
|
||||
use nym_bin_common::logging::{maybe_print_banner, setup_no_otel_logger};
|
||||
use nym_network_defaults::setup_env;
|
||||
|
||||
mod commands;
|
||||
@@ -19,7 +19,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
if !args.no_banner {
|
||||
maybe_print_banner(crate_name!(), crate_version!());
|
||||
}
|
||||
setup_tracing_logger();
|
||||
setup_no_otel_logger().expect("failed to initialize logging");
|
||||
|
||||
if let Err(err) = commands::execute(args).await {
|
||||
log::error!("{err}");
|
||||
|
||||
@@ -8,24 +8,30 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace = true, optional = true }
|
||||
cfg-if = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"], optional = true }
|
||||
clap_complete = { workspace = true, optional = true }
|
||||
clap_complete_fig = { workspace = true, optional = true }
|
||||
const-str = { workspace = true }
|
||||
log = { workspace = true }
|
||||
opentelemetry = { workspace = true, optional = true }
|
||||
opentelemetry-otlp = { workspace = true,features=["metrics", "grpc-tonic", "tls",
|
||||
"tls-webpki-roots"], optional = true }
|
||||
opentelemetry-semantic-conventions = { workspace = true, features = ["semconv_experimental"], optional = true }
|
||||
opentelemetry-stdout = { workspace = true, features = ["trace", "metrics"], optional = true }
|
||||
opentelemetry_sdk = { workspace = true, optional = true }
|
||||
rand = { workspace = true, optional = true }
|
||||
schemars = { workspace = true, features = ["preserve_order"], optional = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
|
||||
## tracing
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true }
|
||||
tracing-tree = { workspace = true, optional = true }
|
||||
tracing = { workspace = true, optional = true }
|
||||
opentelemetry-jaeger = { workspace = true, features = ["rt-tokio", "collector_client", "isahc_collector_client"], optional = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tracing-core = { workspace = true }
|
||||
tracing-opentelemetry = { workspace = true, optional = true }
|
||||
tracing-serde = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
|
||||
tracing-tree = { workspace = true }
|
||||
utoipa = { workspace = true, optional = true }
|
||||
opentelemetry = { workspace = true, features = ["rt-tokio"], optional = true }
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
|
||||
@@ -35,13 +41,17 @@ default = []
|
||||
openapi = ["utoipa"]
|
||||
output_format = ["serde_json", "dep:clap"]
|
||||
bin_info_schema = ["schemars"]
|
||||
basic_tracing = ["dep:tracing", "tracing-subscriber"]
|
||||
tracing = [
|
||||
"basic_tracing",
|
||||
"tracing-tree",
|
||||
"opentelemetry-jaeger",
|
||||
tokio-console = ["otel"]
|
||||
otel = [
|
||||
"chrono",
|
||||
"tracing-opentelemetry",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"opentelemetry-stdout",
|
||||
"opentelemetry_sdk",
|
||||
"serde_json",
|
||||
"rand",
|
||||
]
|
||||
clap = ["dep:clap", "dep:clap_complete", "dep:clap_complete_fig"]
|
||||
models = []
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
pub mod build_information;
|
||||
pub mod logging;
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
pub mod opentelemetry;
|
||||
|
||||
#[cfg(feature = "clap")]
|
||||
pub mod completions;
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#[cfg(feature = "otel")]
|
||||
use opentelemetry_otlp::ExporterBuildError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum TracingError {
|
||||
#[error("tracing logger already initialised")]
|
||||
TracingLoggerAlreadyInitialised,
|
||||
|
||||
#[error("Logging error: {0}")]
|
||||
TracingTryInitError(tracing_subscriber::util::TryInitError),
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
#[error("{0}")]
|
||||
TracingExporterBuildError(#[from] ExporterBuildError),
|
||||
|
||||
#[error("{0}")]
|
||||
TracingFilterParseError(#[from] tracing_subscriber::filter::ParseError),
|
||||
}
|
||||
@@ -1,19 +1,12 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod error;
|
||||
|
||||
use error::TracingError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::IsTerminal;
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use opentelemetry;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use opentelemetry_jaeger;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_opentelemetry;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_subscriber;
|
||||
#[cfg(feature = "tracing")]
|
||||
pub use tracing_tree;
|
||||
use tracing_subscriber::{filter::Directive, layer::SubscriberExt, util::SubscriberInitExt};
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
@@ -22,7 +15,6 @@ pub struct LoggingSettings {
|
||||
}
|
||||
|
||||
// don't call init so that we could attach additional layers
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
@@ -31,7 +23,6 @@ pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
|
||||
.with(default_tracing_env_filter())
|
||||
}
|
||||
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
||||
if ::std::env::var("RUST_LOG").is_ok() {
|
||||
tracing_subscriber::filter::EnvFilter::from_default_env()
|
||||
@@ -43,7 +34,6 @@ pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn default_tracing_fmt_layer<S, W>(
|
||||
writer: W,
|
||||
) -> impl tracing_subscriber::Layer<S> + Sync + Send + 'static
|
||||
@@ -63,45 +53,47 @@ where
|
||||
.with_target(false)
|
||||
}
|
||||
|
||||
#[cfg(feature = "basic_tracing")]
|
||||
pub fn setup_tracing_logger() {
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
build_tracing_logger().init()
|
||||
/// Creates a tracing filter that sets more granular log levels for specific crates.
|
||||
/// This allows for finer control over logging verbosity.
|
||||
pub(crate) fn granual_filtered_env() -> Result<tracing_subscriber::filter::EnvFilter, TracingError>
|
||||
{
|
||||
fn directive_checked(directive: impl Into<String>) -> Result<Directive, TracingError> {
|
||||
directive.into().parse().map_err(From::from)
|
||||
}
|
||||
|
||||
let mut filter = default_tracing_env_filter();
|
||||
|
||||
// these crates are more granularly filtered
|
||||
let filter_crates = ["defguard_wireguard_rs"];
|
||||
for crate_name in filter_crates {
|
||||
filter = filter.add_directive(directive_checked(format!("{crate_name}=warn"))?);
|
||||
}
|
||||
Ok(filter)
|
||||
}
|
||||
|
||||
pub fn setup_no_otel_logger() -> Result<(), TracingError> {
|
||||
// Only set up if not already initialized
|
||||
if tracing::dispatcher::has_been_set() {
|
||||
// It shouldn't be - this is really checking that it is torn down between async command executions
|
||||
return Err(TracingError::TracingLoggerAlreadyInitialised);
|
||||
}
|
||||
|
||||
let registry = tracing_subscriber::registry()
|
||||
.with(default_tracing_fmt_layer(std::io::stderr))
|
||||
.with(granual_filtered_env()?);
|
||||
|
||||
registry
|
||||
.try_init()
|
||||
.map_err(|e| TracingError::TracingTryInitError(e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: This has to be a macro, running it as a function does not work for the file_appender for some reason
|
||||
#[cfg(feature = "tracing")]
|
||||
#[macro_export]
|
||||
macro_rules! setup_tracing {
|
||||
($service_name: expr) => {
|
||||
use nym_bin_common::logging::tracing_subscriber::layer::SubscriberExt;
|
||||
use nym_bin_common::logging::tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
let registry = nym_bin_common::logging::tracing_subscriber::Registry::default()
|
||||
.with(nym_bin_common::logging::tracing_subscriber::EnvFilter::from_default_env())
|
||||
.with(
|
||||
nym_bin_common::logging::tracing_tree::HierarchicalLayer::new(4)
|
||||
.with_targets(true)
|
||||
.with_bracketed_fields(true),
|
||||
);
|
||||
|
||||
let tracer = nym_bin_common::logging::opentelemetry_jaeger::new_collector_pipeline()
|
||||
.with_endpoint("http://44.199.230.10:14268/api/traces")
|
||||
.with_service_name($service_name)
|
||||
.with_isahc()
|
||||
.with_trace_config(
|
||||
nym_bin_common::logging::opentelemetry::sdk::trace::config().with_sampler(
|
||||
nym_bin_common::logging::opentelemetry::sdk::trace::Sampler::TraceIdRatioBased(
|
||||
0.1,
|
||||
),
|
||||
),
|
||||
)
|
||||
.install_batch(nym_bin_common::logging::opentelemetry::runtime::Tokio)
|
||||
.expect("Could not init tracer");
|
||||
|
||||
let telemetry = nym_bin_common::logging::tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
registry.with(telemetry).init();
|
||||
setup_no_otel_logger()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use opentelemetry_sdk::trace::IdGenerator;
|
||||
use opentelemetry::trace::{TraceId, SpanId};
|
||||
use rand::RngCore;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Compact13BytesIdGenerator;
|
||||
|
||||
impl IdGenerator for Compact13BytesIdGenerator {
|
||||
fn new_trace_id(&self) -> TraceId {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut bytes = [0u8; 16];
|
||||
|
||||
// Fill the first 13 bytes with random data
|
||||
rng.fill_bytes(&mut bytes[0..12]);
|
||||
// Set the last 4 bytes to zero
|
||||
bytes[12] = 0;
|
||||
bytes[13] = 0;
|
||||
bytes[14] = 0;
|
||||
bytes[15] = 0;
|
||||
|
||||
TraceId::from_bytes(bytes)
|
||||
}
|
||||
|
||||
fn new_span_id(&self) -> SpanId {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut bytes = [0u8; 8];
|
||||
rng.fill_bytes(&mut bytes);
|
||||
|
||||
SpanId::from_bytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compress_trace_id(trace_id: &TraceId) -> [u8; 12] {
|
||||
let bytes = trace_id.to_bytes();
|
||||
|
||||
let mut compressed = [0u8; 12];
|
||||
compressed.copy_from_slice(&bytes[0..12]);
|
||||
|
||||
compressed
|
||||
}
|
||||
|
||||
pub fn decompress_trace_id(compressed: &[u8; 12]) -> [u8; 16] {
|
||||
let mut bytes = [0u8; 16];
|
||||
bytes[0..12].copy_from_slice(compressed);
|
||||
bytes[12..].copy_from_slice(&[0u8; 4]);
|
||||
bytes
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
use opentelemetry::{Context, TraceFlags};
|
||||
use opentelemetry::propagation::{Injector, Extractor, TextMapPropagator};
|
||||
use opentelemetry::trace::{SpanContext, TraceContextExt, TraceId};
|
||||
use opentelemetry_sdk::{propagation::TraceContextPropagator, trace::IdGenerator};
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use tracing::instrument;
|
||||
|
||||
/// Make a Carrier for context propagation
|
||||
pub struct ContextCarrier {
|
||||
data: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl ContextCarrier {
|
||||
pub fn new_empty() -> Self {
|
||||
ContextCarrier {
|
||||
data: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_data(data: HashMap<String, String>) -> Self {
|
||||
if data.is_empty() {
|
||||
return ContextCarrier::new_empty();
|
||||
}
|
||||
|
||||
ContextCarrier { data }
|
||||
}
|
||||
|
||||
pub fn new_with_current_context(context: Context) -> Self {
|
||||
let mut carrier = ContextCarrier::new_empty();
|
||||
let propagator = TraceContextPropagator::new();
|
||||
propagator.inject_context(&context, &mut carrier);
|
||||
carrier
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
|
||||
self.data.iter()
|
||||
}
|
||||
|
||||
pub fn from_map(data: HashMap<String, String>) -> Self {
|
||||
ContextCarrier { data }
|
||||
}
|
||||
|
||||
pub fn into_map(self) -> HashMap<String, String> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn extract_trace_id(&self) -> Option<TraceId> {
|
||||
self.get("traceparent").and_then(|tp| {
|
||||
let parts: Vec<&str> = tp.split('-').collect();
|
||||
if parts.len() == 4 {
|
||||
TraceId::from_hex(parts[1]).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn extract_trace_id_into_bytes(&self) -> Option<[u8; 16]> {
|
||||
self.extract_trace_id().map(|id| id.to_bytes())
|
||||
}
|
||||
|
||||
pub fn extract_traceparent(&self) -> Option<String> {
|
||||
self.get("traceparent").map(|s| s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Injector for ContextCarrier {
|
||||
fn set(&mut self, key: &str, value: String) {
|
||||
self.data.insert(key.to_string(), value);
|
||||
}
|
||||
}
|
||||
|
||||
impl Extractor for ContextCarrier {
|
||||
fn get(&self, key: &str) -> Option<&str> {
|
||||
self.data.get(key).map(|s| s.as_str())
|
||||
}
|
||||
|
||||
fn keys(&self) -> Vec<&str> {
|
||||
self.data.keys().map(|k| k.as_str()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ContextCarrier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self.data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ManualContextPropagator {
|
||||
pub root_span: tracing::Span,
|
||||
pub trace_id: TraceId,
|
||||
}
|
||||
|
||||
impl ManualContextPropagator {
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
pub fn new(name: &str, context: HashMap<String, String>) -> Self {
|
||||
let carrier = ContextCarrier::new_with_data(context);
|
||||
let trace_id = match carrier.extract_trace_id() {
|
||||
Some(id) => id,
|
||||
None => Context::current().span().span_context().trace_id(),
|
||||
};
|
||||
|
||||
let root_span_builder = new_span_context_with_id(trace_id.clone());
|
||||
|
||||
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
|
||||
root_span.set_parent(root_span_builder);
|
||||
|
||||
ManualContextPropagator {
|
||||
root_span,
|
||||
trace_id,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
pub fn new_from_tid(name: &str, trace_id: TraceId) -> Self {
|
||||
let root_span_builder = new_span_context_with_id(trace_id.clone());
|
||||
|
||||
let root_span = tracing::info_span!("trace_root", name = %name, trace_id = %trace_id);
|
||||
root_span.set_parent(root_span_builder);
|
||||
|
||||
ManualContextPropagator {
|
||||
root_span,
|
||||
trace_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_span(&self) -> &tracing::Span {
|
||||
&self.root_span
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
pub fn new_span_context_with_id(trace_id: TraceId) -> Context {
|
||||
let id_gen = opentelemetry_sdk::trace::RandomIdGenerator::default();
|
||||
let span_id = id_gen.new_span_id();
|
||||
let span_context = SpanContext::new(
|
||||
trace_id,
|
||||
span_id,
|
||||
TraceFlags::SAMPLED,
|
||||
true,
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
Context::current().with_remote_span_context(span_context)
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
pub fn extract_trace_id_from_tracing_cx() -> TraceId {
|
||||
let cx = tracing::Span::current().context();
|
||||
let binding = cx.span();
|
||||
let trace_id = binding.span_context().trace_id();
|
||||
trace_id
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
pub mod context;
|
||||
pub mod compact_id_generator;
|
||||
mod trace_id_format;
|
||||
|
||||
use tracing::{info, Level};
|
||||
use tracing_subscriber::filter::Directive;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::fmt;
|
||||
|
||||
use crate::logging::default_tracing_env_filter;
|
||||
use crate::logging::error::TracingError;
|
||||
use crate::opentelemetry::compact_id_generator::Compact13BytesIdGenerator;
|
||||
use opentelemetry::trace::TracerProvider;
|
||||
use opentelemetry::{global, KeyValue};
|
||||
use opentelemetry_otlp::tonic_types::metadata::MetadataMap;
|
||||
use opentelemetry_otlp::tonic_types::transport::ClientTlsConfig;
|
||||
use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
|
||||
use opentelemetry_sdk::metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider};
|
||||
use opentelemetry_sdk::trace::SdkTracerProvider;
|
||||
use opentelemetry_sdk::{trace::Sampler, Resource};
|
||||
use opentelemetry_semantic_conventions::resource::{DEPLOYMENT_ENVIRONMENT_NAME, SERVICE_VERSION};
|
||||
use opentelemetry_semantic_conventions::SCHEMA_URL;
|
||||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
||||
use tracing_subscriber::fmt::format::FmtSpan;
|
||||
|
||||
pub struct TracerProviderGuard(Option<SdkTracerProvider>);
|
||||
|
||||
impl Drop for TracerProviderGuard {
|
||||
fn drop(&mut self) {
|
||||
if let Some(tracer_provider) = self.0.take() {
|
||||
// Ensure all spans are flushed before exit
|
||||
if let Err(e) = tracer_provider.shutdown() {
|
||||
eprintln!("Error shutting down tracer provider: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn granual_filtered_env() -> Result<tracing_subscriber::filter::EnvFilter, TracingError>
|
||||
{
|
||||
fn directive_checked(directive: impl Into<String>) -> Result<Directive, TracingError> {
|
||||
directive.into().parse().map_err(From::from)
|
||||
}
|
||||
|
||||
let mut filter = default_tracing_env_filter();
|
||||
|
||||
// these crates are more granularly filtered
|
||||
let filter_crates = ["defguard_wireguard_rs"];
|
||||
for crate_name in filter_crates {
|
||||
filter = filter.add_directive(directive_checked(format!("{crate_name}=warn"))?);
|
||||
}
|
||||
Ok(filter)
|
||||
}
|
||||
|
||||
pub fn setup_tracing_logger(service_name: String) -> Result<TracerProviderGuard, TracingError> {
|
||||
if tracing::dispatcher::has_been_set() {
|
||||
// It shouldn't be - this is really checking that it is torn down between async command executions
|
||||
return Err(TracingError::TracingLoggerAlreadyInitialised);
|
||||
}
|
||||
|
||||
// define ingestion points
|
||||
let endpoint = std::env::var("SIGNOZ_ENDPOINT").expect("SIGNOZ_ENDPOINT not set");
|
||||
let key = std::env::var("SIGNOZ_INGESTION_KEY").expect("SIGNOZ_INGESTION_KEY not set");
|
||||
let mut metadata = MetadataMap::new();
|
||||
metadata.insert(
|
||||
"signoz-ingestion-key",
|
||||
key.parse().expect("Could not parse signoz ingestion key"),
|
||||
);
|
||||
|
||||
// Build resources
|
||||
let resource = build_resource(&service_name);
|
||||
|
||||
// Initialize tracer and meter providers
|
||||
let tracer_provider = init_tracer_provider(&endpoint, metadata.clone(), resource.clone())?;
|
||||
let meter_provider = init_meter_provider(&endpoint, metadata.clone(), resource.clone())?;
|
||||
|
||||
// Bridge tracing and opentelemetry
|
||||
let tracer = tracer_provider.tracer("otel-subscriber");
|
||||
let fmt_layer = fmt::layer()
|
||||
.json()
|
||||
.with_writer(std::io::stderr)
|
||||
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||
.with_span_list(false)
|
||||
.with_current_span(true)
|
||||
.event_format(trace_id_format::TraceIdFormat);
|
||||
|
||||
let registry = tracing_subscriber::registry()
|
||||
.with(fmt_layer)
|
||||
.with(granual_filtered_env()?)
|
||||
.with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
||||
.with(MetricsLayer::new(meter_provider.clone()))
|
||||
.with(OpenTelemetryLayer::new(tracer));
|
||||
|
||||
registry.try_init().map_err(TracingError::TracingTryInitError)?;
|
||||
|
||||
global::set_tracer_provider(tracer_provider.clone());
|
||||
global::set_meter_provider(meter_provider.clone());
|
||||
|
||||
info!("Tracing initialized with service name: {}", service_name);
|
||||
|
||||
Ok(TracerProviderGuard(Some(tracer_provider)))
|
||||
}
|
||||
|
||||
fn build_resource(service_name: &str) -> Resource {
|
||||
Resource::builder()
|
||||
.with_service_name(service_name.to_string())
|
||||
.with_schema_url(
|
||||
[
|
||||
KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
|
||||
KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"),
|
||||
],
|
||||
SCHEMA_URL,
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn init_tracer_provider(
|
||||
endpoint: &str,
|
||||
metadata: MetadataMap,
|
||||
resource: Resource,
|
||||
) -> Result<SdkTracerProvider, TracingError> {
|
||||
let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.with_metadata(metadata)
|
||||
.with_endpoint(endpoint);
|
||||
|
||||
if endpoint.starts_with("https://") {
|
||||
exporter_builder =
|
||||
exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
||||
}
|
||||
|
||||
let exporter = exporter_builder.build()?;
|
||||
|
||||
let tracer = SdkTracerProvider::builder()
|
||||
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
||||
1.0,
|
||||
))))
|
||||
.with_id_generator(Compact13BytesIdGenerator)
|
||||
.with_resource(resource)
|
||||
.with_batch_exporter(exporter)
|
||||
.build();
|
||||
|
||||
global::set_tracer_provider(tracer.clone());
|
||||
Ok(tracer)
|
||||
}
|
||||
|
||||
fn init_meter_provider(
|
||||
endpoint: &str,
|
||||
metadata: MetadataMap,
|
||||
resource: Resource,
|
||||
) -> Result<SdkMeterProvider, TracingError> {
|
||||
let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
|
||||
.with_tonic()
|
||||
.with_metadata(metadata)
|
||||
.with_endpoint(endpoint)
|
||||
.with_temporality(opentelemetry_sdk::metrics::Temporality::default());
|
||||
|
||||
if endpoint.starts_with("https://") {
|
||||
exporter_builder = exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
||||
}
|
||||
|
||||
let exporter = exporter_builder.build()?;
|
||||
|
||||
let reader = PeriodicReader::builder(exporter)
|
||||
.with_interval(std::time::Duration::from_secs(30))
|
||||
.build();
|
||||
|
||||
let stdout_reader =
|
||||
PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
|
||||
|
||||
let meter_provider = MeterProviderBuilder::default()
|
||||
.with_resource(resource)
|
||||
.with_reader(reader)
|
||||
.with_reader(stdout_reader)
|
||||
.build();
|
||||
|
||||
global::set_meter_provider(meter_provider.clone());
|
||||
|
||||
Ok(meter_provider)
|
||||
}
|
||||
|
||||
// pub fn setup_tracing_logger(service_name: String) -> Result<(), TracingError> {
|
||||
// if tracing::dispatcher::has_been_set() {
|
||||
// // It shouldn't be - this is really checking that it is torn down between async command executions
|
||||
// return Err(TracingError::TracingLoggerAlreadyInitialised);
|
||||
// }
|
||||
|
||||
// let key =
|
||||
// std::env::var("SIGNOZ_INGESTION_KEY".to_string()).expect("SIGNOZ_INGESTION_KEY not set");
|
||||
// let mut metadata = MetadataMap::new();
|
||||
// metadata.insert(
|
||||
// "signoz-ingestion-key",
|
||||
// key.parse().expect("Could not parse signoz ingestion key"),
|
||||
// );
|
||||
|
||||
// let tracer_provider = init_tracer_provider(metadata.clone(), service_name.clone())?;
|
||||
// let meter_provider = init_meter_provider(metadata.clone(), service_name.clone())?;
|
||||
// let tracer = tracer_provider.tracer("tracing-otel-subscriber");
|
||||
// let fmt_layer = fmt::layer()
|
||||
// .json()
|
||||
// .with_writer(std::io::stderr)
|
||||
// .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||
// .with_span_list(false)
|
||||
// .with_current_span(true)
|
||||
// .event_format(trace_id_format::TraceIdFormat);
|
||||
|
||||
// cfg_if::cfg_if! {if #[cfg(feature = "tokio-console")] {
|
||||
// // instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
|
||||
// let console_layer = console_subscriber::spawn();
|
||||
|
||||
// tracing_subscriber::registry()
|
||||
// .with(console_layer)
|
||||
// .with(fmt_layer)
|
||||
// .with(granual_filtered_env()?)
|
||||
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
||||
// .with(MetricsLayer::new(meter_provider))
|
||||
// .with(OpenTelemetryLayer::new(tracer))
|
||||
// .try_init()
|
||||
// .map_err(|e| TracingError::TracingTryInitError(e))?;
|
||||
// } else {
|
||||
// tracing_subscriber::registry()
|
||||
// .with(fmt_layer)
|
||||
// .with(granual_filtered_env()?)
|
||||
// .with(tracing_subscriber::filter::LevelFilter::from_level(Level::INFO))
|
||||
// .with(MetricsLayer::new(meter_provider))
|
||||
// .with(OpenTelemetryLayer::new(tracer))
|
||||
// .try_init()
|
||||
// .map_err(|e| TracingError::TracingTryInitError(e))?;
|
||||
// }}
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// fn resource(service_name: String) -> Resource {
|
||||
// Resource::builder()
|
||||
// .with_service_name(service_name)
|
||||
// .with_schema_url(
|
||||
// [
|
||||
// KeyValue::new(SERVICE_VERSION, env!("CARGO_PKG_VERSION")),
|
||||
// KeyValue::new(DEPLOYMENT_ENVIRONMENT_NAME, "develop"),
|
||||
// ],
|
||||
// SCHEMA_URL,
|
||||
// )
|
||||
// .build()
|
||||
// }
|
||||
|
||||
// fn init_tracer_provider(metadata: MetadataMap, service_name: String) -> Result<SdkTracerProvider, TracingError> {
|
||||
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
|
||||
// info!("SIGNOZ_ENDPOINT = {}", endpoint);
|
||||
|
||||
// let mut exporter_builder = opentelemetry_otlp::SpanExporter::builder()
|
||||
// .with_tonic()
|
||||
// .with_metadata(metadata)
|
||||
// .with_endpoint(&endpoint);
|
||||
|
||||
// if endpoint.starts_with("https://") {
|
||||
// exporter_builder =
|
||||
// exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
||||
// }
|
||||
|
||||
// let exporter = exporter_builder.build()?;
|
||||
|
||||
// let tracer = SdkTracerProvider::builder()
|
||||
// .with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
||||
// 1.0,
|
||||
// ))))
|
||||
// .with_id_generator(Compact13BytesIdGenerator)
|
||||
// .with_resource(resource(service_name))
|
||||
// .with_batch_exporter(exporter)
|
||||
// .build();
|
||||
|
||||
// global::set_tracer_provider(tracer.clone());
|
||||
// Ok(tracer)
|
||||
// }
|
||||
|
||||
// fn init_meter_provider(metadata: MetadataMap, service_name: String) -> Result<SdkMeterProvider, TracingError> {
|
||||
// let endpoint = std::env::var("SIGNOZ_ENDPOINT".to_string()).expect("SIGNOZ_ENDPOINT not set");
|
||||
|
||||
// let mut exporter_builder = opentelemetry_otlp::MetricExporter::builder()
|
||||
// .with_tonic()
|
||||
// .with_metadata(metadata)
|
||||
// .with_endpoint(&endpoint)
|
||||
// .with_temporality(opentelemetry_sdk::metrics::Temporality::default());
|
||||
|
||||
// if endpoint.starts_with("https://") {
|
||||
// exporter_builder = exporter_builder.with_tls_config(ClientTlsConfig::new().with_enabled_roots());
|
||||
// }
|
||||
|
||||
// let exporter = exporter_builder.build()?;
|
||||
|
||||
// let reader = PeriodicReader::builder(exporter)
|
||||
// .with_interval(std::time::Duration::from_secs(30))
|
||||
// .build();
|
||||
|
||||
// let stdout_reader =
|
||||
// PeriodicReader::builder(opentelemetry_stdout::MetricExporter::default()).build();
|
||||
|
||||
// let meter_provider = MeterProviderBuilder::default()
|
||||
// .with_resource(resource(service_name))
|
||||
// .with_reader(reader)
|
||||
// .with_reader(stdout_reader)
|
||||
// .build();
|
||||
|
||||
// global::set_meter_provider(meter_provider.clone());
|
||||
|
||||
// Ok(meter_provider)
|
||||
// }
|
||||
@@ -0,0 +1,88 @@
|
||||
use chrono::Utc;
|
||||
use opentelemetry::trace::TraceContextExt;
|
||||
use opentelemetry::{SpanId, TraceId};
|
||||
use serde::ser::{SerializeMap, Serializer as _};
|
||||
use std::io;
|
||||
use tracing::{Event, Subscriber};
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
use tracing_serde::fields::AsMap;
|
||||
use tracing_serde::AsSerde;
|
||||
use tracing_subscriber::fmt::format::Writer;
|
||||
use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
|
||||
use tracing_subscriber::registry::LookupSpan;
|
||||
|
||||
pub struct WriteAdaptor<'a> {
|
||||
fmt_write: &'a mut dyn std::fmt::Write,
|
||||
}
|
||||
|
||||
impl<'a> WriteAdaptor<'a> {
|
||||
pub fn new(fmt_write: &'a mut dyn std::fmt::Write) -> Self {
|
||||
Self { fmt_write }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> io::Write for WriteAdaptor<'a> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let s =
|
||||
std::str::from_utf8(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
self.fmt_write
|
||||
.write_str(s)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||
|
||||
Ok(s.as_bytes().len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TraceIdFormat;
|
||||
|
||||
impl<S, N> FormatEvent<S, N> for TraceIdFormat
|
||||
where
|
||||
S: Subscriber + for<'lookup> LookupSpan<'lookup>,
|
||||
N: for<'writer> FormatFields<'writer> + 'static,
|
||||
{
|
||||
fn format_event(
|
||||
&self,
|
||||
_ctx: &FmtContext<'_, S, N>,
|
||||
mut writer: Writer<'_>,
|
||||
event: &Event<'_>,
|
||||
) -> std::fmt::Result
|
||||
where
|
||||
S: Subscriber + for<'a> LookupSpan<'a>,
|
||||
{
|
||||
let meta = event.metadata();
|
||||
|
||||
let mut visit = || {
|
||||
let mut serializer = serde_json::Serializer::new(WriteAdaptor::new(&mut writer));
|
||||
let mut serializer = serializer.serialize_map(None)?;
|
||||
serializer.serialize_entry("timestamp", &Utc::now().to_rfc3339())?;
|
||||
serializer.serialize_entry("level", &meta.level().as_serde())?;
|
||||
serializer.serialize_entry("fields", &event.field_map())?;
|
||||
serializer.serialize_entry("target", meta.target())?;
|
||||
|
||||
let current_span = tracing::Span::current();
|
||||
let context = current_span.context();
|
||||
let span_ref = context.span();
|
||||
let span_context = span_ref.span_context();
|
||||
|
||||
let trace_id = span_context.trace_id();
|
||||
if trace_id != TraceId::INVALID {
|
||||
serializer.serialize_entry("trace_id", &trace_id.to_string())?;
|
||||
|
||||
let span_id = span_context.span_id();
|
||||
if span_id != SpanId::INVALID {
|
||||
serializer.serialize_entry("span_id", &span_id.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
serializer.end()
|
||||
};
|
||||
|
||||
visit().map_err(|_| std::fmt::Error)?;
|
||||
writeln!(writer)
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,7 @@ cli = ["clap", "comfy-table"]
|
||||
fs-credentials-storage = ["nym-credential-storage/persistent-storage"]
|
||||
fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"]
|
||||
fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"]
|
||||
otel = ["nym-sphinx/otel"]
|
||||
wasm = ["nym-gateway-client/wasm"]
|
||||
metrics-server = []
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::{client::replies::reply_storage, config::DebugConfig};
|
||||
use nym_task::{ShutdownManager, ShutdownToken, ShutdownTracker};
|
||||
|
||||
pub fn setup_empty_reply_surb_backend(debug_config: &DebugConfig) -> reply_storage::Empty {
|
||||
reply_storage::Empty {
|
||||
@@ -15,49 +13,3 @@ pub fn setup_empty_reply_surb_backend(debug_config: &DebugConfig) -> reply_stora
|
||||
.maximum_reply_surb_storage_threshold,
|
||||
}
|
||||
}
|
||||
|
||||
// old 'TaskHandle'
|
||||
pub(crate) enum ShutdownHelper {
|
||||
Internal(ShutdownManager),
|
||||
External(ShutdownTracker),
|
||||
}
|
||||
|
||||
fn new_shutdown_manager() -> Result<ShutdownManager, ClientCoreError> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_arch = "wasm32"))] {
|
||||
Ok(ShutdownManager::build_new_default()?)
|
||||
} else {
|
||||
Ok(ShutdownManager::new_without_signals())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShutdownHelper {
|
||||
pub(crate) fn new(shutdown_tracker: Option<ShutdownTracker>) -> Result<Self, ClientCoreError> {
|
||||
match shutdown_tracker {
|
||||
None => Ok(ShutdownHelper::Internal(new_shutdown_manager()?)),
|
||||
Some(shutdown_tracker) => Ok(ShutdownHelper::External(shutdown_tracker)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_internal(self) -> Option<ShutdownManager> {
|
||||
match self {
|
||||
ShutdownHelper::Internal(manager) => Some(manager),
|
||||
ShutdownHelper::External(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn shutdown_token(&self) -> ShutdownToken {
|
||||
match self {
|
||||
ShutdownHelper::External(shutdown) => shutdown.clone_shutdown_token(),
|
||||
ShutdownHelper::Internal(shutdown) => shutdown.clone_shutdown_token(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn tracker(&self) -> &ShutdownTracker {
|
||||
match self {
|
||||
ShutdownHelper::External(shutdown) => shutdown,
|
||||
ShutdownHelper::Internal(shutdown) => shutdown.shutdown_tracker(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use super::mix_traffic::ClientRequestSender;
|
||||
use super::received_buffer::ReceivedBufferMessage;
|
||||
use super::statistics_control::StatisticsControl;
|
||||
use crate::client::base_client::helpers::ShutdownHelper;
|
||||
use crate::client::base_client::storage::helpers::store_client_keys;
|
||||
use crate::client::base_client::storage::MixnetClientStorage;
|
||||
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||
@@ -53,7 +52,7 @@ use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
|
||||
use nym_statistics_common::clients::ClientStatsSender;
|
||||
use nym_statistics_common::generate_client_stats_id;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{ShutdownManager, ShutdownTracker};
|
||||
use nym_task::ShutdownTracker;
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::HardcodedTopologyProvider;
|
||||
use nym_validator_client::nym_api::NymApiClientExt;
|
||||
@@ -100,6 +99,7 @@ pub struct ClientOutput {
|
||||
}
|
||||
|
||||
impl ClientOutput {
|
||||
#[instrument(name = "ClientOutput::register_receiver", skip_all)]
|
||||
pub fn register_receiver(
|
||||
&mut self,
|
||||
) -> Result<mpsc::UnboundedReceiver<Vec<ReconstructedMessage>>, ClientCoreError> {
|
||||
@@ -434,6 +434,7 @@ where
|
||||
|
||||
// buffer controlling all messages fetched from provider
|
||||
// required so that other components would be able to use them (say the websocket)
|
||||
#[instrument(skip_all)]
|
||||
fn start_received_messages_buffer_controller(
|
||||
local_encryption_keypair: Arc<x25519::KeyPair>,
|
||||
query_receiver: ReceivedBufferRequestReceiver,
|
||||
@@ -466,6 +467,7 @@ where
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[instrument(skip_all)]
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
initialisation_result: InitialisationResult,
|
||||
@@ -572,6 +574,7 @@ where
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[instrument(skip_all)]
|
||||
async fn setup_gateway_transceiver(
|
||||
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send>>,
|
||||
config: &Config,
|
||||
@@ -729,7 +732,7 @@ where
|
||||
shutdown_tracker,
|
||||
)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn start_mix_traffic_controller(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
shutdown_tracker: &ShutdownTracker,
|
||||
@@ -839,6 +842,7 @@ where
|
||||
Ok(client.get_key_rotation_info().await?.into())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
|
||||
where
|
||||
S::ReplyStore: Send + Sync,
|
||||
@@ -881,8 +885,12 @@ where
|
||||
let shared_topology_accessor =
|
||||
TopologyAccessor::new(self.config.debug.topology.ignore_egress_epoch_role);
|
||||
|
||||
// Shutdown notifier for signalling tasks to stop
|
||||
let shutdown = ShutdownHelper::new(self.shutdown)?;
|
||||
// Create a shutdown tracker for this client - either as a child of provided tracker
|
||||
// or get one from the registry
|
||||
let shutdown_tracker = match self.shutdown {
|
||||
Some(parent_tracker) => parent_tracker.child_tracker(),
|
||||
None => nym_task::get_sdk_shutdown_tracker()?,
|
||||
};
|
||||
|
||||
// channels responsible for dealing with reply-related fun
|
||||
let (reply_controller_sender, reply_controller_receiver) =
|
||||
@@ -914,7 +922,7 @@ where
|
||||
self.user_agent.clone(),
|
||||
generate_client_stats_id(*self_address.identity()),
|
||||
input_sender.clone(),
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
);
|
||||
|
||||
// needs to be started as the first thing to block if required waiting for the gateway
|
||||
@@ -924,14 +932,14 @@ where
|
||||
shared_topology_accessor.clone(),
|
||||
self_address.gateway(),
|
||||
self.wait_for_gateway,
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let gateway_packet_router = PacketRouter::new(
|
||||
ack_sender,
|
||||
mixnet_messages_sender,
|
||||
shutdown.shutdown_token(),
|
||||
shutdown_tracker.clone_shutdown_token(),
|
||||
);
|
||||
|
||||
let gateway_transceiver = Self::setup_gateway_transceiver(
|
||||
@@ -944,7 +952,7 @@ where
|
||||
stats_reporter.clone(),
|
||||
#[cfg(unix)]
|
||||
self.connection_fd_callback,
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
)
|
||||
.await?;
|
||||
let gateway_ws_fd = gateway_transceiver.ws_fd();
|
||||
@@ -952,7 +960,7 @@ where
|
||||
let reply_storage = Self::setup_persistent_reply_storage(
|
||||
reply_storage_backend,
|
||||
key_rotation_config,
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -963,7 +971,7 @@ where
|
||||
reply_storage.key_storage(),
|
||||
reply_controller_sender.clone(),
|
||||
stats_reporter.clone(),
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
);
|
||||
|
||||
// The message_sender is the transmitter for any component generating sphinx packets
|
||||
@@ -971,8 +979,10 @@ where
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
|
||||
let (message_sender, client_request_sender) =
|
||||
Self::start_mix_traffic_controller(gateway_transceiver, shutdown.tracker());
|
||||
let (message_sender, client_request_sender) = Self::start_mix_traffic_controller(
|
||||
gateway_transceiver,
|
||||
&shutdown_tracker.child_tracker(),
|
||||
);
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
// controller that connections are closed.
|
||||
@@ -1001,7 +1011,7 @@ where
|
||||
shared_lane_queue_lengths.clone(),
|
||||
client_connection_rx,
|
||||
stats_reporter.clone(),
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
);
|
||||
|
||||
if !self
|
||||
@@ -1017,7 +1027,7 @@ where
|
||||
shared_topology_accessor.clone(),
|
||||
message_sender,
|
||||
stats_reporter.clone(),
|
||||
shutdown.tracker(),
|
||||
&shutdown_tracker.child_tracker(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1045,7 +1055,7 @@ where
|
||||
gateway_connection: GatewayConnection { gateway_ws_fd },
|
||||
},
|
||||
stats_reporter,
|
||||
shutdown_handle: shutdown.into_internal(),
|
||||
shutdown_handle: Some(shutdown_tracker), // The primary tracker for this client
|
||||
client_request_sender,
|
||||
forget_me: self.config.debug.forget_me,
|
||||
remember_me: self.config.debug.remember_me,
|
||||
@@ -1061,7 +1071,7 @@ pub struct BaseClient {
|
||||
pub client_state: ClientState,
|
||||
pub stats_reporter: ClientStatsSender,
|
||||
pub client_request_sender: ClientRequestSender,
|
||||
pub shutdown_handle: Option<ShutdownManager>,
|
||||
pub shutdown_handle: Option<ShutdownTracker>,
|
||||
pub forget_me: ForgetMe,
|
||||
pub remember_me: RememberMe,
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ pub enum InputMessage {
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
max_retransmissions: Option<u32>,
|
||||
// add trace_id for optional tracing of individual messages in debug mode
|
||||
trace_id: Option<[u8; 12]>,
|
||||
},
|
||||
|
||||
/// Creates a message used for a duplex anonymous communication where the recipient
|
||||
@@ -45,6 +47,7 @@ pub enum InputMessage {
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
},
|
||||
|
||||
/// Attempt to use our internally received and stored `ReplySurb` to send the message back
|
||||
@@ -90,12 +93,14 @@ impl InputMessage {
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Self {
|
||||
let message = InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
max_retransmissions: None,
|
||||
trace_id,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
@@ -110,6 +115,7 @@ impl InputMessage {
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Self {
|
||||
let message = InputMessage::Anonymous {
|
||||
recipient,
|
||||
@@ -117,6 +123,7 @@ impl InputMessage {
|
||||
reply_surbs,
|
||||
lane,
|
||||
max_retransmissions: None,
|
||||
trace_id,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
@@ -185,4 +192,13 @@ impl InputMessage {
|
||||
self.set_max_retransmissions(max_retransmissions);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn trace_id(&self) -> Option<[u8; 12]> {
|
||||
match self {
|
||||
InputMessage::Regular { trace_id, .. } => *trace_id,
|
||||
InputMessage::Anonymous { trace_id, .. } => *trace_id,
|
||||
InputMessage::Premade { .. } | InputMessage::Reply { .. } => None,
|
||||
InputMessage::MessageWrapper { message, .. } => message.trace_id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-1
@@ -70,6 +70,7 @@ where
|
||||
.send_reply(recipient_tag, data, lane, max_retransmissions);
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_plain_message(
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
@@ -77,16 +78,18 @@ where
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_plain_message(recipient, content, lane, packet_type, max_retransmissions)
|
||||
.try_send_plain_message(recipient, content, lane, packet_type, max_retransmissions, trace_id)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send a plain message - {err}")
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_repliable_message(
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
@@ -95,6 +98,7 @@ where
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
@@ -105,6 +109,7 @@ where
|
||||
lane,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
trace_id,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -113,20 +118,29 @@ where
|
||||
}
|
||||
|
||||
#[allow(clippy::panic)]
|
||||
#[instrument(skip_all)]
|
||||
async fn on_input_message(&mut self, msg: InputMessage) {
|
||||
let trace_id = msg.trace_id();
|
||||
if let Some(tid) = trace_id {
|
||||
tracing::warn!("Processing input message with trace_id: {:?}", tid);
|
||||
}
|
||||
|
||||
match msg {
|
||||
InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
max_retransmissions,
|
||||
..
|
||||
} => {
|
||||
warn!("Handling regular input message with trace_id: {:?}", trace_id);
|
||||
self.handle_plain_message(
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
PacketType::Mix,
|
||||
max_retransmissions,
|
||||
trace_id
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -136,7 +150,9 @@ where
|
||||
reply_surbs,
|
||||
lane,
|
||||
max_retransmissions,
|
||||
..
|
||||
} => {
|
||||
warn!("Handling anonymous input message with trace_id: {:?}", trace_id);
|
||||
self.handle_repliable_message(
|
||||
recipient,
|
||||
data,
|
||||
@@ -144,6 +160,7 @@ where
|
||||
lane,
|
||||
PacketType::Mix,
|
||||
max_retransmissions,
|
||||
trace_id
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -153,6 +170,7 @@ where
|
||||
lane,
|
||||
max_retransmissions,
|
||||
} => {
|
||||
warn!("Handling reply input message with trace_id: {:?}", trace_id);
|
||||
self.handle_reply(recipient_tag, data, lane, max_retransmissions)
|
||||
.await;
|
||||
}
|
||||
@@ -166,13 +184,16 @@ where
|
||||
data,
|
||||
lane,
|
||||
max_retransmissions,
|
||||
..
|
||||
} => {
|
||||
tracing::warn!("Handling regular input message with trace_id: {:?}", trace_id);
|
||||
self.handle_plain_message(
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
trace_id
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -182,6 +203,7 @@ where
|
||||
reply_surbs,
|
||||
lane,
|
||||
max_retransmissions,
|
||||
..
|
||||
} => {
|
||||
self.handle_repliable_message(
|
||||
recipient,
|
||||
@@ -190,6 +212,7 @@ where
|
||||
lane,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
trace_id
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -213,6 +236,7 @@ where
|
||||
};
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn run(&mut self, shutdown_token: ShutdownToken) {
|
||||
debug!("Started InputMessageListener with graceful shutdown support");
|
||||
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ where
|
||||
|
||||
// TODO: Figure out retransmission packet type signaling
|
||||
self.message_handler
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type)
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type, None)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
|
||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||
#[derive(Debug, Error)]
|
||||
@@ -476,6 +476,7 @@ where
|
||||
self.forward_messages(msgs, lane).await;
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn try_send_plain_message(
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
@@ -483,6 +484,7 @@ where
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<(), PreparationError> {
|
||||
let message = NymMessage::new_plain(message);
|
||||
self.try_split_and_send_non_reply_message(
|
||||
@@ -491,10 +493,12 @@ where
|
||||
lane,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
trace_id,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn try_split_and_send_non_reply_message(
|
||||
&mut self,
|
||||
message: NymMessage,
|
||||
@@ -502,6 +506,7 @@ where
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<(), PreparationError> {
|
||||
debug!("Sending non-reply message with packet type {packet_type}");
|
||||
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
||||
@@ -534,6 +539,7 @@ where
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
trace_id
|
||||
)?;
|
||||
|
||||
let real_message = RealMessage::new(
|
||||
@@ -585,6 +591,7 @@ where
|
||||
TransmissionLane::AdditionalReplySurbs,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -602,6 +609,7 @@ where
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
max_retransmissions: Option<u32>,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<(), SurbWrappedPreparationError> {
|
||||
debug!("Sending message with reply SURBs with packet type {packet_type}");
|
||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||
@@ -625,6 +633,7 @@ where
|
||||
lane,
|
||||
packet_type,
|
||||
max_retransmissions,
|
||||
trace_id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -639,6 +648,7 @@ where
|
||||
recipient: Recipient,
|
||||
chunk: Fragment,
|
||||
packet_type: PacketType,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<PreparedFragment, PreparationError> {
|
||||
debug!("Sending single chunk with packet type {packet_type}");
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
@@ -650,6 +660,7 @@ where
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
trace_id,
|
||||
)?;
|
||||
|
||||
Ok(prepared_fragment)
|
||||
|
||||
@@ -80,6 +80,7 @@ impl StatisticsControl {
|
||||
stats_report.into(),
|
||||
TransmissionLane::General,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
if let Err(err) = self.report_tx.send(report_message).await {
|
||||
tracing::error!("Failed to report client stats: {err:?}");
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::client::mix_traffic::transceiver::ErasedGatewayError;
|
||||
use nym_crypto::asymmetric::ed25519::Ed25519RecoveryError;
|
||||
use nym_gateway_client::error::GatewayClientError;
|
||||
use nym_task::RegistryAccessError;
|
||||
use nym_topology::node::RoutingNodeError;
|
||||
use nym_topology::{NodeId, NymTopologyError};
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
@@ -242,6 +243,9 @@ pub enum ClientCoreError {
|
||||
|
||||
#[error("failed to select valid gateway due to incomputable latency")]
|
||||
GatewaySelectionFailure { source: WeightedError },
|
||||
|
||||
#[error("Could not access task registry, {0}")]
|
||||
RegistryAccess(#[from] RegistryAccessError),
|
||||
}
|
||||
|
||||
impl From<tungstenite::Error> for ClientCoreError {
|
||||
|
||||
@@ -1043,6 +1043,12 @@ impl<C, St> GatewayClient<C, St> {
|
||||
}
|
||||
|
||||
// Note: this requires prior authentication
|
||||
#[instrument(skip_all,
|
||||
fields(
|
||||
gateway = %self.gateway_identity,
|
||||
gateway_address = %self.gateway_address
|
||||
)
|
||||
)]
|
||||
pub fn start_listening_for_mixnet_messages(&mut self) -> Result<(), GatewayClientError> {
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
|
||||
@@ -19,11 +19,11 @@ serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
time = { workspace = true }
|
||||
subtle = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
nym-crypto = { path = "../crypto", features = ["aead", "hashing"] }
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
@@ -34,6 +34,11 @@ nym-task = { path = "../task" }
|
||||
nym-credentials = { path = "../credentials" }
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
|
||||
opentelemetry = { workspace = true, features = ["trace"], optional = true }
|
||||
opentelemetry_sdk = { workspace = true, optional = true }
|
||||
tracing-opentelemetry = { workspace = true, optional = true }
|
||||
tracing = { workspace = true, features = ["std", "attributes", "tracing-attributes"] }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||
workspace = true
|
||||
features = ["time"]
|
||||
@@ -51,3 +56,12 @@ anyhow = { workspace = true }
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" } # we need specific imports in tests
|
||||
nym-test-utils = { path = "../test-utils" }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
otel = [
|
||||
"nym-bin-common/otel",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"tracing-opentelemetry",
|
||||
]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::{AuthenticationFailure, GatewayRequestsError, SharedGatewayKey};
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::iter;
|
||||
use std::time::Duration;
|
||||
use subtle::ConstantTimeEq;
|
||||
@@ -16,6 +17,9 @@ pub struct AuthenticateRequest {
|
||||
pub content: AuthenticateRequestContent,
|
||||
|
||||
pub request_signature: ed25519::Signature,
|
||||
|
||||
#[serde(default)]
|
||||
pub otel_context: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl AuthenticateRequest {
|
||||
@@ -23,6 +27,7 @@ impl AuthenticateRequest {
|
||||
protocol_version: u8,
|
||||
shared_key: &SharedGatewayKey,
|
||||
identity_keys: &ed25519::KeyPair,
|
||||
otel_context: Option<HashMap<String, String>>,
|
||||
) -> Result<AuthenticateRequest, GatewayRequestsError> {
|
||||
let content = AuthenticateRequestContent::new(
|
||||
protocol_version,
|
||||
@@ -35,6 +40,7 @@ impl AuthenticateRequest {
|
||||
Ok(AuthenticateRequest {
|
||||
content,
|
||||
request_signature,
|
||||
otel_context,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,16 @@ use crate::{
|
||||
AUTHENTICATE_V2_PROTOCOL_VERSION, CREDENTIAL_UPDATE_V2_PROTOCOL_VERSION,
|
||||
INITIAL_PROTOCOL_VERSION,
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
use nym_bin_common::opentelemetry::context::ContextCarrier;
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use nym_statistics_common::types::SessionType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use tracing::{instrument, warn};
|
||||
use tungstenite::Message;
|
||||
|
||||
pub mod authenticate;
|
||||
@@ -76,8 +80,13 @@ pub enum ClientControlRequest {
|
||||
address: String,
|
||||
enc_address: String,
|
||||
iv: String,
|
||||
/// this is a trace id that is used in testing and performance verification
|
||||
/// in mainnet, this will always be set to None
|
||||
#[serde(default)]
|
||||
otel_context: Option<HashMap<String, String>>,
|
||||
},
|
||||
|
||||
|
||||
AuthenticateV2(Box<AuthenticateRequest>),
|
||||
|
||||
#[serde(alias = "handshakePayload")]
|
||||
@@ -127,14 +136,25 @@ impl ClientControlRequest {
|
||||
let nonce = shared_key.random_nonce_or_iv();
|
||||
let ciphertext = shared_key.encrypt_naive(address.as_bytes_ref(), Some(&nonce))?;
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
let context_carrier = {
|
||||
let context = opentelemetry::Context::current();
|
||||
ContextCarrier::new_with_current_context(context).into_map()
|
||||
};
|
||||
|
||||
Ok(ClientControlRequest::Authenticate {
|
||||
protocol_version,
|
||||
address: address.as_base58_string(),
|
||||
enc_address: bs58::encode(&ciphertext).into_string(),
|
||||
iv: bs58::encode(&nonce).into_string(),
|
||||
#[cfg(feature = "otel")]
|
||||
otel_context: Some(context_carrier),
|
||||
#[cfg(not(feature = "otel"))]
|
||||
otel_context: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub fn new_authenticate_v2(
|
||||
shared_key: &SharedGatewayKey,
|
||||
identity_keys: &ed25519::KeyPair,
|
||||
@@ -142,8 +162,27 @@ impl ClientControlRequest {
|
||||
// if we're using v2 authentication, we must announce at least that protocol version
|
||||
let protocol_version = AUTHENTICATE_V2_PROTOCOL_VERSION;
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
let context_carrier = {
|
||||
use nym_bin_common::opentelemetry::context::extract_trace_id_from_tracing_cx;
|
||||
let trace_id = extract_trace_id_from_tracing_cx();
|
||||
|
||||
use tracing_opentelemetry::OpenTelemetrySpanExt;
|
||||
|
||||
let current_span = tracing::Span::current();
|
||||
let otel_context = current_span.context();
|
||||
ContextCarrier::new_with_current_context(otel_context).into_map()
|
||||
};
|
||||
#[cfg(not(feature = "otel"))]
|
||||
let context_carrier: HashMap<String, String> = HashMap::new();
|
||||
|
||||
Ok(ClientControlRequest::AuthenticateV2(Box::new(
|
||||
AuthenticateRequest::new(protocol_version, shared_key, identity_keys)?,
|
||||
AuthenticateRequest::new(
|
||||
protocol_version,
|
||||
shared_key,
|
||||
identity_keys,
|
||||
Some(context_carrier)
|
||||
)?,
|
||||
)))
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@ license.workspace = true
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
# TODO: Remove otel from default before release
|
||||
default=["tunneling"]
|
||||
tunneling=[]
|
||||
network-defaults = ["dep:nym-network-defaults"]
|
||||
otel = ["nym-bin-common/otel", "opentelemetry", "opentelemetry_sdk"]
|
||||
debug-inventory = ["nym-http-api-client-macro/debug-inventory"]
|
||||
|
||||
[dependencies]
|
||||
@@ -24,6 +26,8 @@ reqwest = { workspace = true, features = ["json", "gzip", "deflate", "brotli", "
|
||||
http.workspace = true
|
||||
url = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
opentelemetry = { workspace = true, optional = true }
|
||||
opentelemetry_sdk = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true}
|
||||
@@ -53,4 +57,3 @@ features = ["tokio"]
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["rt", "macros"] }
|
||||
|
||||
|
||||
@@ -976,6 +976,22 @@ impl ApiClientCore for Client {
|
||||
|
||||
self.apply_hosts_to_req(&mut req);
|
||||
|
||||
// if opentelemetry is activated add the current trace context to the request
|
||||
#[cfg(feature = "otel")]
|
||||
{
|
||||
use opentelemetry::Context;
|
||||
use nym_bin_common::opentelemetry::context::ContextCarrier;
|
||||
|
||||
let carrier = ContextCarrier::new_with_current_context(Context::current());
|
||||
|
||||
if let Some(traceparent) = carrier.extract_traceparent() {
|
||||
if let Ok(header_value) = HeaderValue::from_str(&traceparent) {
|
||||
req.headers_mut()
|
||||
.insert("traceparent", header_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut rb = RequestBuilder::from_parts(self.reqwest_client.clone(), req);
|
||||
|
||||
rb = rb
|
||||
|
||||
@@ -18,6 +18,7 @@ bytes = { workspace = true, optional = true }
|
||||
colored = { workspace = true, optional = true }
|
||||
futures = { workspace = true, optional = true }
|
||||
mime = { workspace = true, optional = true }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
serde_yaml = { workspace = true, optional = true }
|
||||
@@ -49,6 +50,8 @@ middleware = [
|
||||
"zeroize"
|
||||
]
|
||||
|
||||
otel = ["nym-bin-common/otel"]
|
||||
|
||||
utoipa = ["dep:utoipa"]
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -56,6 +56,16 @@ async fn log_request(
|
||||
|
||||
let host = header_map(request.headers().get(HOST), "Unknown Host".to_string());
|
||||
|
||||
// Extract traceparent from headers if it exists
|
||||
#[cfg(feature = "otel")]
|
||||
let traceparent = request
|
||||
.headers()
|
||||
.get("traceparent")
|
||||
.and_then(|h| h.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
#[cfg(not(feature = "otel"))]
|
||||
let traceparent: Option<String> = None;
|
||||
|
||||
let start = Instant::now();
|
||||
// run request through all middleware, incl. extractors
|
||||
let res = next.run(request).await;
|
||||
@@ -82,10 +92,10 @@ async fn log_request(
|
||||
|
||||
match level {
|
||||
LogLevel::Debug => debug!(
|
||||
"[{addr} -> {host}] {method} '{uri}': {print_status} {time_taken} {agent_str}: {agent}"
|
||||
"[{addr} -> {host}] {method} '{uri}': {print_status} {time_taken} {agent_str}: {agent} traceparent: {traceparent:?}",
|
||||
),
|
||||
LogLevel::Info => info!(
|
||||
"[{addr} -> {host}] {method} '{uri}': {print_status} {time_taken} {agent_str}: {agent}"
|
||||
"[{addr} -> {host}] {method} '{uri}': {print_status} {time_taken} {agent_str}: {agent} traceparent: {traceparent:?}"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ where
|
||||
&address,
|
||||
&address,
|
||||
PacketType::Mix,
|
||||
None
|
||||
)?)
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ impl TryFrom<&[u8]> for SecretKeyAuth {
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<SecretKeyAuth> {
|
||||
// There should be x and at least one y
|
||||
if bytes.len() < 32 * 2 + 8 || (bytes.len() - 8) % 32 != 0 {
|
||||
if bytes.len() < 32 * 2 + 8 || !(bytes.len() - 8).is_multiple_of(32) {
|
||||
return Err(CompactEcashError::DeserializationInvalidLength {
|
||||
actual: bytes.len(),
|
||||
modulus_target: bytes.len() - 8,
|
||||
@@ -152,7 +152,7 @@ impl TryFrom<&[u8]> for VerificationKeyAuth {
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<VerificationKeyAuth> {
|
||||
// There should be at least alpha, one betaG1 and one betaG2 and their length
|
||||
if bytes.len() < 96 * 2 + 48 + 8 || (bytes.len() - 8 - 96) % (96 + 48) != 0 {
|
||||
if bytes.len() < 96 * 2 + 48 + 8 || !(bytes.len() - 8 - 96).is_multiple_of(96 + 48) {
|
||||
return Err(CompactEcashError::DeserializationInvalidLength {
|
||||
actual: bytes.len(),
|
||||
modulus_target: bytes.len() - 8 - 96,
|
||||
|
||||
@@ -8,12 +8,14 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
sphinx-packet = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
rand_distr = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
nym-sphinx-acknowledgements = { path = "acknowledgements" }
|
||||
nym-sphinx-addressing = { path = "addressing" }
|
||||
nym-sphinx-anonymous-replies = { path = "anonymous-replies" }
|
||||
@@ -55,3 +57,7 @@ outfox = [
|
||||
"nym-sphinx-params/outfox",
|
||||
"nym-sphinx-types/outfox",
|
||||
]
|
||||
|
||||
otel = [
|
||||
"nym-bin-common/otel",
|
||||
]
|
||||
@@ -59,7 +59,7 @@ impl SurbAck {
|
||||
};
|
||||
|
||||
let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len());
|
||||
let destination = recipient.as_sphinx_destination();
|
||||
let destination = recipient.as_sphinx_destination(None);
|
||||
|
||||
let surb_ack_payload = prepare_identifier(rng, ack_key, marshaled_fragment_id);
|
||||
let packet_size = match packet_type {
|
||||
|
||||
@@ -8,14 +8,20 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
nym-bin-common = { path = "../../bin-common", features = ["opentelemetry"] } # for trace id compression/decompression
|
||||
nym-crypto = { path = "../../crypto", features = ["asymmetric", "sphinx"] } # all addresses are expressed in terms on their crypto keys
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx"] } # we need to be able to refer to some types defined inside sphinx crate
|
||||
serde = { workspace = true } # implementing serialization/deserialization for some types, like `Recipient`
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
nym-crypto = { path = "../../crypto", features = ["rand"] }
|
||||
bincode = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
otel = ["nym-bin-common/otel"]
|
||||
@@ -150,12 +150,26 @@ impl Recipient {
|
||||
// TODO: Currently the `DestinationAddress` is equivalent to `ClientIdentity`, but perhaps
|
||||
// it shouldn't be? Maybe it should be (for example) H(`ClientIdentity || ClientEncryptionKey`)
|
||||
// instead? That is an open question.
|
||||
pub fn as_sphinx_destination(&self) -> Destination {
|
||||
pub fn as_sphinx_destination(&self, trace_id: Option<[u8; 12]>) -> Destination {
|
||||
#[cfg(feature = "otel")]
|
||||
use nym_bin_common::opentelemetry::compact_id_generator::decompress_trace_id;
|
||||
#[cfg(feature = "otel")]
|
||||
let trace_id_16 = if let Some(trace_id) = trace_id {
|
||||
decompress_trace_id(&trace_id)
|
||||
} else {
|
||||
decompress_trace_id(&[0u8; 12])
|
||||
};
|
||||
#[cfg(not(feature = "otel"))]
|
||||
let trace_id_16 = {
|
||||
_ = trace_id;
|
||||
[0u8; 16]
|
||||
};
|
||||
|
||||
// since the nym mix network differs slightly in design from loopix, we do not care
|
||||
// about "surb_id" field at all and just use the default value.
|
||||
Destination::new(
|
||||
self.client_identity.derive_destination_address(),
|
||||
Default::default(),
|
||||
trace_id_16,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ impl ReplySurb {
|
||||
topology.random_route_to_egress(rng, recipient.gateway())?
|
||||
};
|
||||
let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len());
|
||||
let destination = recipient.as_sphinx_destination();
|
||||
let destination = recipient.as_sphinx_destination(None);
|
||||
|
||||
let mut surb_material = SURBMaterial::new(route, delays, destination);
|
||||
if use_legacy_surb_format && !disable_mix_hops {
|
||||
|
||||
@@ -125,7 +125,7 @@ where
|
||||
|
||||
let route = topology.random_route_to_egress(rng, full_address.gateway())?;
|
||||
let delays = nym_sphinx_routing::generate_hop_delays(average_packet_delay, route.len());
|
||||
let destination = full_address.as_sphinx_destination();
|
||||
let destination = full_address.as_sphinx_destination(None);
|
||||
|
||||
let rotation_id = topology.current_key_rotation();
|
||||
let sphinx_key_rotation = SphinxKeyRotation::from(rotation_id);
|
||||
|
||||
@@ -11,8 +11,10 @@ repository = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
tokio-util = { workspace = true, features = ["codec"] }
|
||||
thiserror = { workspace = true }
|
||||
opentelemetry = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
nym-bin-common = { path = "../../bin-common" }
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] }
|
||||
nym-sphinx-params = { path = "../params", features = ["sphinx", "outfox"] }
|
||||
nym-sphinx-forwarding = { path = "../forwarding" }
|
||||
@@ -21,3 +23,7 @@ nym-sphinx-acknowledgements = { path = "../acknowledgements" }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
otel = ["nym-bin-common/otel"]
|
||||
@@ -2,6 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::packet::FramedNymPacket;
|
||||
#[cfg(feature = "otel")]
|
||||
use nym_bin_common::opentelemetry::{
|
||||
compact_id_generator::decompress_trace_id,
|
||||
context::ManualContextPropagator,
|
||||
};
|
||||
|
||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
@@ -14,7 +20,9 @@ use nym_sphinx_types::{
|
||||
};
|
||||
use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, info, trace};
|
||||
use tracing::{debug, error, info, instrument, trace, warn};
|
||||
#[cfg(feature = "otel")]
|
||||
use tracing::warn_span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MixProcessingResultData {
|
||||
@@ -236,6 +244,7 @@ fn perform_framed_packet_processing(
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn wrap_processed_sphinx_packet(
|
||||
packet: nym_sphinx_types::ProcessedPacket,
|
||||
packet_size: PacketSize,
|
||||
@@ -258,15 +267,36 @@ fn wrap_processed_sphinx_packet(
|
||||
// sphinx all together?
|
||||
ProcessedPacketData::FinalHop {
|
||||
destination,
|
||||
#[cfg(feature = "otel")]
|
||||
identifier,
|
||||
#[cfg(not(feature = "otel"))]
|
||||
identifier: _,
|
||||
payload,
|
||||
} => process_final_hop(
|
||||
destination,
|
||||
payload.recover_plaintext()?,
|
||||
packet_size,
|
||||
packet_type,
|
||||
key_rotation,
|
||||
),
|
||||
} => {
|
||||
// if we have a trace id in the destination, we log it for easier correlation later on
|
||||
#[cfg(feature = "otel")]
|
||||
let span = match identifier[0..12].try_into().map(|b: [u8; 12]| b) {
|
||||
Ok(trace_bytes) if !trace_bytes.iter().all(|b| *b == 0) => {
|
||||
let full_trace_id_bytes = decompress_trace_id(&trace_bytes);
|
||||
let full_trace_id = opentelemetry::trace::TraceId::from_bytes(full_trace_id_bytes);
|
||||
let context_propagator = ManualContextPropagator::new_from_tid("final_hop", full_trace_id);
|
||||
warn_span!(parent: &context_propagator.root_span, "final_hop_processing", trace_id=%full_trace_id)
|
||||
}
|
||||
_ => {
|
||||
warn_span!("final_hop_processing")
|
||||
}
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let _entered_span = span.enter();
|
||||
|
||||
process_final_hop(
|
||||
destination,
|
||||
payload.recover_plaintext()?,
|
||||
packet_size,
|
||||
packet_type,
|
||||
key_rotation,
|
||||
)
|
||||
}
|
||||
}?;
|
||||
|
||||
Ok(MixProcessingResult {
|
||||
|
||||
@@ -44,7 +44,7 @@ impl From<u32> for SphinxKeyRotation {
|
||||
fn from(value: u32) -> Self {
|
||||
if value == 0 || value == u32::MAX {
|
||||
SphinxKeyRotation::Unknown
|
||||
} else if value % 2 == 0 {
|
||||
} else if value.is_multiple_of(2) {
|
||||
SphinxKeyRotation::EvenRotation
|
||||
} else {
|
||||
SphinxKeyRotation::OddRotation
|
||||
|
||||
@@ -163,19 +163,6 @@ pub trait FragmentPreparer {
|
||||
})
|
||||
}
|
||||
|
||||
/// Tries to convert this [`Fragment`] into a [`SphinxPacket`] that can be sent through the Nym mix-network,
|
||||
/// such that it contains required SURB-ACK and public component of the ephemeral key used to
|
||||
/// derive the shared key.
|
||||
/// Also all the data, apart from the said public component, is encrypted with an ephemeral shared key.
|
||||
/// This method can fail if the provided network topology is invalid.
|
||||
/// It returns total expected delay as well as the [`SphinxPacket`] (including first hop address)
|
||||
/// to be sent through the network.
|
||||
///
|
||||
/// The procedure is as follows:
|
||||
/// For each fragment:
|
||||
/// - compute SURB_ACK
|
||||
/// - generate (x, g^x)
|
||||
/// - compute k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
||||
/// - compute v_b = AES-128-CTR(k, serialized_fragment)
|
||||
/// - compute vk_b = g^x || v_b
|
||||
/// - compute sphinx_plaintext = SURB_ACK || g^x || v_b
|
||||
@@ -189,6 +176,7 @@ pub trait FragmentPreparer {
|
||||
packet_sender: &Recipient,
|
||||
packet_recipient: &Recipient,
|
||||
packet_type: PacketType,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
debug!("Preparing chunk for sending");
|
||||
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
|
||||
@@ -249,7 +237,8 @@ pub trait FragmentPreparer {
|
||||
topology.random_route_to_egress(&mut rng, destination)?
|
||||
};
|
||||
|
||||
let destination = packet_recipient.as_sphinx_destination();
|
||||
let destination = packet_recipient.as_sphinx_destination(trace_id);
|
||||
tracing::warn!("Packet destination with trace id: {:?}", &destination.identifier);
|
||||
|
||||
// including set of delays
|
||||
let delays =
|
||||
@@ -274,9 +263,10 @@ pub trait FragmentPreparer {
|
||||
)?,
|
||||
};
|
||||
|
||||
// from the previously constructed route extract the first hop
|
||||
let first_hop_address =
|
||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||
// - compute k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
||||
// from the previously constructed route extract the first hop
|
||||
let first_hop_address =
|
||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||
|
||||
Ok(PreparedFragment {
|
||||
// the round-trip delay is the sum of delays of all hops on the forward route as
|
||||
@@ -428,6 +418,7 @@ where
|
||||
ack_key: &AckKey,
|
||||
packet_recipient: &Recipient,
|
||||
packet_type: PacketType,
|
||||
trace_id: Option<[u8; 12]>,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
let sender = self.sender_address;
|
||||
|
||||
@@ -439,6 +430,7 @@ where
|
||||
&sender,
|
||||
packet_recipient,
|
||||
packet_type,
|
||||
trace_id,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ repository = { workspace = true }
|
||||
[dependencies]
|
||||
sphinx-packet = { workspace = true, optional = true }
|
||||
nym-outfox = { path = "../../../nym-outfox", optional = true }
|
||||
# TODO add optional
|
||||
nym-bin-common = { path = "../../../common/bin-common" }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -32,8 +32,6 @@ tracing.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
|
||||
# TEMP
|
||||
#nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -350,6 +350,7 @@ impl SocksClient {
|
||||
self.config.connection_start_surbs,
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
None
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -373,6 +374,7 @@ impl SocksClient {
|
||||
msg.into_bytes(),
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
None
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -439,6 +441,7 @@ impl SocksClient {
|
||||
per_request_surbs,
|
||||
lane,
|
||||
packet_type,
|
||||
None
|
||||
)
|
||||
} else {
|
||||
InputMessage::new_regular(
|
||||
@@ -446,6 +449,7 @@ impl SocksClient {
|
||||
provider_message.into_bytes(),
|
||||
lane,
|
||||
packet_type,
|
||||
None
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,6 +17,12 @@ pub struct ShutdownToken {
|
||||
inner: CancellationToken,
|
||||
}
|
||||
|
||||
impl From<CancellationToken> for ShutdownToken {
|
||||
fn from(inner: CancellationToken) -> Self {
|
||||
ShutdownToken { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl ShutdownToken {
|
||||
/// A drop in no-op replacement for `send_status_msg` for easier migration from [TaskClient](crate::TaskClient).
|
||||
#[deprecated]
|
||||
@@ -45,6 +51,13 @@ impl ShutdownToken {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Get an owned [CancellationToken](tokio_util::sync::CancellationToken) for public API use.
|
||||
/// This is useful when you need to expose cancellation to SDK users without
|
||||
/// exposing the internal ShutdownToken type.
|
||||
pub fn to_cancellation_token(&self) -> CancellationToken {
|
||||
self.inner.clone()
|
||||
}
|
||||
|
||||
/// Creates a `ShutdownToken` which will get cancelled whenever the
|
||||
/// current token gets cancelled. Unlike a cloned `ShutdownToken`,
|
||||
/// cancelling a child token does not cancel the parent token.
|
||||
|
||||
@@ -314,4 +314,40 @@ impl ShutdownTracker {
|
||||
pub fn clone_shutdown_token(&self) -> ShutdownToken {
|
||||
self.root_cancellation_token.clone()
|
||||
}
|
||||
|
||||
/// Create a child ShutdownTracker that inherits cancellation from this tracker
|
||||
/// but has its own TaskTracker for managing sub-tasks.
|
||||
///
|
||||
/// This enables hierarchical task management where:
|
||||
/// - Parent cancellation flows to all children
|
||||
/// - Each level tracks its own tasks independently
|
||||
/// - Components can wait for their specific sub-tasks to complete
|
||||
pub fn child_tracker(&self) -> ShutdownTracker {
|
||||
// Child token inherits cancellation from parent
|
||||
let child_token = self.root_cancellation_token.child_token();
|
||||
|
||||
// New TaskTracker for this level's tasks
|
||||
let child_task_tracker = TaskTracker::new();
|
||||
|
||||
ShutdownTracker {
|
||||
root_cancellation_token: child_token,
|
||||
tracker: child_task_tracker,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience method to perform a complete shutdown sequence.
|
||||
/// This method:
|
||||
/// 1. Signals cancellation to all tasks
|
||||
/// 2. Closes the tracker to prevent new tasks
|
||||
/// 3. Waits for all existing tasks to complete
|
||||
pub async fn shutdown(self) {
|
||||
// Signal cancellation to all tasks
|
||||
self.root_cancellation_token.cancel();
|
||||
|
||||
// Close the tracker to prevent new tasks from being spawned
|
||||
self.tracker.close();
|
||||
|
||||
// Wait for all existing tasks to complete
|
||||
self.tracker.wait().await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ pub mod cancellation;
|
||||
pub mod connections;
|
||||
pub mod event;
|
||||
pub mod manager;
|
||||
pub(crate) mod runtime_registry;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod signal;
|
||||
pub mod spawn;
|
||||
@@ -18,3 +19,11 @@ pub use tokio_util::task::TaskTracker;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub use signal::{wait_for_signal, wait_for_signal_and_error};
|
||||
|
||||
pub use crate::runtime_registry::RegistryAccessError;
|
||||
|
||||
/// Get or create a ShutdownTracker for SDK use.
|
||||
/// This provides automatic task management without requiring manual setup.
|
||||
pub fn get_sdk_shutdown_tracker() -> Result<ShutdownTracker, RegistryAccessError> {
|
||||
Ok(runtime_registry::RuntimeRegistry::get_or_create_sdk()?.shutdown_tracker_owned())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::ShutdownManager;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::{Arc, LazyLock};
|
||||
|
||||
/// Global registry that manages ShutdownManagers transparently.
|
||||
/// This allows SDK components to get automatic task management without
|
||||
/// exposing the complexity to end users.
|
||||
pub(crate) struct RuntimeRegistry {
|
||||
// For SDK clients: auto-created manager without signal handling
|
||||
sdk_manager: RwLock<Option<Arc<ShutdownManager>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RegistryAccessError {
|
||||
#[error("the runtime registry is poisoned")]
|
||||
Poisoned,
|
||||
}
|
||||
|
||||
impl RuntimeRegistry {
|
||||
/// Get or create a ShutdownManager for SDK use.
|
||||
/// This manager doesn't listen to OS signals, making it suitable for library use.
|
||||
pub(crate) fn get_or_create_sdk() -> Result<Arc<ShutdownManager>, RegistryAccessError> {
|
||||
let guard = REGISTRY
|
||||
.sdk_manager
|
||||
.read()
|
||||
.map_err(|_| RegistryAccessError::Poisoned)?;
|
||||
if let Some(manager) = guard.as_ref() {
|
||||
return Ok(manager.clone());
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
let mut guard = REGISTRY
|
||||
.sdk_manager
|
||||
.write()
|
||||
.map_err(|_| RegistryAccessError::Poisoned)?;
|
||||
Ok(guard
|
||||
.get_or_insert_with(|| {
|
||||
Arc::new(ShutdownManager::new_without_signals().with_cancel_on_panic())
|
||||
})
|
||||
.clone())
|
||||
}
|
||||
|
||||
/// Check if an SDK manager has been created.
|
||||
/// Useful for testing and debugging.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn has_sdk_manager() -> Result<bool, RegistryAccessError> {
|
||||
Ok(REGISTRY
|
||||
.sdk_manager
|
||||
.read()
|
||||
.map_err(|_| RegistryAccessError::Poisoned)?
|
||||
.is_some())
|
||||
}
|
||||
|
||||
/// Clear the SDK manager.
|
||||
/// This is primarily for testing to ensure isolation between tests.
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn clear() -> Result<(), RegistryAccessError> {
|
||||
*REGISTRY
|
||||
.sdk_manager
|
||||
.write()
|
||||
.map_err(|_| RegistryAccessError::Poisoned)? = None;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Global instance of the runtime registry.
|
||||
/// Uses LazyLock for on-demand initialization.
|
||||
static REGISTRY: LazyLock<RuntimeRegistry> = LazyLock::new(|| RuntimeRegistry {
|
||||
sdk_manager: RwLock::new(None),
|
||||
});
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_or_create_sdk() {
|
||||
// Clear any existing manager
|
||||
let _ = RuntimeRegistry::clear().await;
|
||||
|
||||
assert!(!RuntimeRegistry::has_sdk_manager().unwrap());
|
||||
|
||||
let manager1 = RuntimeRegistry::get_or_create_sdk().unwrap();
|
||||
assert!(RuntimeRegistry::has_sdk_manager().unwrap());
|
||||
|
||||
let manager2 = RuntimeRegistry::get_or_create_sdk().unwrap();
|
||||
// Should return the same instance
|
||||
assert!(Arc::ptr_eq(&manager1, &manager2));
|
||||
|
||||
let _ = RuntimeRegistry::clear().await;
|
||||
assert!(!RuntimeRegistry::has_sdk_manager().unwrap());
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ x25519-dalek = { workspace = true, features = ["static_secrets"] }
|
||||
cosmwasm-std = { workspace = true }
|
||||
cosmrs = { workspace = true }
|
||||
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client" }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
|
||||
@@ -50,6 +50,7 @@ zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-api-requests = { path = "../nym-api/nym-api-requests" }
|
||||
nym-bin-common = { path = "../common/bin-common" }
|
||||
nym-credentials = { path = "../common/credentials" }
|
||||
nym-credentials-interface = { path = "../common/credentials-interface" }
|
||||
nym-credential-verification = { path = "../common/credential-verification" }
|
||||
@@ -82,9 +83,24 @@ nym-service-provider-requests-common = { path = "../common/service-provider-requ
|
||||
|
||||
|
||||
defguard_wireguard_rs = { workspace = true }
|
||||
opentelemetry = { workspace = true, optional = true }
|
||||
opentelemetry_sdk = { workspace = true, optional = true }
|
||||
tracing-opentelemetry = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
nym-gateway-storage = { path = "../common/gateway-storage", features = ["mock"] }
|
||||
nym-wireguard = { path = "../common/wireguard", features = ["mock"] }
|
||||
mock_instant = "0.6.0"
|
||||
time = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
otel = [
|
||||
"nym-bin-common/otel",
|
||||
"nym-client-core/otel",
|
||||
"nym-gateway-requests/otel",
|
||||
"nym-sphinx/otel",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"tracing-opentelemetry",
|
||||
]
|
||||
|
||||
@@ -14,6 +14,8 @@ use futures::{
|
||||
future::{FusedFuture, OptionFuture},
|
||||
FutureExt, StreamExt,
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
use nym_bin_common::opentelemetry::context::ManualContextPropagator;
|
||||
use nym_credential_verification::CredentialVerifier;
|
||||
use nym_credential_verification::{
|
||||
bandwidth_storage_manager::BandwidthStorageManager, ClientBandwidth,
|
||||
@@ -31,6 +33,8 @@ use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_statistics_common::{gateways::GatewaySessionEvent, types::SessionType};
|
||||
use nym_validator_client::coconut::EcashApiError;
|
||||
use rand::{random, CryptoRng, Rng};
|
||||
#[cfg(feature = "otel")]
|
||||
use std::collections::HashMap;
|
||||
use std::{process, time::Duration};
|
||||
use thiserror::Error;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
@@ -147,6 +151,8 @@ pub(crate) struct AuthenticatedHandler<R, S> {
|
||||
// senders that are used to return the result of the ping to the handler requesting the ping.
|
||||
is_active_request_receiver: IsActiveRequestReceiver,
|
||||
is_active_ping_pending_reply: Option<(u64, IsActiveResultSender)>,
|
||||
#[cfg(feature = "otel")]
|
||||
pub otel_propagator: Option<ManualContextPropagator>,
|
||||
}
|
||||
|
||||
// explicitly remove handle from the global store upon being dropped
|
||||
@@ -189,6 +195,21 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
client_address: client.address.as_base58_string(),
|
||||
})?;
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
let manual_ctx_propagator = {
|
||||
let context = match client.otel_context {
|
||||
Some(ref ctx) => ctx.clone(),
|
||||
None => HashMap::new(),
|
||||
};
|
||||
|
||||
let manual_ctx_propagator = if !context.is_empty() {
|
||||
Some(ManualContextPropagator::new("upgrading_fresh_to_authenticated", context))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
manual_ctx_propagator
|
||||
};
|
||||
|
||||
let handler = AuthenticatedHandler {
|
||||
bandwidth_storage_manager: BandwidthStorageManager::new(
|
||||
Box::new(fresh.shared_state.storage.clone()),
|
||||
@@ -202,6 +223,8 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
mix_receiver,
|
||||
is_active_request_receiver,
|
||||
is_active_ping_pending_reply: None,
|
||||
#[cfg(feature = "otel")]
|
||||
otel_propagator: manual_ctx_propagator,
|
||||
};
|
||||
handler.send_metrics(GatewaySessionEvent::new_session_start(
|
||||
handler.client.address,
|
||||
@@ -227,7 +250,17 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `mix_packet`: packet received from the client that should get forwarded into the network.
|
||||
#[instrument(skip_all)]
|
||||
fn forward_packet(&self, mix_packet: MixPacket) {
|
||||
#[cfg(feature = "otel")]
|
||||
{
|
||||
let span = match &self.otel_propagator {
|
||||
Some(propagator) => info_span!(parent: &propagator.root_span, "forwarding_mix_packet"),
|
||||
None => info_span!("forwarding_mix_packet_no_otel"),
|
||||
};
|
||||
let _enter = span.enter();
|
||||
}
|
||||
|
||||
if let Err(err) = self
|
||||
.inner
|
||||
.shared_state
|
||||
@@ -287,6 +320,18 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
&mut self,
|
||||
mix_packet: MixPacket,
|
||||
) -> Result<ServerResponse, RequestHandlingError> {
|
||||
trace!("forwarding sphinx packet");
|
||||
#[cfg(feature = "otel")]
|
||||
let span = {
|
||||
let span = match &self.otel_propagator {
|
||||
Some(propagator) => info_span!(parent: &propagator.root_span, "handling_forward_sphinx"),
|
||||
None => debug_span!("handling_forward_sphinx_no_otel"),
|
||||
};
|
||||
span
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let _enter = span.enter();
|
||||
|
||||
let required_bandwidth = mix_packet.packet().len() as i64;
|
||||
|
||||
let remaining_bandwidth = self
|
||||
@@ -305,8 +350,20 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `bin_msg`: raw message to handle.
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_binary(&mut self, bin_msg: Vec<u8>) -> Message {
|
||||
trace!("binary request");
|
||||
#[cfg(feature = "otel")]
|
||||
let span = {
|
||||
let span = match &self.otel_propagator {
|
||||
Some(propagator) => info_span!(parent: &propagator.root_span, "handling_binary_request"),
|
||||
None => info_span!("handling_binary_request_no_otel"),
|
||||
};
|
||||
span
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let _enter = span.enter();
|
||||
|
||||
// this function decrypts the request and checks the MAC
|
||||
match BinaryRequest::try_from_encrypted_tagged_bytes(bin_msg, &self.client.shared_keys) {
|
||||
Err(e) => {
|
||||
@@ -379,6 +436,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
Ok(SensitiveServerResponse::KeyUpgradeAck {}.encrypt(&self.client.shared_keys)?)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_encrypted_text_request(
|
||||
&mut self,
|
||||
ciphertext: Vec<u8>,
|
||||
@@ -408,6 +466,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `raw_request`: raw message to handle.
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_text(&mut self, raw_request: String) -> Message
|
||||
where
|
||||
R: Rng + CryptoRng,
|
||||
@@ -552,6 +611,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_is_active_request(
|
||||
&mut self,
|
||||
reply_tx: IsActiveResultSender,
|
||||
@@ -582,16 +642,31 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
/// Simultaneously listens for incoming client requests, which realistically should only be
|
||||
/// binary requests to forward sphinx packets or increase bandwidth
|
||||
/// and for sphinx packets received from the mix network that should be sent back to the client.
|
||||
#[instrument(level = "debug", skip_all,
|
||||
fields(
|
||||
client = %self.client.address.as_base58_string()
|
||||
)
|
||||
)]
|
||||
pub(crate) async fn listen_for_requests(mut self)
|
||||
where
|
||||
R: Rng + CryptoRng,
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
{
|
||||
trace!("Started listening for ALL incoming requests...");
|
||||
|
||||
// Ping timeout future used to check if the client responded to our ping request
|
||||
let mut ping_timeout: OptionFuture<_> = None.into();
|
||||
|
||||
#[cfg(feature = "otel")]
|
||||
let from_client_span = {
|
||||
let span = match &self.otel_propagator {
|
||||
Some(propagator) => info_span!(parent: &propagator.root_span, "authenticated_client_handler_listen"),
|
||||
None => tracing::debug_span!("authenticated_client_handler_listen_no_otel"),
|
||||
};
|
||||
span
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let _enter = from_client_span.enter();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
// Received a request to ping the client to check if it's still active
|
||||
@@ -609,10 +684,10 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
},
|
||||
// The ping timeout expired, meaning the client didn't respond to our ping request
|
||||
_ = &mut ping_timeout, if !ping_timeout.is_terminated() => {
|
||||
ping_timeout = None.into();
|
||||
self.handle_ping_timeout().await;
|
||||
ping_timeout = None.into();
|
||||
self.handle_ping_timeout().await;
|
||||
},
|
||||
socket_msg = self.inner.read_websocket_message() => {
|
||||
socket_msg = self.inner.read_websocket_message().in_current_span() => {
|
||||
let socket_msg = match socket_msg {
|
||||
None => break,
|
||||
Some(Ok(socket_msg)) => socket_msg,
|
||||
@@ -627,7 +702,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
}
|
||||
|
||||
if let Some(response) = self.handle_request(socket_msg).await {
|
||||
if let Err(err) = self.inner.send_websocket_message(response).await {
|
||||
if let Err(err) = self.inner.send_websocket_message(response).in_current_span().await {
|
||||
debug!(
|
||||
"Failed to send message over websocket: {err}. Assuming the connection is dead.",
|
||||
);
|
||||
@@ -635,7 +710,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
}
|
||||
}
|
||||
},
|
||||
mix_messages = self.mix_receiver.next() => {
|
||||
mix_messages = self.mix_receiver.next().in_current_span() => {
|
||||
let mix_messages = match mix_messages {
|
||||
None => {
|
||||
debug!("mix receiver was closed! Assuming the connection is dead.");
|
||||
|
||||
@@ -13,6 +13,8 @@ use futures::{
|
||||
channel::{mpsc, oneshot},
|
||||
SinkExt, StreamExt,
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
use nym_bin_common::opentelemetry::context::ManualContextPropagator;
|
||||
use nym_credentials_interface::AvailableBandwidth;
|
||||
use nym_crypto::aes::cipher::crypto_common::rand_core::RngCore;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
@@ -34,6 +36,8 @@ use nym_node_metrics::events::MetricsEvent;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use nym_task::ShutdownToken;
|
||||
use rand::CryptoRng;
|
||||
#[cfg(feature = "otel")]
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
@@ -41,7 +45,11 @@ use time::OffsetDateTime;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio::time::timeout;
|
||||
use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
|
||||
use tracing::*;
|
||||
#[cfg(feature = "otel")]
|
||||
use tracing::info_span;
|
||||
use tracing::{debug, error, info, instrument, Instrument, warn};
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum InitialAuthenticationError {
|
||||
@@ -163,6 +171,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
|
||||
/// Attempts to perform websocket handshake with the remote and upgrades the raw TCP socket
|
||||
/// to the framed WebSocket.
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn perform_websocket_handshake(&mut self) -> Result<(), WsError>
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
@@ -186,6 +195,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `init_msg`: a client handshake init message which should contain its identity public key as well as an ephemeral key.
|
||||
#[instrument(skip_all)]
|
||||
async fn perform_registration_handshake(
|
||||
&mut self,
|
||||
init_msg: Vec<u8>,
|
||||
@@ -211,6 +221,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
}
|
||||
|
||||
/// Attempts to read websocket message from the associated socket.
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn read_websocket_message(&mut self) -> Option<Result<Message, WsError>>
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
@@ -226,6 +237,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `msg`: WebSocket message to write back to the client.
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn send_websocket_message(
|
||||
&mut self,
|
||||
msg: impl Into<Message>,
|
||||
@@ -242,6 +254,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn send_error_response(
|
||||
&mut self,
|
||||
err: impl std::error::Error,
|
||||
@@ -269,6 +282,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
///
|
||||
/// * `shared_keys`: keys derived between the client and gateway.
|
||||
/// * `packets`: unwrapped packets that are to be pushed back to the client.
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn push_packets_to_client(
|
||||
&mut self,
|
||||
shared_keys: &SharedGatewayKey,
|
||||
@@ -632,6 +646,8 @@ impl<R, S> FreshHandler<R, S> {
|
||||
address,
|
||||
shared_keys.key,
|
||||
session_request_start,
|
||||
#[cfg(feature = "otel")]
|
||||
None,
|
||||
)),
|
||||
ServerResponse::Authenticate {
|
||||
protocol_version: Some(negotiated_protocol),
|
||||
@@ -641,9 +657,14 @@ impl<R, S> FreshHandler<R, S> {
|
||||
))
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(
|
||||
address = %request.content.client_identity.derive_destination_address(),
|
||||
))]
|
||||
async fn handle_authenticate_v2(
|
||||
&mut self,
|
||||
request: Box<AuthenticateRequest>,
|
||||
#[cfg(feature = "otel")]
|
||||
otel_context: Option<HashMap<String, String>>,
|
||||
) -> Result<InitialAuthResult, InitialAuthenticationError>
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin,
|
||||
@@ -718,6 +739,8 @@ impl<R, S> FreshHandler<R, S> {
|
||||
address,
|
||||
shared_key.key,
|
||||
session_request_start,
|
||||
#[cfg(feature = "otel")]
|
||||
otel_context,
|
||||
)),
|
||||
ServerResponse::Authenticate {
|
||||
protocol_version: Some(negotiated_protocol),
|
||||
@@ -816,6 +839,8 @@ impl<R, S> FreshHandler<R, S> {
|
||||
remote_address,
|
||||
shared_keys,
|
||||
OffsetDateTime::now_utc(),
|
||||
#[cfg(feature = "otel")]
|
||||
None
|
||||
);
|
||||
|
||||
Ok(InitialAuthResult::new(
|
||||
@@ -846,6 +871,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn handle_initial_client_request(
|
||||
&mut self,
|
||||
request: ClientControlRequest,
|
||||
@@ -854,17 +880,45 @@ impl<R, S> FreshHandler<R, S> {
|
||||
S: AsyncRead + AsyncWrite + Unpin + Send,
|
||||
R: CryptoRng + RngCore + Send,
|
||||
{
|
||||
// we can handle stateless client requests without prior authentication, like `ClientControlRequest::SupportedProtocol`
|
||||
// extract and set up opentelemetry context if provided
|
||||
#[cfg(feature = "otel")]
|
||||
let (context_propagator, otel_ctx) = if let ClientControlRequest::AuthenticateV2(ref auth_req) = request {
|
||||
if let Some(otel_context) = &auth_req.otel_context {
|
||||
info!("=== OpenTelemetry context provided in the request: {otel_context:?} ===");
|
||||
(Some(ManualContextPropagator::new("handling_initial_client_request_with_otel", otel_context.clone())), Some(otel_context.clone()))
|
||||
} else {
|
||||
debug!("No OpenTelemetry context provided in the request");
|
||||
(None, None)
|
||||
}
|
||||
} else {
|
||||
debug!("No OpenTelemetry context provided in the request");
|
||||
(None, None)
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let child_span = match context_propagator {
|
||||
Some(ref propagator) => {
|
||||
let span = info_span!(parent: &propagator.root_span, "=== Handling initial client request with otel context ===");
|
||||
span
|
||||
}
|
||||
None => tracing::debug_span!("=== Handling initial client request without otel context ==="),
|
||||
};
|
||||
#[cfg(feature = "otel")]
|
||||
let _enter = child_span.enter();
|
||||
|
||||
let auth_result = match request {
|
||||
ClientControlRequest::Authenticate {
|
||||
protocol_version,
|
||||
address,
|
||||
enc_address,
|
||||
iv,
|
||||
otel_context: _,
|
||||
} => {
|
||||
self.handle_legacy_authenticate(protocol_version, address, enc_address, iv)
|
||||
.await
|
||||
}
|
||||
#[cfg(feature = "otel")]
|
||||
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req, otel_ctx).await,
|
||||
#[cfg(not(feature = "otel"))]
|
||||
ClientControlRequest::AuthenticateV2(req) => self.handle_authenticate_v2(req).await,
|
||||
ClientControlRequest::RegisterHandshakeInitRequest {
|
||||
protocol_version,
|
||||
@@ -889,13 +943,12 @@ impl<R, S> FreshHandler<R, S> {
|
||||
}
|
||||
other => debug!("authentication failure: {other}"),
|
||||
}
|
||||
|
||||
self.send_and_forget_error_response(&err).await;
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
// try to send auth response back to the client
|
||||
// try to send auth response back to the client
|
||||
if let Err(source) = self
|
||||
.send_websocket_message(auth_result.server_response)
|
||||
.await
|
||||
@@ -912,9 +965,11 @@ impl<R, S> FreshHandler<R, S> {
|
||||
warn!("could not establish client details");
|
||||
return Err(InitialAuthenticationError::EmptyClientDetails);
|
||||
};
|
||||
|
||||
Ok(Some(client_details))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn handle_until_authenticated_or_failure(
|
||||
mut self,
|
||||
) -> Option<AuthenticatedHandler<R, S>>
|
||||
@@ -953,7 +1008,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
registration_details.session_request_timestamp,
|
||||
);
|
||||
|
||||
return AuthenticatedHandler::upgrade(
|
||||
let auth_handle = AuthenticatedHandler::upgrade(
|
||||
self,
|
||||
registration_details,
|
||||
mix_receiver,
|
||||
@@ -962,10 +1017,12 @@ impl<R, S> FreshHandler<R, S> {
|
||||
.await
|
||||
.inspect_err(|err| error!("failed to upgrade client handler: {err}"))
|
||||
.ok();
|
||||
return auth_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn wait_for_initial_message(
|
||||
&mut self,
|
||||
) -> Result<ClientControlRequest, InitialAuthenticationError>
|
||||
@@ -1016,6 +1073,7 @@ impl<R, S> FreshHandler<R, S> {
|
||||
.map_err(|_| InitialAuthenticationError::InvalidRequest)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn start_handling(self)
|
||||
where
|
||||
S: AsyncRead + AsyncWrite + Unpin + Send,
|
||||
@@ -1025,10 +1083,10 @@ impl<R, S> FreshHandler<R, S> {
|
||||
let shutdown = self.shutdown.clone();
|
||||
tokio::select! {
|
||||
_ = shutdown.cancelled() => {
|
||||
trace!("received cancellation")
|
||||
tracing::trace!("received cancellation")
|
||||
}
|
||||
_ = super::handle_connection(self) => {
|
||||
debug!("finished connection handler for {remote}")
|
||||
_ = super::handle_connection(self).instrument(tracing::debug_span!("connection_handler", remote = %remote)) => {
|
||||
tracing::debug!("finished connection handler for {remote}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@ use nym_gateway_requests::shared_key::SharedGatewayKey;
|
||||
use nym_gateway_requests::ServerResponse;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use rand::{CryptoRng, Rng};
|
||||
#[cfg(feature = "otel")]
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
use tracing::{debug, instrument, trace, warn};
|
||||
#[cfg(feature = "otel")]
|
||||
use tracing::Instrument;
|
||||
|
||||
pub(crate) use self::authenticated::AuthenticatedHandler;
|
||||
pub(crate) use self::fresh::FreshHandler;
|
||||
@@ -48,6 +52,8 @@ pub(crate) struct ClientDetails {
|
||||
// note, this does **NOT ALWAYS** indicate timestamp of when client connected
|
||||
// it is (for v2 auth) timestamp the client **signed** when it created the request
|
||||
pub(crate) session_request_timestamp: OffsetDateTime,
|
||||
#[cfg(feature = "otel")]
|
||||
pub(crate) otel_context: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl ClientDetails {
|
||||
@@ -56,12 +62,16 @@ impl ClientDetails {
|
||||
address: DestinationAddressBytes,
|
||||
shared_keys: SharedGatewayKey,
|
||||
session_request_timestamp: OffsetDateTime,
|
||||
#[cfg(feature = "otel")]
|
||||
otel_context: Option<HashMap<String, String>>,
|
||||
) -> Self {
|
||||
ClientDetails {
|
||||
address,
|
||||
id,
|
||||
shared_keys,
|
||||
session_request_timestamp,
|
||||
#[cfg(feature = "otel")]
|
||||
otel_context,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +102,7 @@ impl InitialAuthResult {
|
||||
}
|
||||
|
||||
// imo there's no point in including the peer address in anything higher than debug
|
||||
#[instrument(level = "debug", skip_all, fields(peer = %handle.peer_address))]
|
||||
#[instrument(skip_all)]
|
||||
pub(crate) async fn handle_connection<R, S>(mut handle: FreshHandler<R, S>)
|
||||
where
|
||||
R: Rng + CryptoRng + Send,
|
||||
@@ -118,7 +128,23 @@ where
|
||||
trace!("managed to perform websocket handshake!");
|
||||
|
||||
if let Some(auth_handle) = handle.handle_until_authenticated_or_failure().await {
|
||||
auth_handle.listen_for_requests().await
|
||||
#[cfg(feature = "otel")]
|
||||
{
|
||||
let from_client_span = {
|
||||
let parent = match auth_handle.otel_propagator.as_ref() {
|
||||
Some(propagator) => propagator.root_span(),
|
||||
None => &tracing::Span::current(), // fallback to current span if no propagator
|
||||
};
|
||||
tracing::info_span!(parent: parent, "listening for requests")
|
||||
};
|
||||
auth_handle.listen_for_requests()
|
||||
.instrument(from_client_span)
|
||||
.await
|
||||
}
|
||||
#[cfg(not(feature = "otel"))]
|
||||
{
|
||||
auth_handle.listen_for_requests().await;
|
||||
}
|
||||
}
|
||||
|
||||
trace!("the handler is done!");
|
||||
|
||||
@@ -53,6 +53,7 @@ impl Listener {
|
||||
)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn try_handle_accepted_connection(&self, accepted: io::Result<(TcpStream, SocketAddr)>) {
|
||||
match accepted {
|
||||
Ok((socket, remote_address)) => {
|
||||
@@ -83,6 +84,7 @@ impl Listener {
|
||||
.network
|
||||
.new_ingress_websocket_client();
|
||||
|
||||
|
||||
// 4. spawn the task handling the client connection
|
||||
self.shutdown.try_spawn_named(
|
||||
async move {
|
||||
@@ -90,7 +92,7 @@ impl Listener {
|
||||
let metrics_ref = handle.shared_state.metrics.clone();
|
||||
|
||||
// 4.1. handle all client requests until connection gets terminated
|
||||
handle.start_handling().await;
|
||||
handle.start_handling().in_current_span().await;
|
||||
|
||||
// 4.2. decrement the connection counter
|
||||
metrics_ref.network.disconnected_ingress_websocket_client();
|
||||
@@ -104,6 +106,7 @@ impl Listener {
|
||||
|
||||
// TODO: change the signature to pub(crate) async fn run(&self, handler: Handler)
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn run(&mut self) {
|
||||
info!("Starting websocket listener at {}", self.address);
|
||||
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
|
||||
@@ -122,7 +125,7 @@ impl Listener {
|
||||
trace!("client_handling::Listener: received shutdown");
|
||||
break
|
||||
}
|
||||
connection = tcp_listener.accept() => {
|
||||
connection = tcp_listener.accept().in_current_span() => {
|
||||
self.try_handle_accepted_connection(connection)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,6 +979,7 @@ fn create_input_message(
|
||||
response_packet,
|
||||
lane,
|
||||
packet_type,
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
tracing::error!("No nym-address or sender tag provided");
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ nym-topology = { path = "../common/topology" }
|
||||
nym-api-requests = { path = "nym-api-requests" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
nym-http-api-client = { path = "../common/http-api-client" }
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["output_format", "openapi", "basic_tracing"] }
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["output_format", "openapi"] }
|
||||
nym-node-tester-utils = { path = "../common/node-tester-utils" }
|
||||
nym-node-requests = { path = "../nym-node/nym-node-requests" }
|
||||
nym-types = { path = "../common/types" }
|
||||
|
||||
@@ -168,7 +168,7 @@ impl BlindSignRequestBody {
|
||||
pub fn try_decode_joined_commitments(
|
||||
joined: &[u8],
|
||||
) -> Result<Vec<G1Projective>, CompactEcashError> {
|
||||
if joined.len() % 48 != 0 {
|
||||
if !joined.len().is_multiple_of(48) {
|
||||
// that's not the most ideal error variant, but creating dedicated error type would have been an overkill
|
||||
return Err(CompactEcashError::DeserializationLengthMismatch {
|
||||
type_name: "joined commitments".to_string(),
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||
// instrument tokio console subscriber needs RUSTFLAGS="--cfg tokio_unstable" at build time
|
||||
console_subscriber::init();
|
||||
} else {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
nym_bin_common::logging::setup_no_otel_logger().expect("failed to initialize logging");
|
||||
}}
|
||||
|
||||
info!("Starting nym api...");
|
||||
|
||||
@@ -67,8 +67,7 @@ pub struct PaginatedCachedNodesExpandedResponseSchema {
|
||||
/// Return all Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_nodes_expanded",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
|
||||
@@ -15,8 +15,7 @@ use nym_api_requests::nym_nodes::NodeRoleQueryParam;
|
||||
/// Return all Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_nodes_basic_all",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
@@ -53,8 +52,7 @@ pub(crate) async fn nodes_basic_all(
|
||||
/// Returns Nym Nodes and optionally legacy mixnodes (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded and support mixing role.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_mixnodes_basic_all",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParams),
|
||||
path = "/mixnodes/all",
|
||||
@@ -77,8 +75,7 @@ pub(crate) async fn mixnodes_basic_all(
|
||||
/// Returns Nym Nodes and optionally legacy mixnodes (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded and are in the active set with one of the mixing roles.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_mixnodes_basic_active",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParams),
|
||||
path = "/mixnodes/active",
|
||||
@@ -101,8 +98,7 @@ pub(crate) async fn mixnodes_basic_active(
|
||||
/// Returns Nym Nodes and optionally legacy gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded and support entry gateway role.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_entry_gateways_basic_all",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParams),
|
||||
path = "/entry-gateways",
|
||||
@@ -125,8 +121,7 @@ pub(crate) async fn entry_gateways_basic_all(
|
||||
/// Returns Nym Nodes and optionally legacy gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded and support exit gateway role.
|
||||
#[utoipa::path(
|
||||
operation_id = "v2_exit_gateways_basic_all",
|
||||
tag = "Unstable Nym Nodes v2",
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParams),
|
||||
path = "/exit-gateways",
|
||||
|
||||
@@ -1221,12 +1221,14 @@ fn create_input_message(
|
||||
surbs,
|
||||
TransmissionLane::General,
|
||||
None,
|
||||
None
|
||||
),
|
||||
IncludedSurbs::ExposeSelfAddress => nym_sdk::mixnet::InputMessage::new_regular(
|
||||
recipient,
|
||||
data,
|
||||
TransmissionLane::General,
|
||||
None,
|
||||
None
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-credential-proxy"
|
||||
version = "0.3.0"
|
||||
version = "0.2.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
@@ -45,9 +45,7 @@ utoipa = { workspace = true, features = ["axum_extras", "time"] }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
zeroize.workspace = true
|
||||
|
||||
nym-bin-common = { path = "../../common/bin-common", features = [
|
||||
"basic_tracing",
|
||||
] }
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-crypto = { path = "../../common/crypto", features = [
|
||||
|
||||
@@ -6,7 +6,7 @@ cfg_if::cfg_if! {
|
||||
use crate::cli::Cli;
|
||||
use clap::Parser;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::logging::setup_tracing_logger;
|
||||
use nym_bin_common::logging::setup_no_otel_logger;
|
||||
use nym_network_defaults::setup_env;
|
||||
use tracing::{info, trace};
|
||||
|
||||
@@ -29,7 +29,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
trace!("args: {cli:#?}");
|
||||
|
||||
setup_env(cli.config_env_file.as_ref());
|
||||
setup_tracing_logger();
|
||||
setup_no_otel_logger().expect("failed to initialize logging");
|
||||
|
||||
let bin_info = bin_info_owned!();
|
||||
info!("using the following version: {bin_info}");
|
||||
|
||||
@@ -195,5 +195,6 @@ fn create_input_message(
|
||||
surbs,
|
||||
TransmissionLane::General,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
tokio-postgres = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["basic_tracing"] }
|
||||
nym-bin-common = { path = "../common/bin-common" }
|
||||
nym-client-core = { path = "../common/client-core" }
|
||||
nym-crypto = { path = "../common/crypto" }
|
||||
nym-network-defaults = { path = "../common/network-defaults" }
|
||||
|
||||
@@ -187,7 +187,7 @@ async fn nym_topology_from_env() -> anyhow::Result<NymTopology> {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
nym_bin_common::logging::setup_tracing_logger();
|
||||
nym_bin_common::logging::setup_no_otel_logger().expect("failed to initialize logging");
|
||||
|
||||
let args = Args::parse();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-node-status-agent"
|
||||
version = "1.0.4"
|
||||
version = "1.0.6"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
@@ -36,6 +36,9 @@ WORKDIR /nym
|
||||
|
||||
COPY --from=builder /usr/src/nym/target/release/nym-node-status-agent ./
|
||||
COPY --from=builder /usr/src/nym-vpn-client/nym-vpn-core/target/release/nym-gateway-probe ./
|
||||
COPY --from=builder /usr/src/nym/nym-node-status-api/nym-node-status-agent/entrypoint.sh ./
|
||||
RUN chmod +x /nym/entrypoint.sh
|
||||
|
||||
ENV SLEEP_TIME=5
|
||||
ENV NODE_STATUS_AGENT_PROBE_PATH=/nym/nym-gateway-probe
|
||||
ENTRYPOINT [ "/nym/nym-node-status-agent", "run-probe" ]
|
||||
ENTRYPOINT [ "/nym/entrypoint.sh" ]
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Node Status Agent
|
||||
|
||||
An agent to run tests and report results back to the Node Status API.
|
||||
|
||||
Environment variables that can be set individually are:
|
||||
|
||||
- `NYM_NODE_MNEMONICS` - mnemonic to get tickets for tests
|
||||
- `NODE_STATUS_AGENT_SERVER_PORT` - Node Status API port
|
||||
- `NODE_STATUS_AGENT_SERVER_ADDRESS` - Node Status API address
|
||||
|
||||
Or use `NODE_STATUS_AGENT_ARGS` to pass your own arguments:
|
||||
|
||||
```
|
||||
NODE_STATUS_AGENT_ARGS="run-probe --server localhost:8000 --mnemonic foo bar baz"
|
||||
```
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Starting agent loop with sleep interval: ${SLEEP_TIME}s"
|
||||
|
||||
# Trap SIGTERM to allow graceful shutdown
|
||||
trap "echo 'Stopping...'; exit 0" SIGTERM
|
||||
|
||||
DEFAULT_ARGS="run-probe --server \"${NODE_STATUS_AGENT_SERVER_ADDRESS}|${NODE_STATUS_AGENT_SERVER_PORT}\" --mnemonic \"${NYM_NODE_MNEMONICS}\""
|
||||
ARGS=${NODE_STATUS_AGENT_ARGS:-${DEFAULT_ARGS}}
|
||||
COMMAND="/nym/nym-node-status-agent ${ARGS}"
|
||||
|
||||
echo "default_args = '${DEFAULT_ARGS}'"
|
||||
echo "args = '${ARGS}'"
|
||||
echo "command = '${COMMAND}'"
|
||||
|
||||
# Run probe in an infinite loop
|
||||
while true; do
|
||||
eval $COMMAND
|
||||
sleep "$SLEEP_TIME"
|
||||
done
|
||||
@@ -1,11 +1,7 @@
|
||||
# Example environment variables for nym-node-status-api
|
||||
|
||||
# Database configuration
|
||||
# For SQLite:
|
||||
# DATABASE_URL=sqlite://nym-node-status-api.sqlite
|
||||
|
||||
# For PostgreSQL:
|
||||
# DATABASE_URL=postgres://testuser:testpass@localhost:5433/nym_node_status_api_test
|
||||
# Database configuration for PostgreSQL:
|
||||
DATABASE_URL=postgres://testuser:testpass@localhost:5433/nym_node_status_api_test
|
||||
|
||||
# Network configuration
|
||||
NETWORK_NAME=sandbox
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO gateways (\n gateway_identity_key,\n bonded,\n performance,\n self_described,\n last_updated_utc\n ) VALUES ($1, $2, $3, $4, $5)\n RETURNING id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Int4",
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "117f96b2d0cec62858d065e700589f87d7d469fd301e831a1952641ec9375580"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n key as \"key!\",\n value_json as \"value_json!\",\n last_updated_utc as \"last_updated_utc!\"\n FROM summary",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "key!",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "value_json!",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "last_updated_utc!",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1327b5118f9144dddbcf8edb11f7dc549cf503409fd6dfedcdc02dbcd61d5454"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO nym_node_daily_mixing_stats (\n node_id, date_utc,\n total_stake, packets_received,\n packets_sent, packets_dropped\n ) VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT(node_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = nym_node_daily_mixing_stats.packets_received + excluded.packets_received,\n packets_sent = nym_node_daily_mixing_stats.packets_sent + excluded.packets_sent,\n packets_dropped = nym_node_daily_mixing_stats.packets_dropped + excluded.packets_dropped\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Varchar",
|
||||
"Int8",
|
||||
"Int4",
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "13c7178d57f28e11b47bc96d43ad14acd3c400ed9452db7095fac2a44ece8576"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n total_stake\n FROM nym_nodes\n WHERE node_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "total_stake",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "1c41eccf970cdc943ac2a343d03e6b229a2096d9fdac24d693005b57ed4333ca"
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n node_id,\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n bond_info IS NOT NULL\n AND\n self_described IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "node_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "bond_info: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf"
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT gateway_identity_key\n FROM gateways\n WHERE bonded = true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gateway_identity_key",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686"
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n node_id,\n ed25519_identity_pubkey,\n total_stake,\n ip_addresses as \"ip_addresses!: serde_json::Value\",\n mix_port,\n x25519_sphinx_pubkey,\n node_role as \"node_role: serde_json::Value\",\n supported_roles as \"supported_roles: serde_json::Value\",\n entry as \"entry: serde_json::Value\",\n performance,\n self_described as \"self_described: serde_json::Value\",\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n self_described IS NOT NULL\n AND\n bond_info IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "node_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "ed25519_identity_pubkey",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "total_stake",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "ip_addresses!: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "mix_port",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "x25519_sphinx_pubkey",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "node_role: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "supported_roles: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "entry: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "performance",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "self_described: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "bond_info: serde_json::Value",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE testruns SET status = $1 WHERE gateway_id = $2 AND status = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "32e1c6b00d97dbd4987062f46017512f33caff1be023c82d914514f17112c061"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n WITH oldest_queued AS (\n SELECT id\n FROM testruns\n WHERE status = $1\n ORDER BY created_utc asc\n LIMIT 1\n FOR UPDATE SKIP LOCKED\n )\n UPDATE testruns\n SET\n status = $3,\n last_assigned_utc = $2\n FROM oldest_queued\n WHERE testruns.id = oldest_queued.id\n RETURNING\n testruns.id,\n testruns.gateway_id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "gateway_id",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int8",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "38439a6c33bf21b90032659797105b6af747c3ae6f48bc41e5ec509a2d87abcc"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE testruns SET status = $1 WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3c4d989cdb23fcd626ce258846d167237f0baa96cf24fcff1c0fcaa6dedafbb3"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO gateway_session_stats\n (gateway_identity_key, node_id, day,\n unique_active_clients, session_started, users_hashes,\n vpn_sessions, mixnet_sessions, unknown_sessions)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n ON CONFLICT DO NOTHING",
|
||||
"query": "INSERT INTO gateway_session_stats\n (gateway_identity_key, node_id, day,\n unique_active_clients, session_started, users_hashes,\n vpn_sessions, mixnet_sessions, unknown_sessions)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n ON CONFLICT DO NOTHING;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -18,5 +18,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4fca38abbb416d9457c34a8ba4faf481a837eda4f3e1bee1d430a4eb102a5b3d"
|
||||
"hash": "4a664274579ea845f1db258dafedaf253b20c182174fc20062c98a49ffe4782a"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO summary\n (key, value_json, last_updated_utc)\n VALUES ($1, $2, $3)\n ON CONFLICT(key) DO UPDATE SET\n value_json=excluded.value_json,\n last_updated_utc=excluded.last_updated_utc;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4b671c10fe1ce968dd4cddb139fe13df44dbeee268dbb3a4ccfa403053b28707"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO summary_history\n (date, timestamp_utc, value_json)\n VALUES ($1, $2, $3)\n ON CONFLICT(date) DO UPDATE SET\n timestamp_utc=excluded.timestamp_utc,\n value_json=excluded.value_json;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int8",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4c55e15e47237149282bd8c0e3d861fc752db87fd57d7ff41709a7aa469b1aa5"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE gateways SET last_probe_log = $1 WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "528f96815c255353230ecbed2b7615b01fe87b1f88819d12f109f3556484772b"
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n nd.node_id,\n moniker,\n website,\n security_contact,\n details\n FROM\n nym_node_descriptions nd\n INNER JOIN\n nym_nodes nn on nd.node_id = nn.node_id\n WHERE\n bond_info IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "node_id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "moniker",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "website",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "security_contact",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "details",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "56854f703321ff8d8f30628c7e5322024ea01b778ab55efa9c7c6b219ef36308"
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO gateways\n (gateway_identity_key, bonded,\n self_described, explorer_pretty_bond,\n last_updated_utc, performance)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT(gateway_identity_key) DO UPDATE SET\n bonded=excluded.bonded,\n self_described=excluded.self_described,\n explorer_pretty_bond=excluded.explorer_pretty_bond,\n last_updated_utc=excluded.last_updated_utc,\n performance = excluded.performance;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Int8",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "57111a1b630945c8bea377bfd6bc1285d938f4c88ee5c277878d262400db5fb1"
|
||||
}
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n date_utc as \"date_utc!\",\n SUM(total_stake) as \"total_stake!: i64\",\n SUM(packets_received) as \"total_packets_received!: i64\",\n SUM(packets_sent) as \"total_packets_sent!: i64\",\n SUM(packets_dropped) as \"total_packets_dropped!: i64\"\n FROM (\n SELECT\n date_utc,\n n.total_stake,\n n.packets_received,\n n.packets_sent,\n n.packets_dropped\n FROM nym_node_daily_mixing_stats n\n )\n GROUP BY date_utc\n ORDER BY date_utc ASC\n ",
|
||||
"query": "\n SELECT\n date_utc as \"date_utc!\",\n SUM(total_stake)::bigint as \"total_stake!: i64\",\n SUM(packets_received)::bigint as \"total_packets_received!: i64\",\n SUM(packets_sent)::bigint as \"total_packets_sent!: i64\",\n SUM(packets_dropped)::bigint as \"total_packets_dropped!: i64\"\n FROM nym_node_daily_mixing_stats\n GROUP BY date_utc\n ORDER BY date_utc ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -11,7 +11,7 @@
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "total_stake!: i64",
|
||||
"type_info": "Numeric"
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
@@ -40,5 +40,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "32cf68dd34346fcac5cd0cd585845a9df296fdaebc5920dd1c12398e2967cffb"
|
||||
"hash": "5a5c764d89e2f19eec4dc994c83e4aedc4b62634ae22ccdfc218fb3c5ce58560"
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n id as \"id!\",\n date as \"date!\",\n timestamp_utc as \"timestamp_utc!\",\n value_json as \"value_json!\"\n FROM summary_history\n ORDER BY date DESC\n LIMIT 30",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id!",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "date!",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "timestamp_utc!",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "value_json!",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "7600823da7ce80b8ffda933608603a2752e28df775d1af8fd943a5fc8d7dc00d"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n gateway_identity_key\n FROM\n gateways\n WHERE\n id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gateway_identity_key",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "7b1c9b42347e83c396c51cfbd03558d124f3d4f0209de661832560001cddb0eb"
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT\n id,\n gateway_identity_key,\n self_described,\n explorer_pretty_bond\n FROM gateways\n WHERE gateway_identity_key = $1\n AND bonded = true\n ORDER BY gateway_identity_key\n LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int4"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "gateway_identity_key",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "self_described",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "explorer_pretty_bond",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "7e68a05cd72b223ba363aa497097dac4aa2f08d12ed1ce590f7ab9caafc9574d"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE\n testruns\n SET\n status = $1\n WHERE\n status = $2\n AND\n last_assigned_utc < $3\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int4",
|
||||
"Int4",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "82bf46daa4f64c93a90e3c7ee505e4d9eb9d0a4fe272663628fafada8e97213e"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user