Compare commits

..

2 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 6fd40e104f force client to use auth v1 2025-03-11 08:45:55 +00:00
Jon Häggblad 987ef5114c Always purge sender tags on startup 2025-03-09 00:42:17 +01:00
441 changed files with 9039 additions and 72162 deletions
-1
View File
@@ -1,2 +1 @@
nym-validator-rewarder/.sqlx/** diff=nodiff
nym-node-status-api/nym-node-status-api/.sqlx/** diff=nodiff
@@ -26,7 +26,6 @@ jobs:
runs-on: ${{ matrix.platform }}
env:
CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps:
- uses: actions/checkout@v4
@@ -12,7 +12,6 @@ jobs:
runs-on: arc-ubuntu-22.04
env:
CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps:
- name: Check out repository code
uses: actions/checkout@v4
-1
View File
@@ -37,7 +37,6 @@ jobs:
env:
CARGO_TERM_COLOR: always
IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }}
RUSTUP_PERMIT_COPY_RENAME: 1
steps:
- name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
@@ -1,57 +0,0 @@
name: ci-check-ns-api-version
on:
pull_request:
paths:
- "nym-node-status-api/**"
env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-api"
jobs:
check-if-tag-exists:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if git tag exists
run: |
TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
if [[ -z "$TAG" ]]; then
echo "Tag is empty"
exit 1
fi
git ls-remote --tags origin | awk '{print $2}'
if git ls-remote --tags origin | awk '{print $2}' | grep -q "refs/tags/$TAG$" ; then
echo "Tag '$TAG' ALREADY EXISTS on the remote"
exit 1
else
echo "Tag '$TAG' does not exist on the remote"
fi
- name: Check if harbor tag exists
run: |
TAG=${{ steps.get_version.outputs.result }}
registry=https://harbor.nymte.ch
repo_name=nym/node-status-api
if [[ -z $TAG ]]; then
echo "Tag is empty"
exit 1
fi
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq --arg tag $TAG '.tags | contains([$tag])' )
if [[ $exists = "true" ]]; then
echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo"
exit 1
elif [[ $exists = "false" ]]; then
echo "Version '$TAG' doesn't exist on the remote"
else
echo "Unknown output '$exists'"
exit 1
fi
Generated
+789 -851
View File
File diff suppressed because it is too large Load Diff
+23 -23
View File
@@ -137,7 +137,7 @@ members = [
"tools/internal/testnet-manager",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/validator-status-check",
"tools/internal/testnet-manager/dkg-bypass-contract",
"tools/nym-cli",
"tools/nym-id-cli",
"tools/nym-nr-query",
@@ -191,10 +191,10 @@ aes = "0.8.1"
aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1"
ammonia = "4"
anyhow = "1.0.97"
anyhow = "1.0.95"
arc-swap = "1.7.1"
argon2 = "0.5.0"
async-trait = "0.1.87"
async-trait = "0.1.86"
axum = "0.7.5"
axum-client-ip = "0.6.1"
axum-extra = "0.9.4"
@@ -205,24 +205,24 @@ bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] }
bit-vec = "0.7.0" # can we unify those?
bitvec = "1.0.0"
blake3 = "1.6.1"
blake3 = "1.5.5"
bloomfilter = "1.0.14"
bs58 = "0.5.1"
bytecodec = "0.4.15"
bytes = "1.10.1"
bytes = "1.7.2"
cargo_metadata = "0.18.1"
celes = "2.5.0"
cfg-if = "1.0.0"
chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1"
chrono = "0.4.40"
chrono = "0.4.39"
cipher = "0.4.3"
clap = "4.5.31"
clap = "4.5.30"
clap_complete = "4.5"
clap_complete_fig = "4.5"
colored = "2.2"
comfy-table = "7.1.4"
console = "0.15.11"
console = "0.15.10"
console-subscriber = "0.1.1"
console_error_panic_hook = "0.1"
const-str = "0.5.6"
@@ -247,12 +247,12 @@ envy = "0.4"
etherparse = "0.13.0"
eyre = "0.6.9"
fastrand = "2.1.1"
flate2 = "1.1.0"
flate2 = "1.0.35"
futures = "0.3.31"
futures-util = "0.3"
generic-array = "0.14.7"
getrandom = "0.2.10"
getset = "0.1.5"
getset = "0.1.4"
handlebars = "3.5.5"
headers = "0.4.0"
hex = "0.4.3"
@@ -273,7 +273,7 @@ inquire = "0.6.2"
ip_network = "0.4.1"
ipnetwork = "0.20"
isocountry = "0.3.2"
itertools = "0.14.0"
itertools = "0.13.0"
k256 = "0.13"
lazy_static = "1.5.0"
ledger-transport = "0.10.0"
@@ -308,14 +308,14 @@ reqwest = { version = "0.12.4", default-features = false }
rocket = "0.5.0"
rocket_cors = "0.6.0"
rocket_okapi = "0.8.0"
rs_merkle = "1.5.0"
rs_merkle = "1.4.2"
safer-ffi = "0.1.13"
schemars = "0.8.22"
semver = "1.0.26"
serde = "1.0.219"
serde_bytes = "0.11.17"
schemars = "0.8.21"
semver = "1.0.25"
serde = "1.0.217"
serde_bytes = "0.11.15"
serde_derive = "1.0"
serde_json = "1.0.140"
serde_json = "1.0.138"
serde_json_path = "0.7.2"
serde_repr = "0.1"
serde_with = "3.9.0"
@@ -331,10 +331,10 @@ syn = "1"
sysinfo = "0.33.0"
tap = "1.0.1"
tar = "0.4.44"
tempfile = "3.18"
tempfile = "3.15"
thiserror = "2.0"
time = "0.3.39"
tokio = "1.44"
time = "0.3.37"
tokio = "1.43"
tokio-postgres = "0.7"
tokio-stream = "0.1.17"
tokio-test = "0.4.4"
@@ -370,9 +370,9 @@ prometheus = { version = "0.13.0" }
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
# plus to make our live easier we need serde support from https://github.com/zkcrypto/bls12_381/pull/125
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect-updated" }
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.1", default-features = false }
ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0"
# cosmwasm-related
@@ -447,4 +447,4 @@ dbg_macro = "deny"
exit = "deny"
panic = "deny"
unimplemented = "deny"
unreachable = "deny"
unreachable = "deny"
-10
View File
@@ -67,13 +67,3 @@ As a general approach, licensing is as follows this pattern:
- documentation is Apache 2.0 or CC0-1.0
Nym Node Operators and Validators Terms and Conditions can be found [here](https://nym.com/operators-validators-terms).
## Getting Started
```bash
yarn install
```
```bash
yarn build
```
@@ -658,9 +658,6 @@ pub struct ReplySurbs {
/// Specifies the number of mixnet hops the packet should go through. If not specified, then
/// the default value is used.
pub surb_mix_hops: Option<u8>,
/// Specifies if we should reset all the sender tags on startup
pub fresh_sender_tags: bool,
}
impl Default for ReplySurbs {
@@ -678,7 +675,6 @@ impl Default for ReplySurbs {
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
surb_mix_hops: None,
fresh_sender_tags: false,
}
}
}
@@ -88,7 +88,7 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
let db_path = db_path.as_ref();
if db_path.exists() {
info!("loading existing surb database");
match fs_backend::Backend::try_load(db_path, surb_config.fresh_sender_tags).await {
match fs_backend::Backend::try_load(db_path).await {
Ok(backend) => Ok(backend),
Err(err) => {
error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future");
@@ -10,7 +10,7 @@ use crate::{
CombinedReplyStorage, ReceivedReplySurbsMap, ReplyStorageBackend, SentReplyKeys, UsedSenderTags,
};
use async_trait::async_trait;
use log::{debug, error, info, warn};
use log::{error, info, warn};
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use std::fs;
use std::path::{Path, PathBuf};
@@ -52,10 +52,7 @@ impl Backend {
Ok(backend)
}
pub async fn try_load<P: AsRef<Path>>(
database_path: P,
fresh_sender_tags: bool,
) -> Result<Self, StorageError> {
pub async fn try_load<P: AsRef<Path>>(database_path: P) -> Result<Self, StorageError> {
let owned_path: PathBuf = database_path.as_ref().into();
if owned_path.file_name().is_none() {
return Err(StorageError::DatabasePathWithoutFilename {
@@ -121,11 +118,15 @@ impl Backend {
if days > 2 {
info!("it's been over {days} days and {hours} hours since we last used our data store. our used sender tags are already outdated - we're going to purge them now.");
manager.delete_all_tags().await?;
} else if fresh_sender_tags {
debug!("starting with fresh sender tags");
manager.delete_all_tags().await?;
}
// We ran into a bug where the client was re-using the same sender tag while connected to
// different gateways. This does not work since changing the gateway changes the
// nym-addres.
// A stop-gap solution is to always purge the tags when the client is started.
// When writing this I'm not yet sure what the correct solution is.
manager.delete_all_tags().await?;
Ok(Backend {
temporary_old_path: None,
database_path: owned_path,
@@ -204,15 +204,15 @@ impl<C, St> GatewayClient<C, St> {
"Attemting to establish connection to gateway at: {}",
self.gateway_address
);
let (ws_stream, _) = connect_async(
&self.gateway_address,
#[cfg(unix)]
self.connection_fd_callback.clone(),
)
.await?;
let (ws_stream, _) = connect_async(&self.gateway_address).await?;
self.connection = SocketState::Available(Box::new(ws_stream));
#[cfg(unix)]
if let (Some(callback), Some(fd)) = (self.connection_fd_callback.as_ref(), self.ws_fd()) {
callback.as_ref()(fd);
}
Ok(())
}
@@ -683,7 +683,7 @@ impl<C, St> GatewayClient<C, St> {
}
if self.shared_key.is_some() {
self.authenticate(supports_auth_v2).await?;
self.authenticate(false).await?;
if self.authenticated {
// if we are authenticated it means we MUST have an associated shared_key
@@ -1016,8 +1016,7 @@ impl<C, St> GatewayClient<C, St> {
}
// if we're reconnecting, because we lost connection, we need to re-authenticate the connection
self.authenticate(self.negotiated_protocol.supports_authenticate_v2())
.await?;
self.authenticate(false).await?;
// this call is NON-blocking
self.start_listening_for_mixnet_messages()?;
@@ -1,11 +1,6 @@
use crate::error::GatewayClientError;
use nym_http_api_client::HickoryDnsResolver;
#[cfg(unix)]
use std::{
os::fd::{AsRawFd, RawFd},
sync::Arc,
};
use tokio::net::TcpStream;
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
use tungstenite::handshake::client::Response;
@@ -16,10 +11,7 @@ use std::net::SocketAddr;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) async fn connect_async(
endpoint: &str,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), GatewayClientError> {
use tokio::net::TcpSocket;
let resolver = HickoryDnsResolver::default();
let uri =
Url::parse(endpoint).map_err(|_| GatewayClientError::InvalidUrl(endpoint.to_owned()))?;
@@ -45,41 +37,14 @@ pub(crate) async fn connect_async(
}
};
let mut stream = Err(GatewayClientError::NoEndpointForConnection {
address: endpoint.to_owned(),
});
for sock_addr in sock_addrs {
let socket = if sock_addr.is_ipv4() {
TcpSocket::new_v4()
} else {
TcpSocket::new_v6()
}
.map_err(|err| GatewayClientError::NetworkConnectionFailed {
let stream = TcpStream::connect(&sock_addrs[..]).await.map_err(|error| {
GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
source: err.into(),
})?;
#[cfg(unix)]
if let Some(callback) = connection_fd_callback.as_ref() {
callback.as_ref()(socket.as_raw_fd());
source: error.into(),
}
})?;
match socket.connect(sock_addr).await {
Ok(s) => {
stream = Ok(s);
break;
}
Err(err) => {
stream = Err(GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
source: err.into(),
});
continue;
}
}
}
tokio_tungstenite::client_async_tls(endpoint, stream?)
tokio_tungstenite::client_async_tls(endpoint, stream)
.await
.map_err(|error| GatewayClientError::NetworkConnectionFailed {
address: endpoint.to_owned(),
@@ -43,9 +43,6 @@ pub enum GatewayClientError {
#[error("connection failed: {address}: {source}")]
NetworkConnectionFailed { address: String, source: WsError },
#[error("no socket address for endpoint: {address}")]
NoEndpointForConnection { address: String },
#[error("Invalid URL: {0}")]
InvalidUrl(String),
@@ -23,12 +23,11 @@ use nym_api_requests::models::{
NymNodeDescription, RewardEstimationResponse, StakeSaturationResponse,
};
use nym_api_requests::models::{LegacyDescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::nym_nodes::{NodesByAddressesResponse, SkimmedNode};
use nym_api_requests::nym_nodes::SkimmedNode;
use nym_coconut_dkg_common::types::EpochId;
use nym_ecash_contract_common::deposit::DepositId;
use nym_http_api_client::UserAgent;
use nym_network_defaults::NymNetworkDetails;
use std::net::IpAddr;
use time::Date;
use url::Url;
@@ -711,11 +710,4 @@ impl NymApiClient {
.issued_ticketbooks_challenge(expiration_date, deposits)
.await?)
}
pub async fn nodes_by_addresses(
&self,
addresses: Vec<IpAddr>,
) -> Result<NodesByAddressesResponse, ValidatorClientError> {
Ok(self.nym_api.nodes_by_addresses(addresses).await?)
}
}
@@ -83,12 +83,6 @@ impl TryFrom<ContractVKShare> for EcashApiClient {
let url_address = Url::parse(&share.announce_address)?;
// The NymApiClient constructed here uses the default (hickory DoT/DoH) resolver because
// this EcashApiClient is used by both client and non-client applications.
//
// In non-client applications this resolver can cause warning logs about H2 connection
// failure. This indicates that the long lived https connection was closed by the remote
// peer and the resolver will have to reconnect. It should not impact actual functionality
Ok(EcashApiClient {
api_client: NymApiClient::new(url_address),
verification_key: VerificationKeyAuth::try_from_bs58(&share.share)?,
@@ -12,13 +12,10 @@ use nym_api_requests::ecash::models::{
};
use nym_api_requests::ecash::VerificationKeyResponse;
use nym_api_requests::models::{
AnnotationResponse, ApiHealthResponse, BinaryBuildInformationOwned, ChainStatusResponse,
LegacyDescribedMixNode, NodePerformanceResponse, NodeRefreshBody, NymNodeDescription,
PerformanceHistoryResponse, RewardedSetResponse,
};
use nym_api_requests::nym_nodes::{
NodesByAddressesRequestBody, NodesByAddressesResponse, PaginatedCachedNodesResponse,
AnnotationResponse, ApiHealthResponse, LegacyDescribedMixNode, NodePerformanceResponse,
NodeRefreshBody, NymNodeDescription, PerformanceHistoryResponse, RewardedSetResponse,
};
use nym_api_requests::nym_nodes::PaginatedCachedNodesResponse;
use nym_api_requests::pagination::PaginatedResponse;
pub use nym_api_requests::{
ecash::{
@@ -43,7 +40,6 @@ pub use nym_http_api_client::Client;
use nym_http_api_client::{ApiClient, NO_PARAMS};
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, NodeId, NymNodeDetails};
use std::net::IpAddr;
use time::format_description::BorrowedFormatItem;
use time::Date;
use tracing::instrument;
@@ -70,19 +66,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
#[instrument(level = "debug", skip(self))]
async fn build_information(&self) -> Result<BinaryBuildInformationOwned, NymAPIError> {
self.get_json(
&[
routes::API_VERSION,
routes::API_STATUS_ROUTES,
routes::BUILD_INFORMATION,
],
NO_PARAMS,
)
.await
}
#[deprecated]
#[instrument(level = "debug", skip(self))]
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
@@ -1032,23 +1015,6 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn nodes_by_addresses(
&self,
addresses: Vec<IpAddr>,
) -> Result<NodesByAddressesResponse, NymAPIError> {
self.post_json(
&[
routes::API_VERSION,
"unstable",
routes::NYM_NODES_ROUTES,
routes::nym_nodes::BY_ADDRESSES,
],
NO_PARAMS,
&NodesByAddressesRequestBody { addresses },
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_network_details(&self) -> Result<NymNetworkDetailsResponse, NymAPIError> {
self.get_json(
@@ -1057,15 +1023,6 @@ pub trait NymApiClientExt: ApiClient {
)
.await
}
#[instrument(level = "debug", skip(self))]
async fn get_chain_status(&self) -> Result<ChainStatusResponse, NymAPIError> {
self.get_json(
&[routes::API_VERSION, routes::NETWORK, routes::CHAIN_STATUS],
NO_PARAMS,
)
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -43,14 +43,11 @@ pub mod nym_nodes {
pub const NYM_NODES_BONDED: &str = "bonded";
pub const NYM_NODES_REWARDED_SET: &str = "rewarded-set";
pub const NYM_NODES_REFRESH_DESCRIBED: &str = "refresh-described";
pub const BY_ADDRESSES: &str = "by-addresses";
}
pub const STATUS_ROUTES: &str = "status";
pub const API_STATUS_ROUTES: &str = "api-status";
pub const HEALTH: &str = "health";
pub const BUILD_INFORMATION: &str = "build-information";
pub const MIXNODE: &str = "mixnode";
pub const GATEWAY: &str = "gateway";
pub const NYM_NODES: &str = "nym-nodes";
@@ -72,5 +69,4 @@ pub const SUBMIT_NODE: &str = "submit-node-monitoring-results";
pub const SERVICE_PROVIDERS: &str = "services";
pub const DETAILS: &str = "details";
pub const CHAIN_STATUS: &str = "chain-status";
pub const NETWORK: &str = "network";
@@ -62,7 +62,6 @@ pub use cw3;
pub use cw4;
pub use cw_controllers;
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
pub use prost::Name;
pub use tendermint_rpc::endpoint::block::Response as BlockResponse;
pub use tendermint_rpc::{
endpoint::{tx::Response as TxResponse, validators::Response as ValidatorResponse},
+9
View File
@@ -25,6 +25,15 @@ pub fn in6addr_any_init() -> IpAddr {
IpAddr::V6(Ipv6Addr::UNSPECIFIED)
}
/// Helper for providing binding warnings if node tries to bind to any of those
pub const SPECIAL_ADDRESSES: &[IpAddr] = &[
IpAddr::V4(Ipv4Addr::LOCALHOST),
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
IpAddr::V4(Ipv4Addr::BROADCAST),
IpAddr::V6(Ipv6Addr::LOCALHOST),
IpAddr::V6(Ipv6Addr::UNSPECIFIED),
];
// TODO: is it really part of 'Config'?
pub trait OptionalSet {
/// If the value is available (i.e. `Some`), the provided closure is applied.
+1 -1
View File
@@ -21,7 +21,7 @@ lazy_static = { workspace = true }
rand = { workspace = true }
rand_chacha = { workspace = true }
rand_core = { workspace = true }
sha2 = { workspace = true }
sha2 = "0.9"
serde = { workspace = true }
serde_derive = { workspace = true }
thiserror = { workspace = true }
+2 -96
View File
@@ -54,12 +54,12 @@ pub(crate) fn hash_to_scalar<M: AsRef<[u8]>>(msg: M, domain: &[u8]) -> Scalar {
pub(crate) fn hash_to_scalars<M: AsRef<[u8]>>(msg: M, domain: &[u8], n: usize) -> Vec<Scalar> {
let mut output = vec![Scalar::zero(); n];
Scalar::hash_to_field::<ExpandMsgXmd<Sha256>, _>([msg], domain, &mut output);
Scalar::hash_to_field::<ExpandMsgXmd<Sha256>>(msg.as_ref(), domain, &mut output);
output
}
pub(crate) fn hash_g2<M: AsRef<[u8]>>(msg: M, domain: &[u8]) -> G2Projective {
<G2Projective as HashToCurve<ExpandMsgXmd<Sha256>>>::hash_to_curve([msg], domain)
<G2Projective as HashToCurve<ExpandMsgXmd<Sha256>>>::hash_to_curve(msg, domain)
}
pub(crate) fn combine_scalar_chunks(chunks: &[Scalar]) -> Scalar {
@@ -112,97 +112,3 @@ pub(crate) fn deserialize_g2(b: &[u8]) -> Option<G2Projective> {
G2Projective::from_bytes(&encoding).into()
}
}
#[cfg(test)]
mod tests {
use super::*;
use bls12_381::G2Affine;
#[test]
fn test_hash_to_scalar() {
let msg1 = "foo";
let expected1 = Scalar::from_bytes(&[
253, 57, 224, 227, 175, 195, 226, 82, 46, 175, 33, 126, 171, 239, 255, 92, 108, 168, 6,
79, 90, 11, 235, 236, 221, 10, 85, 133, 42, 81, 95, 30,
])
.unwrap();
let msg2 = "bar";
let expected2 = Scalar::from_bytes(&[
48, 83, 69, 52, 42, 18, 135, 244, 211, 190, 160, 196, 118, 154, 24, 126, 0, 125, 72,
201, 170, 225, 123, 201, 52, 120, 171, 132, 235, 182, 20, 26,
])
.unwrap();
let msg3 = [
33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123,
250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27,
115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101,
60, 42, 92, 128, 131, 161, 43,
];
let expected3 = Scalar::from_bytes(&[
128, 189, 8, 43, 186, 55, 52, 61, 171, 196, 159, 177, 162, 100, 27, 143, 85, 83, 218,
171, 91, 220, 155, 25, 7, 38, 2, 36, 4, 93, 136, 4,
])
.unwrap();
assert_eq!(
hash_to_scalar(msg1, b"NYMECASH-V01-CS02-with-expander-SHA256"),
expected1
);
assert_eq!(
hash_to_scalar(msg2, b"NYMECASH-V01-CS02-with-expander-SHA256"),
expected2
);
assert_eq!(
hash_to_scalar(msg3, b"NYMECASH-V01-CS02-with-expander-SHA256"),
expected3
);
}
#[test]
fn test_hash_g2() {
let msg1 = "foo";
let expected1 = G2Affine::from_compressed(&[
175, 187, 62, 7, 29, 17, 42, 93, 28, 93, 234, 253, 101, 166, 158, 187, 153, 82, 93, 18,
11, 233, 36, 107, 51, 117, 30, 127, 32, 254, 210, 77, 133, 12, 253, 255, 84, 128, 36,
214, 234, 103, 50, 21, 26, 78, 112, 49, 20, 69, 19, 109, 7, 78, 33, 227, 196, 180, 168,
219, 73, 251, 192, 221, 41, 138, 160, 131, 191, 186, 156, 117, 179, 179, 191, 235, 171,
26, 219, 148, 170, 179, 11, 38, 137, 14, 95, 115, 171, 186, 163, 82, 158, 6, 239, 88,
])
.unwrap()
.into();
let msg2 = "bar";
let expected2 = G2Affine::from_compressed(&[
183, 25, 90, 187, 34, 184, 30, 182, 215, 242, 158, 83, 116, 34, 210, 96, 188, 79, 83,
255, 100, 122, 90, 188, 196, 93, 164, 253, 20, 106, 205, 33, 48, 140, 60, 149, 66, 246,
121, 244, 146, 66, 170, 60, 113, 95, 102, 237, 25, 231, 8, 42, 121, 124, 180, 140, 34,
104, 173, 251, 89, 189, 28, 196, 49, 66, 101, 38, 68, 44, 40, 235, 21, 35, 204, 123,
218, 238, 216, 92, 134, 217, 212, 246, 176, 77, 187, 0, 245, 134, 132, 73, 31, 44, 137,
197,
])
.unwrap()
.into();
let msg3 = [
33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123,
250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27,
115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101,
60, 42, 92, 128, 131, 161, 43,
];
let expected3 = G2Affine::from_compressed(&[
151, 185, 8, 123, 223, 150, 192, 192, 115, 10, 3, 129, 49, 179, 31, 108, 0, 17, 46,
231, 184, 164, 247, 228, 22, 142, 87, 70, 120, 111, 154, 15, 245, 110, 32, 84, 53, 117,
239, 93, 89, 119, 32, 17, 39, 250, 198, 137, 6, 95, 137, 202, 54, 244, 238, 190, 11,
217, 237, 95, 72, 59, 140, 56, 3, 42, 61, 195, 192, 101, 46, 204, 207, 75, 70, 176,
207, 48, 24, 195, 248, 234, 178, 168, 54, 109, 19, 189, 51, 52, 120, 69, 248, 226, 102,
91,
])
.unwrap()
.into();
assert_eq!(hash_g2(msg1, b"DUMMY_TEST_DOMAIN"), expected1);
assert_eq!(hash_g2(msg2, b"DUMMY_TEST_DOMAIN"), expected2);
assert_eq!(hash_g2(msg3, b"DUMMY_TEST_DOMAIN"), expected3);
}
}
+6 -7
View File
@@ -10,7 +10,6 @@ use nym_sphinx::params::packet_sizes::PacketSize;
use serde::{Deserialize, Serialize};
use std::string::FromUtf8Error;
use thiserror::Error;
use time::OffsetDateTime;
// specific errors (that should not be nested!!) for clients to match on
#[derive(Debug, Copy, Clone, Error, Serialize, Deserialize)]
@@ -113,15 +112,15 @@ pub enum AuthenticationFailure {
#[error("failed to verify request signature")]
InvalidSignature(#[from] SignatureError),
#[error("provided request timestamp is in the future")]
RequestTimestampInFuture,
#[error("the client is not registered")]
NotRegistered,
#[error("the provided request timestamp is excessively skewed. got {received} whilst the server time is {server}")]
ExcessiveTimestampSkew {
received: OffsetDateTime,
server: OffsetDateTime,
},
#[error("the provided request is too stale to process")]
StaleRequest,
#[error("the provided request timestamp is smaller or equal to one previously used")]
#[error("the provided request timestamp is smaller or equal to a one previously used")]
RequestReuse,
}
@@ -38,22 +38,13 @@ impl AuthenticateRequest {
})
}
pub fn verify_timestamp(
&self,
max_request_timestamp_skew: Duration,
) -> Result<(), AuthenticationFailure> {
pub fn verify_timestamp(&self, max_request_age: Duration) -> Result<(), AuthenticationFailure> {
let now = OffsetDateTime::now_utc();
if self.content.request_timestamp() < now - max_request_timestamp_skew {
return Err(AuthenticationFailure::ExcessiveTimestampSkew {
received: self.content.request_timestamp(),
server: now,
});
if self.content.request_timestamp() + max_request_age < now {
return Err(AuthenticationFailure::StaleRequest);
}
if self.content.request_timestamp() - max_request_timestamp_skew > now {
return Err(AuthenticationFailure::ExcessiveTimestampSkew {
received: self.content.request_timestamp(),
server: now,
});
if self.content.request_timestamp() > now {
return Err(AuthenticationFailure::RequestTimestampInFuture);
}
Ok(())
}
-23
View File
@@ -1,6 +1,3 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
//! DNS resolver configuration for internal lookups.
//!
//! The resolver itself is the set combination of the google, cloudflare, and quad9 endpoints
@@ -12,19 +9,6 @@
//!
//! Requires the `dns-over-https-rustls`, `webpki-roots` feature for the
//! `hickory-resolver` crate
//!
//!
//! Note: The hickory DoH resolver can cause warning logs about H2 connection failure. This
//! indicates that the long lived https connection was closed by the remote peer and the resolver
//! will have to reconnect. It should not impact actual functionality.
//!
//! code ref: https://github.com/hickory-dns/hickory-dns/blob/06a8b1ce9bd9322d8e6accf857d30257e1274427/crates/proto/src/h2/h2_client_stream.rs#L534
//!
//! example log:
//!
//! ```txt
//! WARN /home/ubuntu/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/hickory-proto-0.24.3/src/h2/h2_client_stream.rs:493: h2 connection failed: unexpected end of file
//! ```
#![deny(missing_docs)]
use crate::ClientBuilder;
@@ -49,13 +33,6 @@ impl ClientBuilder {
/// Override the DNS resolver implementation used by the underlying http client.
pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> Self {
self.reqwest_client_builder = self.reqwest_client_builder.dns_resolver(resolver);
self.use_secure_dns = false;
self
}
/// Override the DNS resolver implementation used by the underlying http client.
pub fn no_hickory_dns(mut self) -> Self {
self.use_secure_dns = false;
self
}
}
+20 -42
View File
@@ -228,8 +228,6 @@ pub struct ClientBuilder {
timeout: Option<Duration>,
custom_user_agent: bool,
reqwest_client_builder: reqwest::ClientBuilder,
#[allow(dead_code)] // not dead code, just unused in wasm
use_secure_dns: bool,
}
impl ClientBuilder {
@@ -241,46 +239,37 @@ impl ClientBuilder {
U: IntoUrl,
E: Display,
{
// a naive check: if the provided URL does not start with http(s), add that scheme
let str_url = url.as_str();
// a naive check: if the provided URL does not start with http(s), add that scheme
if !str_url.starts_with("http") {
let alt = format!("http://{str_url}");
warn!("the provided url ('{str_url}') does not contain scheme information. Changing it to '{alt}' ...");
// TODO: or should we maybe default to https?
Self::new(alt)
} else {
Ok(Self::new_with_url(url.into_url()?))
}
}
#[cfg(target_arch = "wasm32")]
let reqwest_client_builder = reqwest::ClientBuilder::new();
/// Constructs a new http `ClientBuilder` from a valid url.
pub fn new_with_url(url: Url) -> Self {
if !url.scheme().starts_with("http") {
warn!("the provided url ('{url}') does not use HTTP / HTTPS scheme");
}
#[cfg(not(target_arch = "wasm32"))]
let reqwest_client_builder = {
let r = reqwest::ClientBuilder::new()
.dns_resolver(Arc::new(HickoryDnsResolver::default()));
#[cfg(target_arch = "wasm32")]
let reqwest_client_builder = reqwest::ClientBuilder::new();
// Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which
// `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."`
//
// I am going to leave it here anyways so that gzip decompression is attempted even if
// that feature is removed.
r.gzip(true)
};
#[cfg(not(target_arch = "wasm32"))]
let reqwest_client_builder = {
let r = reqwest::ClientBuilder::new();
// Note this is extra as the `gzip` feature for `reqwest` crate should be enabled which
// `"Enable[s] auto gzip decompression by checking the Content-Encoding response header."`
//
// I am going to leave it here anyways so that gzip decompression is attempted even if
// that feature is removed.
r.gzip(true)
};
ClientBuilder {
url,
timeout: None,
custom_user_agent: false,
reqwest_client_builder,
use_secure_dns: true,
Ok(ClientBuilder {
url: url.into_url()?,
timeout: None,
custom_user_agent: false,
reqwest_client_builder,
})
}
}
@@ -336,18 +325,10 @@ impl ClientBuilder {
let mut builder = self
.reqwest_client_builder
.timeout(self.timeout.unwrap_or(DEFAULT_TIMEOUT));
// if no custom user agent was set, use a default
if !self.custom_user_agent {
builder =
builder.user_agent(format!("nym-http-api-client/{}", env!("CARGO_PKG_VERSION")))
}
// unless explicitly disabled use the DoT/DoH enabled resolver
if self.use_secure_dns {
builder = builder.dns_resolver(Arc::new(HickoryDnsResolver::default()));
}
builder.build()?
};
@@ -374,9 +355,6 @@ pub struct Client {
impl Client {
/// Create a new http `Client`
// no timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
//
// In order to prevent interference in API requests at the DNS phase we default to a resolver
// that uses DoT and DoH.
pub fn new(base_url: Url, timeout: Option<Duration>) -> Self {
Self::new_url::<_, String>(base_url, timeout).expect(
"we provided valid url and we were unwrapping previous construction errors anyway",
+2 -2
View File
@@ -15,10 +15,10 @@ bls12_381 = { workspace = true, features = ["alloc", "pairings", "experimental",
bincode.workspace = true
cfg-if.workspace = true
itertools = { workspace = true }
digest = { workspace = true }
digest = "0.9"
rand = { workspace = true }
thiserror = { workspace = true }
sha2 = { workspace = true }
sha2 = "0.9"
bs58 = { workspace = true }
serde = { workspace = true, features = ["derive"] }
rayon = { workspace = true, optional = true }
+6 -73
View File
@@ -113,13 +113,17 @@ const G1_HASH_DOMAIN: &[u8] = b"NYMECASH-V01-CS02-with-BLS12381G1_XMD:SHA-256_SS
const SCALAR_HASH_DOMAIN: &[u8] = b"NYMECASH-V01-CS02-with-expander-SHA256";
pub fn hash_g1<M: AsRef<[u8]>>(msg: M) -> G1Projective {
<G1Projective as HashToCurve<ExpandMsgXmd<sha2::Sha256>>>::hash_to_curve([msg], G1_HASH_DOMAIN)
<G1Projective as HashToCurve<ExpandMsgXmd<sha2::Sha256>>>::hash_to_curve(msg, G1_HASH_DOMAIN)
}
pub fn hash_to_scalar<M: AsRef<[u8]>>(msg: M) -> Scalar {
let mut output = vec![Scalar::zero()];
Scalar::hash_to_field::<ExpandMsgXmd<sha2::Sha256>, _>([msg], SCALAR_HASH_DOMAIN, &mut output);
Scalar::hash_to_field::<ExpandMsgXmd<sha2::Sha256>>(
msg.as_ref(),
SCALAR_HASH_DOMAIN,
&mut output,
);
output[0]
}
@@ -397,75 +401,4 @@ mod tests {
assert_eq!(hash_to_scalar(msg2), hash_to_scalar(msg2));
assert_ne!(hash_to_scalar(msg1), hash_to_scalar(msg2));
}
#[test]
fn test_hash_to_scalar() {
let msg1 = "foo";
let expected1 = Scalar::from_bytes(&[
253, 57, 224, 227, 175, 195, 226, 82, 46, 175, 33, 126, 171, 239, 255, 92, 108, 168, 6,
79, 90, 11, 235, 236, 221, 10, 85, 133, 42, 81, 95, 30,
])
.unwrap();
let msg2 = "bar";
let expected2 = Scalar::from_bytes(&[
48, 83, 69, 52, 42, 18, 135, 244, 211, 190, 160, 196, 118, 154, 24, 126, 0, 125, 72,
201, 170, 225, 123, 201, 52, 120, 171, 132, 235, 182, 20, 26,
])
.unwrap();
let msg3 = [
33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123,
250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27,
115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101,
60, 42, 92, 128, 131, 161, 43,
];
let expected3 = Scalar::from_bytes(&[
128, 189, 8, 43, 186, 55, 52, 61, 171, 196, 159, 177, 162, 100, 27, 143, 85, 83, 218,
171, 91, 220, 155, 25, 7, 38, 2, 36, 4, 93, 136, 4,
])
.unwrap();
assert_eq!(hash_to_scalar(msg1), expected1);
assert_eq!(hash_to_scalar(msg2), expected2);
assert_eq!(hash_to_scalar(msg3), expected3);
}
#[test]
fn test_hash_to_g1() {
let msg1 = "foo";
let expected1 = G1Affine::from_compressed(&[
161, 109, 186, 0, 192, 221, 83, 87, 71, 31, 120, 201, 185, 35, 62, 239, 46, 120, 117,
150, 191, 227, 128, 161, 78, 201, 207, 167, 86, 181, 229, 115, 2, 6, 178, 16, 251, 118,
219, 115, 184, 96, 2, 10, 31, 63, 150, 70,
])
.unwrap()
.into();
let msg2 = "bar";
let expected2 = G1Affine::from_compressed(&[
135, 102, 204, 42, 221, 49, 209, 192, 250, 87, 59, 255, 197, 93, 37, 113, 38, 2, 154,
233, 68, 234, 206, 182, 121, 212, 166, 210, 74, 155, 190, 33, 203, 237, 176, 60, 249,
241, 53, 170, 18, 168, 49, 35, 1, 151, 205, 174,
])
.unwrap()
.into();
let msg3 = [
33, 135, 76, 234, 71, 35, 247, 216, 39, 242, 42, 88, 152, 29, 74, 135, 9, 29, 216, 123,
250, 87, 108, 29, 245, 126, 109, 102, 84, 71, 158, 224, 145, 243, 49, 121, 244, 27,
115, 121, 25, 66, 216, 67, 97, 101, 140, 160, 77, 239, 114, 215, 152, 48, 15, 231, 101,
60, 42, 92, 128, 131, 161, 43,
];
let expected3 = G1Affine::from_compressed(&[
184, 200, 211, 115, 47, 45, 39, 185, 105, 9, 222, 247, 132, 241, 121, 130, 238, 224,
155, 109, 105, 201, 137, 154, 132, 149, 214, 233, 136, 69, 77, 132, 174, 30, 46, 123,
20, 92, 219, 18, 45, 29, 208, 127, 158, 145, 130, 41,
])
.unwrap()
.into();
assert_eq!(hash_g1(msg1), expected1);
assert_eq!(hash_g1(msg2), expected2);
assert_eq!(hash_g1(msg3), expected3);
}
}
-6
View File
@@ -161,12 +161,6 @@ impl From<NymNodeRoutingAddress> for SocketAddr {
}
}
impl AsRef<SocketAddr> for NymNodeRoutingAddress {
fn as_ref(&self) -> &SocketAddr {
&self.0
}
}
impl TryInto<NodeAddressBytes> for NymNodeRoutingAddress {
type Error = NymNodeRoutingAddressError;
@@ -7,7 +7,7 @@ use nym_sphinx_addressing::clients::Recipient;
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
use nym_sphinx_params::packet_sizes::PacketSize;
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm};
use nym_sphinx_types::{NymPacket, SURBMaterial, SphinxError, SURB};
use nym_sphinx_types::{NymPacket, SURBMaterial, SphinxError, SURB, UPDATED_LEGACY_VERSION};
use nym_topology::{NymRouteProvider, NymTopologyError};
use rand::{CryptoRng, RngCore};
use serde::de::{Error as SerdeError, Visitor};
@@ -101,7 +101,8 @@ impl ReplySurb {
let delays = nym_sphinx_routing::generate_hop_delays(average_delay, route.len());
let destination = recipient.as_sphinx_destination();
let surb_material = SURBMaterial::new(route, delays, destination);
let surb_material =
SURBMaterial::new(route, delays, destination).with_version(UPDATED_LEGACY_VERSION);
// this can't fail as we know we have a valid route to gateway and have correct number of delays
Ok(ReplySurb {
+5
View File
@@ -30,6 +30,7 @@ pub use sphinx_packet::{
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
surb::{SURBMaterial, SURB},
version::Version,
version::UPDATED_LEGACY_VERSION,
Error as SphinxError, ProcessedPacket, ProcessedPacketData,
};
@@ -90,8 +91,12 @@ impl NymPacket {
destination: &Destination,
delays: &[Delay],
) -> Result<NymPacket, NymPacketError> {
// FIXME:
// for now explicitly use the legacy version until sufficient number of nodes
// understand both variants
Ok(NymPacket::Sphinx(
SphinxPacketBuilder::new()
.with_version(UPDATED_LEGACY_VERSION)
.with_payload_size(size)
.build_packet(message, route, destination, delays)?,
))
@@ -182,11 +182,9 @@ impl BlockProcessor {
// the ones concerned with individual messages
for (index, msg) in block_tx.tx.body.messages.iter().enumerate() {
for msg_module in &mut self.msg_modules {
if msg.type_url == msg_module.type_url() {
msg_module
.handle_msg(index, msg, &block_tx, &mut tx)
.await?
}
msg_module
.handle_msg(index, msg, &block_tx, &mut tx)
.await?
}
}
}
-9
View File
@@ -83,15 +83,6 @@ pub enum ScraperError {
source: cosmrs::ErrorReport,
},
#[error("could not parse msg in tx {hash} at index {index} into {type_url}: {source}")]
MsgParseFailure {
hash: Hash,
index: usize,
type_url: String,
#[source]
source: cosmrs::ErrorReport,
},
#[error("received an invalid chain subscription event of kind {kind} while we were waiting for new block data (query: '{query}')")]
InvalidSubscriptionEvent { query: String, kind: String },
@@ -9,8 +9,6 @@ use cosmrs::Any;
#[async_trait]
pub trait MsgModule {
fn type_url(&self) -> String;
async fn handle_msg(
&mut self,
index: usize,
-4
View File
@@ -103,8 +103,4 @@ impl LaneQueueLengthsInner {
{
self.map.entry(*lane).and_modify(f);
}
pub fn total(&self) -> usize {
self.map.values().sum()
}
}
-9
View File
@@ -254,15 +254,6 @@ impl NymTopology {
}
}
pub fn with_additional_nodes<N>(mut self, nodes: impl Iterator<Item = N>) -> Self
where
N: TryInto<RoutingNode>,
<N as TryInto<RoutingNode>>::Error: Display,
{
self.add_additional_nodes(nodes);
self
}
pub fn has_node_details(&self, node_id: NodeId) -> bool {
self.node_details.contains_key(&node_id)
}
@@ -494,9 +494,6 @@ pub struct ReplySurbsWasm {
/// Defines how many mix nodes the reply surb should go through.
/// If not set, the default value is going to be used.
pub surb_mix_hops: Option<u8>,
/// Specifies if we should reset all the sender tags on startup
pub fresh_sender_tags: bool,
}
impl Default for ReplySurbsWasm {
@@ -528,7 +525,6 @@ impl From<ReplySurbsWasm> for ConfigReplySurbs {
reply_surbs.maximum_reply_key_age_ms as u64,
),
surb_mix_hops: reply_surbs.surb_mix_hops,
fresh_sender_tags: reply_surbs.fresh_sender_tags,
}
}
}
@@ -552,7 +548,6 @@ impl From<ConfigReplySurbs> for ReplySurbsWasm {
maximum_reply_surb_age_ms: reply_surbs.maximum_reply_surb_age.as_millis() as u32,
maximum_reply_key_age_ms: reply_surbs.maximum_reply_key_age.as_millis() as u32,
surb_mix_hops: reply_surbs.surb_mix_hops,
fresh_sender_tags: reply_surbs.fresh_sender_tags,
}
}
}
@@ -378,9 +378,6 @@ pub struct ReplySurbsWasmOverride {
#[tsify(optional)]
pub surb_mix_hops: Option<u8>,
/// Specifies if we should reset all the sender tags on startup
pub fresh_sender_tags: bool,
}
impl From<ReplySurbsWasmOverride> for ReplySurbsWasm {
@@ -419,7 +416,6 @@ impl From<ReplySurbsWasmOverride> for ReplySurbsWasm {
.maximum_reply_key_age_ms
.unwrap_or(def.maximum_reply_key_age_ms),
surb_mix_hops: value.surb_mix_hops,
fresh_sender_tags: value.fresh_sender_tags,
}
}
}
+17 -55
View File
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3
[[package]]
name = "ahash"
@@ -1185,7 +1185,6 @@ name = "nym-pemstore"
version = "0.3.0"
dependencies = [
"pem",
"tracing",
]
[[package]]
@@ -1252,12 +1251,6 @@ dependencies = [
"regex",
]
[[package]]
name = "pin-project-lite"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pkcs8"
version = "0.9.0"
@@ -1477,9 +1470,9 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "schemars"
version = "0.8.22"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
dependencies = [
"dyn-clone",
"schemars_derive",
@@ -1489,9 +1482,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.22"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
dependencies = [
"proc-macro2",
"quote",
@@ -1529,18 +1522,18 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.26"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.219"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [
"serde_derive",
]
@@ -1565,9 +1558,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.219"
version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [
"proc-macro2",
"quote",
@@ -1784,9 +1777,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.39"
version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8"
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
"itoa",
@@ -1801,15 +1794,15 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.3"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.20"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c"
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [
"num-conv",
"time-core",
@@ -1847,37 +1840,6 @@ dependencies = [
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "tracing-core"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
]
[[package]]
name = "typenum"
version = "1.18.0"
+1 -3
View File
@@ -7,6 +7,4 @@ package-lock.json
# local env files
.env*.local
.env
scratch.md
.env
@@ -1,10 +0,0 @@
- Run synchronization against [pool.ntp.org](https://www.ntppool.org/en/):
```bash
ntpdate -q pool.ntp.org
```
- Enable `ntp` service, start and review the status:
```bash
systemctl enable --now ntp
service ntp start
service ntp status
```
@@ -1 +1 @@
808_623_916
807_251_217
@@ -1 +1 @@
1_028_488
1_025_628
@@ -1 +1 @@
404_311_958
403_625_608
@@ -1,7 +1,7 @@
| **Item** | **Description** | **Amount in NYM** |
|:-------------------|:------------------------------------------------------|--------------------:|
| Total Supply | Maximum amount of NYM token in existence | 1_000_000_000 |
| Mixmining Reserve | Tokens releasing for operators rewards | 191_376_083 |
| Mixmining Reserve | Tokens releasing for operators rewards | 192_748_782 |
| Vesting Tokens | Tokens locked outside of cicrulation for future claim | 0 |
| Circulating Supply | Amount of unlocked tokens | 808_623_916 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_028_488 |
| Circulating Supply | Amount of unlocked tokens | 807_251_217 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_025_628 |
@@ -1 +1 @@
Tuesday, March 11th 2025, 11:04:18 UTC
Monday, February 3rd 2025, 13:47:19 UTC
@@ -16,10 +16,8 @@ Options:
If this is a brand new nym-node, specify whether it should only be initialised without actually running the subprocesses [env: NYMNODE_INIT_ONLY=]
--local
Flag specifying this node will be running in a local setting [env: NYMNODE_LOCAL=]
--mode [<MODE>...]
Specifies the current mode(s) of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
--modes <MODES>
Specifies the current mode(s) of this nym-node as a single flag [env: NYMNODE_MODES=] [possible values: mixnode, entry-gateway, exit-gateway, exit-providers-only]
--mode <MODE>
Specifies the current mode of this nym-node [env: NYMNODE_MODE=] [possible values: mixnode, entry-gateway, exit-gateway]
-w, --write-changes
If this node has been initialised before, specify whether to write any new changes to the config file [env: NYMNODE_WRITE_CONFIG_CHANGES=]
--bonding-information-output <BONDING_INFORMATION_OUTPUT>
@@ -33,7 +31,7 @@ Options:
--location <LOCATION>
Optional **physical** location of this node's server. Either full country name (e.g. 'Poland'), two-letter alpha2 (e.g. 'PL'), three-letter alpha3 (e.g. 'POL') or three-digit numeric-3 (e.g. '616') can be provided [env: NYMNODE_LOCATION=]
--http-bind-address <HTTP_BIND_ADDRESS>
Socket address this node will use for binding its http API. default: `[::]:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
Socket address this node will use for binding its http API. default: `0.0.0.0:8080` [env: NYMNODE_HTTP_BIND_ADDRESS=]
--landing-page-assets-path <LANDING_PAGE_ASSETS_PATH>
Path to assets directory of custom landing page of this node [env: NYMNODE_HTTP_LANDING_ASSETS=]
--http-access-token <HTTP_ACCESS_TOKEN>
@@ -45,29 +43,27 @@ Options:
--expose-crypto-hardware <EXPOSE_CRYPTO_HARDWARE>
Specify whether detailed system crypto hardware information should be exposed. default: true [env: NYMNODE_HTTP_EXPOSE_CRYPTO_HARDWARE=] [possible values: true, false]
--mixnet-bind-address <MIXNET_BIND_ADDRESS>
Address this node will bind to for listening for mixnet packets default: `[::]:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
Address this node will bind to for listening for mixnet packets default: `0.0.0.0:1789` [env: NYMNODE_MIXNET_BIND_ADDRESS=]
--mixnet-announce-port <MIXNET_ANNOUNCE_PORT>
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_MIXNET_ANNOUNCE_PORT=]
--nym-api-urls <NYM_API_URLS>
Addresses to nym APIs from which the node gets the view of the network [env: NYMNODE_NYM_APIS=]
--nyxd-urls <NYXD_URLS>
Addresses to nyxd chain endpoint which the node will use for chain interactions [env: NYMNODE_NYXD=]
--enable-console-logging <ENABLE_CONSOLE_LOGGING>
Specify whether running statistics of this node should be logged to the console [env: NYMNODE_ENABLE_CONSOLE_LOGGING=] [possible values: true, false]
--wireguard-enabled <WIREGUARD_ENABLED>
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
Socket address this node will use for binding its wireguard interface. default: `0.0.0.0:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
--verloc-bind-address <VERLOC_BIND_ADDRESS>
Socket address this node will use for binding its verloc API. default: `[::]:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
Socket address this node will use for binding its verloc API. default: `0.0.0.0:1790` [env: NYMNODE_VERLOC_BIND_ADDRESS=]
--verloc-announce-port <VERLOC_ANNOUNCE_PORT>
If applicable, custom port announced in the self-described API that other clients and nodes will use. Useful when the node is behind a proxy [env: NYMNODE_VERLOC_ANNOUNCE_PORT=]
--entry-bind-address <ENTRY_BIND_ADDRESS>
Socket address this node will use for binding its client websocket API. default: `[::]:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
Socket address this node will use for binding its client websocket API. default: `0.0.0.0:9000` [env: NYMNODE_ENTRY_BIND_ADDRESS=]
--announce-ws-port <ANNOUNCE_WS_PORT>
Custom announced port for listening for websocket client traffic. If unspecified, the value from the `bind_address` will be used instead [env: NYMNODE_ENTRY_ANNOUNCE_WS_PORT=]
--announce-wss-port <ANNOUNCE_WSS_PORT>
@@ -1,5 +0,0 @@
{
"mainnet":"Mainnet Endpoints",
"sandbox":"Sandbox Endpoints"
}
@@ -1,5 +0,0 @@
{
"mainnet":"Mainnet Endpoints",
"sandbox":"Sandbox Endpoints"
}
+5 -2
View File
@@ -1,8 +1,11 @@
import { Callout } from 'nextra/components'
# Node Status API
The Node Status API serves information about individual `nym-nodes` in the Mixnet, such as which role they are operating in, statistics about them, services such as Network Requesters, as well as summaries of the state of the Mixnet.
The Node Status API contains information about the network, its topology, and the routing scores of all nodes within it. It offers broadly similar information to the experimental [Habourmaster frontend](https://harbourmaster.nymtech.net/) but is stable where the Harbourmaster is subject to sudden changes as we modify and experiment with how we scrape and present data about the Mixnet infrastructure.
<Callout type="info">
We recommend that developers building applications such as explorers or analytics interfaces about the Mixnet run their own instance of the API, in order to promote a robust network of downstream services, and spread the load of API calls amongst as many endpoints as possible.
People building applications or dashboards which requires information about nodes, their uptime, and their delegations should use this instead of Habourmaster.
</Callout>
The code for this service can be found [in our monorepo](https://github.com/nymtech/nym/tree/develop/nym-node-status-api). In the future we will encourage developers to run their own instance of this API in order to distribute endpoints and query load.
@@ -1,5 +0,0 @@
{
"ns-api-run-deploy":"Run Instance",
"mainnet":"Mainnet Endpoints",
"sandbox":"Sandbox Endpoints"
}
@@ -1,11 +1,9 @@
import { RedocStandalone } from 'redoc';
import { Callout } from 'nextra/components'
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/).
<br /><br />
<RedocStandalone
specUrl="https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json"
options={{
@@ -1,336 +0,0 @@
import { Callout } from 'nextra/components'
import { AccordionTemplate } from 'components/accordion-template.tsx'
# NS API: Deployment Guide
## Components
The Node Status API is made up of 3 components:
- `nym-node-status-api`
- `nym-node-status-client`
- `nym-node-status-agent`
The API stores its data in a local SQLite database. It periodically gets most of its data from a [NymAPI](./nym-api) instance, and for instances also running with the Gateway Probe, uses the stored topology to conduct performance probe tests.
## Gateway Probe
You can run the `nym-node-status-api` alone, but if you want to run probes for `nym-node`s running as Gateways, you have to also run the `nym-node-status-agent` (which consumes the `nym-node-status-client` lib). The probe will run a set of tests per Gateway node, and return the sort of results seen [here](https://harbourmaster.nymtech.net/gateway/23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb).
## UI
The API exposes a [Swagger](https://swagger.io/docs/) documentation UI by default on port `8000` (see an example [here](https://mainnet-node-status-api.nymtech.cc/swagger/)).
Currently we are not shipping a custom UI component for the Node Status API. The [Harbourmaster](https://harbourmaster.nymtech.net/) frontend consumes this API, amongst other things, but this is an internal repo we use to experiment with new APIs and data on, so it is not public yet.
<Callout type="info">
We invite developers to roll their own UI for their Node Status API instance.
</Callout>
## Docker Images
We will ship Docker images for both the `agent` and `api` in the future. There are Docker images for both in root of each corresponding crate ([`agent`](https://github.com/nymtech/nym/blob/09ea406c02e9a3beebc062f525e4ea1b4222dcbb/nym-node-status-api/nym-node-status-agent/Dockerfile), [`api`](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/Dockerfile)) which are used internally, which could be a starting point for developers to dockerize their instance for the moment.
## Build
### Prerequisites
- Rust
- SQLite
- Get an `ipinfo` key following instructions [here](https://github.com/ipinfo/rust?tab=readme-ov-file#getting-started).
### Compilation
```shell
cargo build --release --package nym-node-status-api --package nym-node-status-agent --package nym-node-status-client
```
## Run
Since the Node Status API depends on both flags and environmental variables, it might be easier to run the binary via a script like the one below - this this script essentially just `source`-s the defined `.env` file after exporting certain binary-specific variables, and then runs the binary. You can find the `.env` files [here](https://github.com/nymtech/nym/tree/master/envs).
<Callout type="info">
All CLI flags are configurable as environmental variables and vice versa, so take the following scripts / setups as guides that you can change however best suits your setup. You can see all definitions [here](https://github.com/nymtech/nym/blob/develop/nym-node-status-api/nym-node-status-api/src/cli/mod.rs#L14).
</Callout>
```bash
#!/bin/bash
set -e
export ENVIRONMENT=${ENVIRONMENT:-"mainnet"} # see nym/envs/ for all possible environments
export NYM_API_CLIENT_TIMEOUT=60
export NODE_STATUS_API_TESTRUN_REFRESH_INTERVAL=120
export IPINFO_API_TOKEN=<YOUR_IPINFO_API_KEY>
monorepo_root=<PATH/TO/NYM/>
set -a
source "${monorepo_root}/envs/${ENVIRONMENT}.env"
echo ${monorepo_root}/envs/${ENVIRONMENT}.env
set +a
export RUST_LOG=${RUST_LOG:-debug} # debug is useful to check everything is working initially, but quite verbose
echo "Verifying environment variables were properly sourced:"
echo "RUST_LOG=${RUST_LOG}"
echo "BECH32_PREFIX=${BECH32_PREFIX}"
echo "NETWORK_NAME=${NETWORK_NAME}"
<PATH/TO/>nym-node-status-api -- --ipinfo-api-token $IPINFO_API_TOKEN
```
### Functionality Without Gateway Probe
Data will be restricted to information that doesn't involve Probe results; `routing` and `config` scores will be `0` and `last_probe` results `null`, as you can see in this snipped output of the `gateways` endpoint:
<AccordionTemplate name="Output">
```shell
{
"gateway_identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
"bonded": true,
"performance": 99,
"self_described": {
"authenticator": {
"address": "6Gdtw13Fa46AvkqkHELZZCMKWASDodoJeK9APRNpjjdj.7ji8DDkpjA2AdgwK7wbZm8yi4xZGogGJeypBQt4hAw3P@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb"
},
"auxiliary_details": {
"accepted_operator_terms_and_conditions": true,
"announce_ports": {
"mix_port": null,
"verloc_port": null
},
"location": null
},
"build_information": {
"binary_name": "nym-node",
"build_timestamp": "2025-02-13T11:49:34.670488195Z",
"build_version": "1.5.0",
"cargo_profile": "release",
"cargo_triple": "x86_64-unknown-linux-gnu",
"commit_branch": "HEAD",
"commit_sha": "a3e19b4563843055b305ea9a397eb1ad84b5c378",
"commit_timestamp": "2025-02-10T18:14:47.000000000+01:00",
"rustc_channel": "stable",
"rustc_version": "1.84.1"
},
"declared_role": {
"entry": true,
"exit_ipr": true,
"exit_nr": true,
"mixnode": false
},
"host_information": {
"hostname": "bwng1.bwnym.xyz",
"ip_address": [
"95.164.2.86"
],
"keys": {
"ed25519": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
"x25519": "H6pFjqtdSVxkxEQ3wFnuSoobDAUqHx1bYMVJzPZdRByn",
"x25519_noise": null
}
},
"ip_packet_router": {
"address": "7ms2D2uYiTuhX6MKeVL5rz5usgehEoxAAovwYm9nJyBF.3siMjk3wTU7ykaXLNi9c7LpX8yonYKPCA4BQoMwhsfTV@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb"
},
"last_polled": "2025-03-03 09:48:03.635274187 +00:00:00",
"mixnet_websockets": {
"ws_port": 9000,
"wss_port": 9001
},
"network_requester": {
"address": "HuNL1pFprNSKW6jdqppibXP5KNKCNJxDh7ivpYcoULN9.C62NahRTUf6kqpNtDVHXoVriQr6yyaU5LtxdgpbsGrtA@23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
"uses_exit_policy": true
},
"wireguard": {
"port": 51822,
"public_key": "6o8x9GitFjcrkjrJnivWaQCPnxXykQPYLneNr2FEB8Vq"
}
},
"explorer_pretty_bond": {
"identity_key": "23A7CSaBSA2L67PWuFTPXUnYrCdyVcB7ATYsjUsfdftb",
"location": {
"latitude": 52.5083,
"longitude": 5.475,
"two_letter_iso_country_code": "NL"
},
"owner": "n1cp5gq0apat6c7qmenqp5zjprn2vwvc7jl29j8r",
"pledge_amount": {
"amount": "100000000",
"denom": "unym"
}
},
"description": {
"moniker": "bwn_g1",
"website": "https://bwnym.xyz",
"security_contact": "bwnym@proton.me",
"details": "This gateway is part of the NYM project, which is dedicated to create outstanding privacy software that is legally compliant without sacrificing integrity or having any backdoors."
},
"last_probe_result": null,
"last_probe_log": null,
"last_testrun_utc": null,
"last_updated_utc": "2025-03-03T10:45:48+00:00",
"routing_score": 0.0,
"config_score": 0
},
```
</AccordionTemplate>
If you have already run the API before, make sure to add the following to your script `--database-url "sqlite://node-status-api.sqlite?mode=rwc` so it will continue using the same DB.
### Functionality with Gateway Probe
If you want to enable Gateway node probes and have the NS API store that data, you need to periodically run the `nym-node-status-agent`, authenticated with your `nym-node-status-api` instance. Authentication is to make sure that only the `-agent` you are operating (or others you trust) are submitting data to your API instance.
#### Compile Gateway Probe
The `nym-node-status-agent` is a thin wrapper around the Gateway Probe binary which currently is in the NymVPN repo. `git checkout` to the most recent [release](https://github.com/nymtech/nym-vpn-client/releases), and compile the probe by following the [readme instructions](https://github.com/nymtech/nym-vpn-client/tree/develop/nym-vpn-core/crates/nym-gateway-probe). You will point the `-agent` at this binary when doing Probe testruns.
#### Generate Keypair
```shell
<PATH/TO/>nym-node-status-agent generate-keypair --path <PATH/TO/KEY/FILE/TO/GENERATE>/<KEY_NAME>
# e.g.
# nym-node-status-agent generate-keypair --path ~/.ssh/ns-agent-key
```
You will then want to export the generated `public-key` so its accessible to the `nym-node-status-api` however you are setting your environmental variables, as `NODE_STATUS_API_AGENT_KEY_LIST`:
```bash
export NODE_STATUS_API_AGENT_KEY_LIST=<YOUR_KEY> # e.g. "H4z8kx5Kkf5JNQHfxaE1MwRndjDCD1C7HsVhHTFfBZ4J"
```
In this situation, you are probably only using one key. However, it is possible to set multiple keys as a comma seperated list, in case you wish to whitelist multiple `-agent`s to be able to submit to a single `-api` instance.
#### Run the Node Status Agent
```shell
<PATH/TO/>nym-node-status-agent run-probe --server-address http://127.0.0.1 --server-port 8000 --ns-api-auth-key "<NS_AGENT_PRIVATE_KEY>" --probe-path <PATH/TO/> nym-gateway-probe
```
You will see a lot of output like so:
<AccordionTemplate name="Output">
```shell
listen_port=48586
public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26
preshared_key=0000000000000000000000000000000000000000000000000000000000000000
protocol_version=1
endpoint=185.186.78.251:51822
last_handshake_time_sec=0
last_handshake_time_nsec=0
tx_bytes=0
rx_bytes=0
persistent_keepalive_interval=0
allowed_ip=0.0.0.0/0
2025/03/03 18:58:28 Pinging nymtech.net seq=0
2025/03/03 18:58:29 Ping latency: 44.503483ms
2025/03/03 18:58:29 Pinging nymtech.net seq=1
2025/03/03 18:58:29 Ping latency: 42.852414ms
2025/03/03 18:58:29 Pinging nymtech.net seq=2
2025/03/03 18:58:29 Ping latency: 43.627256ms
2025/03/03 18:58:29 Pinging nymtech.net seq=3
2025/03/03 18:58:29 Ping latency: 43.638839ms
2025/03/03 18:58:29 Pinging nymtech.net seq=4
2025/03/03 18:58:29 Ping latency: 43.345357ms
2025/03/03 18:58:29 Pinging 1.1.1.1 seq=0
2025/03/03 18:58:29 Ping latency: 46.327233ms
2025/03/03 18:58:34 Pinging 1.1.1.1 seq=1
2025/03/03 18:58:34 Ping latency: 46.273726ms
2025/03/03 18:58:39 Pinging 1.1.1.1 seq=2
2025/03/03 18:58:39 Ping latency: 46.542774ms
2025/03/03 18:58:44 Pinging 1.1.1.1 seq=3
2025/03/03 18:58:44 Ping latency: 45.663545ms
2025/03/03 18:58:49 Pinging 1.1.1.1 seq=4
2025/03/03 18:58:49 Ping latency: 43.803063ms
2025/03/03 18:58:56 Downloaded file content length: 1.00 MB
2025/03/03 18:58:56 Download duration: 1.308072386s
2025/03/03 18:58:56 private_key=1083749e43f4f8fb008f3f7deef9107ef86a68969670ddbb9f07bf85f94fb564
listen_port=39129
public_key=3f95caf771b8a63b9bdae6c186f7aba2eae93483f1c82c0243b5e00c85b4ec26
preshared_key=0000000000000000000000000000000000000000000000000000000000000000
protocol_version=1
endpoint=185.186.78.251:51822
last_handshake_time_sec=0
last_handshake_time_nsec=0
tx_bytes=0
rx_bytes=0
persistent_keepalive_interval=0
allowed_ip=::/0
2025/03/03 18:58:56 Pinging ipv6.google.com seq=0
2025/03/03 18:58:56 Ping latency: 42.839528ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=1
2025/03/03 18:58:56 Ping latency: 54.844651ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=2
2025/03/03 18:58:56 Ping latency: 51.23104ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=3
2025/03/03 18:58:56 Ping latency: 43.320409ms
2025/03/03 18:58:56 Pinging ipv6.google.com seq=4
2025/03/03 18:58:56 Ping latency: 63.517358ms
2025/03/03 18:58:56 Pinging 2001:4860:4860::8888 seq=0
2025/03/03 18:58:56 Ping latency: 54.682534ms
2025/03/03 18:59:01 Pinging 2001:4860:4860::8888 seq=1
2025/03/03 18:59:01 Ping latency: 55.56235ms
2025/03/03 18:59:06 Pinging 2001:4860:4860::8888 seq=2
2025/03/03 18:59:06 Ping latency: 55.970418ms
2025/03/03 18:59:11 Pinging 2001:4860:4860::8888 seq=3
2025/03/03 18:59:14 Failed to send ping: i/o timeout
2025/03/03 18:59:19 Pinging 2001:4860:4860::8888 seq=4
2025/03/03 18:59:22 Failed to send ping: i/o timeout
2025/03/03 18:59:27 Pinging 2606:4700:4700::1111 seq=0
2025/03/03 18:59:27 Ping latency: 45.072616ms
2025/03/03 18:59:32 Pinging 2606:4700:4700::1111 seq=1
2025/03/03 18:59:32 Ping latency: 44.357306ms
2025/03/03 18:59:37 Pinging 2606:4700:4700::1111 seq=2
2025/03/03 18:59:37 Ping latency: 44.013562ms
2025/03/03 18:59:42 Pinging 2606:4700:4700::1111 seq=3
2025/03/03 18:59:42 Ping latency: 46.94342ms
2025/03/03 18:59:47 Pinging 2606:4700:4700::1111 seq=4
2025/03/03 18:59:48 Ping latency: 43.372288ms
2025/03/03 18:59:53 Pinging 2620:fe::fe seq=0
2025/03/03 18:59:53 Ping latency: 42.164952ms
2025/03/03 18:59:58 Pinging 2620:fe::fe seq=1
2025/03/03 18:59:58 Ping latency: 42.295812ms
2025/03/03 19:00:03 Pinging 2620:fe::fe seq=2
2025/03/03 19:00:03 Ping latency: 43.117534ms
2025/03/03 19:00:08 Pinging 2620:fe::fe seq=3
2025/03/03 19:00:08 Ping latency: 44.26068ms
2025/03/03 19:00:13 Pinging 2620:fe::fe seq=4
2025/03/03 19:00:13 Ping latency: 45.29956ms
2025/03/03 19:00:21 Downloaded file content length: 10.00 MB
2025/03/03 19:00:21 Download duration: 3.39529252s
```
</AccordionTemplate>
Whilst you can run the `-agent` directly, it might be easier to run multiple instances in parallel with a script like so:
```bash
#!/bin/bash
set -eu
export ENVIRONMENT=${ENVIRONMENT:-"mainnet"}
probe_git_ref="nym-vpn-core-v1.4.0" # check for the most recent release
monorepo_root=<PATH/TO/NYM/>
set -a
source "${monorepo_root}/envs/${ENVIRONMENT}.env"
set +a
export RUST_LOG="info"
export NODE_STATUS_AGENT_SERVER_ADDRESS="http://127.0.0.1"
export NODE_STATUS_AGENT_SERVER_PORT="8000"
export NODE_STATUS_AGENT_AUTH_KEY=<NS_AGENT_PRIVATE_KEY>
export NODE_STATUS_AGENT_PROBE_EXTRA_ARGS="netstack-download-timeout-sec=30,netstack-num-ping=2,netstack-send-timeout-sec=1,netstack-recv-timeout-sec=1"
workers=${1:-1}
echo "Running $workers workers in parallel"
function swarm() {
local workers=$1
for ((i = 1; i <= workers; i++)); do
${monorepo_root}/target/release/nym-node-status-agent run-probe --probe-path ~/<PATH/TO>/nym-vpn-client/nym-vpn-core/target/debug/nym-gateway-probe &
done
wait
echo "All agents completed"
}
swarm $workers
```
And run specifying the number of workers with `./<SCRIPT_NAME>.sh <NUMBER_OF_WORKERS>`.
<Callout type="info">
When running the probe, use logging level `RUST_LOG=info`. The Node Status API relies on that granularity for parsing probe results, and the logs grow incessantly if a lower level (e.g. `DEBUG`) is used.
</Callout>
### Ports
By default the API listens on `8000`, so you will need to configure this post to be reachable on your remote server. You can modify this with the `--http_port` flag.
@@ -1,3 +0,0 @@
{
"mainnet":"Mainnet Endpoints"
}
+72 -284
View File
@@ -47,218 +47,6 @@ This page displays a full list of all the changes during our release cycle from
<VarInfo />
## `v2025.4-dorina-patched`
Patched version of `dorina` with a few fixes and tweaks to the release. We would like to ask `nym-node` operators to upgrade to this version as quickly as possible to implement the fixes across the network and improve general quality before NymVPN launch.
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina-patched)
- [`nym-node`](nodes/nym-node.mdx) version `1.6.2`
```shell
nym-node
Binary Name: nym-node
Build Timestamp: 2025-03-06T20:32:36.922212778Z
Build Version: 1.6.2
Commit SHA: 247ebb7c4339de0a298a7fcb2574122a8306c3b8
Commit Date: 2025-03-06T21:26:16.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.85.0
rustc Channel: stable
cargo Profile: release
```
- Use legacy crypto for constructing SURB headers ([#5579])
- Bugfix: make sure to correctly decode response content when putting it into error message ([#5571])
- Tweak surb management to be more conservative ([#5570])
- Deserialize v5 authenticator requests ([#5568])
- Chore: additional logs when attempting to load ecash keys ([#5567])
- Add full response body to error message upon decoding failure ([#5566])
- Hotfix: ensure we bail on merkle leaves insertion upon missing data ([#5565])
- Feature: v2 authentication request (#5537) ([#5563])
- Create authenticator v5 request/response types ([#5561])
[#5579]: https://github.com/nymtech/nym/pull/5579
[#5571]: https://github.com/nymtech/nym/pull/5571
[#5570]: https://github.com/nymtech/nym/pull/5570
[#5568]: https://github.com/nymtech/nym/pull/5568
[#5567]: https://github.com/nymtech/nym/pull/5567
[#5566]: https://github.com/nymtech/nym/pull/5566
[#5565]: https://github.com/nymtech/nym/pull/5565
[#5563]: https://github.com/nymtech/nym/pull/5563
[#5561]: https://github.com/nymtech/nym/pull/5561
## `v2025.4-dorina`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.4-dorina)
- [`nym-node`](nodes/nym-node.mdx) version `1.6.0`
```shell
Binary Name: nym-node
Build Timestamp: 2025-03-04T09:03:11.322601809Z
Build Version: 1.6.0
Commit SHA: 7060fa6dad58f17543f5086c73b1854ad1ceae60
Commit Date: 2025-03-03T17:24:10.000000000Z
Commit Branch: release/2025.4-dorina
rustc Version: 1.86.0-nightly
rustc Channel: nightly
cargo Profile: release
```
### Operators Updates & Tools
- New advanced [guide to virtualise a dedicated server](nodes/preliminary-steps/vps-setup/advanced), providing steps for experienced operators and aspiring sys-admins who seek for higher optimisation and better efficiency of their work orchestrating multiple nodes.
- New Service Grant program is being implemented by operators setting up new ~150 Exit Gateways following the updated [specs for `nym-node`](nodes#minimum-requirements)
### Features
- [Feature/chain status api](https://github.com/nymtech/nym/pull/5539):
this PR introduces `/v1/network/chain-status` endpoint on nym api to give basic information about the current block as seen by this API (with some caching) and updates `/health` endpoint to give stall information.
- [Add SURBs soft threshold](https://github.com/nymtech/nym/pull/5535): the IPR should try to keep a buffer of available SURBs to reduce latency.
- [Simplify IPR v8](https://github.com/nymtech/nym/pull/5532): purge stuff from IPR v8 to simplify; use protocol field in v8.
- [Shared instance for DNS AsyncResolver](https://github.com/nymtech/nym/pull/5523):
make the `HickoryDnsResolver` use a shared instance by default to limit fd use. Now the multiple `nym_http_api_client::Client`s that get built should take advantage of a shared connection pool for DNS lookups. If for some reason a client does need an independent AsyncResolver this can still be done with the added `thread_resolver` function.
- [cherry-pick 17d3ff2d775f61aee381d90a304ed416c08f33fc onto dorina](https://github.com/nymtech/nym/pull/5519)
- [cherry-pick 6e5d0dac1b75413c5f09122b0d953f8ec6ef48df onto dorina](https://github.com/nymtech/nym/pull/5518)
- [feat: add config option for maximum number of client connections](https://github.com/nymtech/nym/pull/5513)
- [IPR request types v8](https://github.com/nymtech/nym/pull/5498): Bump IPR request/response types to v8
- [Support static routes for HTTP requests](https://github.com/nymtech/nym/pull/5487)
- [added missing import to doctest](https://github.com/nymtech/nym/pull/5480)
- [adjusted TestSetup::new_complex to ensure bonded node's existence](https://github.com/nymtech/nym/pull/5478)
- [Trigger contracts CI on main workspace Cargo changes](https://github.com/nymtech/nym/pull/5477): since the contracts workspace depends on the common code in the main workspace, and since the contracts are critical to not have regressions in, trigger contracts CI on any changes to the workspace Cargo.toml and lock files.
- [Run cargo autoinherit](https://github.com/nymtech/nym/pull/5460): run `cargo autoinherit` to move a bunch of dependencies to the workspace level. `Cargo.lock` remains untouched.
- [Disable debug in wasm and wallet workflows too](https://github.com/nymtech/nym/pull/5459)
- [Fix clippy::precedence](https://github.com/nymtech/nym/pull/5457): fix clippy warnings for the Rust beta toolchain.
- [Provide Interval context with node descriptor endpoints](https://github.com/nymtech/nym/pull/5456): add current interval context information to existing enpoints using `build_skimmed_nodes_response` under the hood. This allows clients checking for a refresh to send the `epoch_uid` as a query parameter when fetching updates so the server can tell it that there have been no changes, instead of sending duplicate data over and over. The changes in this PR should be backwards compatible and never interfere with existing clients. The additions to the `NodeParams` are optional, so there is no error if a client does not send them. Old clients will not send `epoch_uid` by accident so they cannot accidentally clear their set of known nodes. In the response the status field is optional so if it is missing (e.g. if a new client talks to an old server) the connection still works. For old clients speaking to new servers, the json parsing will simply ignore extra information not included in the objects json spec.
<AccordionTemplate name={<TestingSteps/>}>
Made a request to the `/api/v1/unstable/nym-nodes/semi-skimmed` endpoint:
- without entering an epoch_id
- with entering the current epoch_id
- with entering an old epoch_id
- with entering a future epoch_id
All results returned the same data, as expected
</AccordionTemplate>
- [Feature/add gbp currency](https://github.com/nymtech/nym/pull/5453)
- [Add helper to extract a list of sqlite files with journal files wal/shm](https://github.com/nymtech/nym/pull/5452)
- [Add a middleware layer to the nym api allowing for data compression](https://github.com/nymtech/nym/pull/5451): after Testing in a minimal example, this does work as expected. Routes still default to plain encoding, however if a client indicates support for a compressed encoding using the `Accept-Encoding` header then the served response will be compressed with the appropriate `Content-Encoding` header. ([Proof-of-Concept](https://gist.github.com/jmwample/c15a983e804fc338fee3d1b037d216b0))
<AccordionTemplate name={<TestingSteps/>}>
Sent requests with and without Accept-Encoding: gzip to observe response behaviour
Verified if responses included content-encoding: gzip when compression was requested
Checked response file output to confirm actual compression occurred
</AccordionTemplate>
- [Condense core API functionalities and enable gzip decompression for reqwest payloads](https://github.com/nymtech/nym/pull/5450): this PR is intended to take out variables from our usage of HTTP requests in the `nym-http-api-client`. To do this the PR: (1) adds the `ApiClientCore` trait with the minimal feature required to send a request, (2) turns all request sending into trait extension automatically implemented for any type that implements `ApiClientCore`. This has the benefit of consistent expected behavior for all clients using `nym-http-api-client`, including features added going forward. FOR EXAMPLE this pr adds a default header `"accept-encoding: gzip;q=1.0, *;q=0.5"` which indicates that compression is preferred whenever available. Other features to keep in mind here are things like configurable retries, domain fallbacks, etc. Note: the `Apiclient` interface could be simplified, but that would require refactoring our downstream usages of the API. For now this isn't necessary as `ApiClient` is implemented automatically so it costs nothing to have it this way. It just allows divergent usage in downstream crates.
<AccordionTemplate name={<TestingSteps/>}>
Measured nym-api response times before and after updating the API client using curl
Checked if the client automatically decompressed Gzip responses
</AccordionTemplate>
- [Seedable clients](https://github.com/nymtech/nym/pull/5440): Adds `DerivationMaterial` and accompanying methods to builders. `DerivationMaterial` encapsulates parameters for deterministic key derivation using HKDF (SHA-512). Use the `derive_secret()` method to generate a 32-byte secret. To prepare for a new derivation, call the `next()` method which increments the index. **It is the caller's responsibility to track and persist the derivation index if keys need to be rederived.**
<AccordionTemplate name="Example">
```rust
let master_key = [0u8; 32]; // your secret master key
let salt = "unique-salt-value".to_string();
let material = DerivationMaterial::new(master_key, 0, salt.as_bytes());
// Derive a secret
let secret = material.derive_secret().expect("Failed to derive secret");
// Prepare for the next derivation
let next_material = material.next();
```
</AccordionTemplate>
- [Remove all recv_with_delay and add shutdown condition to loops in client-core](https://github.com/nymtech/nym/pull/5435): inside client-core we want to prepare the ground for moving a behaviour close to what we have in the vpn client. Remove all the recv_with_delay since we want to just stop. Add shutdown condition to all select loops to guard against the shutdown listener being polled inside the select blocks. Remove unwraps when sending on unbounded channels in case the receiver exits before the sender. Move `TaskClient` to be a member field so make it easier to wrap log errors in a shutdown check. Update all fork names to use underscore consistently, since the task separator is hyphen
<AccordionTemplate name={<TestingSteps/>}>
Validated that all binaries including `nym-node`, `nym-client`, `nym-network-requester`, and `nym-socks5-client` are behaving well without indicating the presence of any unexpected errors or crashes
</AccordionTemplate>
- [Disable the test for checking the remaining bandwidth in nym-node-status-api](https://github.com/nymtech/nym/pull/5425): this check fails almost every time on CI, possibly due to rate limiting? It's not good to disable the check, but it's blocking CI as it stands now. Given that we have the check above for locating the ip, we at least have a little coverage.
- [Dz nym node stats](https://github.com/nymtech/nym/pull/5418): removed obsolete fields from stats (blacklisted mixnodes, blacklisted gateways, bonded mixnodes, bonded gateways). Introduced nym-node scraping, beside just mixnodes. `/mixnodes/stats` now returns data for nym-nodes as well, which results in much more accurate "packets mixed" stats.
- [Nymnode entrypoint docker](https://github.com/nymtech/nym/pull/5300)
### Bugfix
- [bugfix: dont query for ecash apis unless necessary when spending ticketbooks](https://github.com/nymtech/nym/pull/5508)
- [bugfix: bound check when recovering a reply SURB](https://github.com/nymtech/nym/pull/5502)
- [fix: update fx average rate calcs to ignore 0 values](https://github.com/nymtech/nym/pull/5454)
### Chore
- [chore: workspace global panic preventing lints](https://github.com/nymtech/nym/pull/5512)
- [chore: removed all old coconut code](https://github.com/nymtech/nym/pull/5500)
- [build(deps): bump the patch-updates group across 1 directory with 3 updates](https://github.com/nymtech/nym/pull/5482): updates `clap` from 4.5.28 to 4.5.30, updates `clap` from 4.5.28 to 4.5.30, updates `prost` from 0.13.4 to 0.13.5.
- [build(deps): bump http from 1.1.0 to 1.2.0](https://github.com/nymtech/nym/pull/5472)
- [build(deps): bump utoipa-swagger-ui from 8.0.3 to 8.1.0](https://github.com/nymtech/nym/pull/5471)
- [build(deps): bump colored from 2.1.0 to 2.2.0](https://github.com/nymtech/nym/pull/5470)
- [build(deps): bump celes from 2.4.0 to 2.5.0](https://github.com/nymtech/nym/pull/5469)
- [build(deps): bump the patch-updates group with 2 updates](https://github.com/nymtech/nym/pull/5467): updates `clap` from 4.5.28 to 4.5.29, updates `prost` from 0.13.4 to 0.13.5.
- [build(deps): bump elliptic from 6.5.4 to 6.6.1 in /docker/typescript_client/upload_contract](https://github.com/nymtech/nym/pull/5463): bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.4 to 6.6.1.
- [build(deps): bump uniffi_build from 0.25.3 to 0.29.0](https://github.com/nymtech/nym/pull/5448)
- [Upgrade tower to 0.5.2](https://github.com/nymtech/nym/pull/5446)
- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3 in /nym-wallet](https://github.com/nymtech/nym/pull/5445)
- [build(deps): bump hickory-proto from 0.24.2 to 0.24.3](https://github.com/nymtech/nym/pull/5444)
- [build(deps): bump the patch-updates group across 1 directory with 10 updates](https://github.com/nymtech/nym/pull/5439):
Bumps the patch-updates group with 10 updates in the directory:
| Package | From | To |
| --- | --- | --- |
| [async-trait](https://github.com/dtolnay/async-trait) | `0.1.85` | `0.1.86` |
| [clap](https://github.com/clap-rs/clap) | `4.5.27` | `4.5.28` |
| [comfy-table](https://github.com/nukesor/comfy-table) | `7.1.3` | `7.1.4` |
| [hickory-resolver](https://github.com/hickory-dns/hickory-dns) | `0.24.2` | `0.24.3` |
| [once_cell](https://github.com/matklad/once_cell) | `1.20.2` | `1.20.3` |
| [pin-project](https://github.com/taiki-e/pin-project) | `1.1.8` | `1.1.9` |
| [serde_json_path](https://github.com/hiltontj/serde_json_path) | `0.7.1` | `0.7.2` |
| [toml](https://github.com/toml-rs/toml) | `0.8.19` | `0.8.20` |
| [cosmrs](https://github.com/cosmos/cosmos-rust) | `0.21.0` | `0.21.1` |
| [tokio-postgres](https://github.com/sfackler/rust-postgres) | `0.7.12` | `0.7.13` |
- [build(deps): bump openssl from 0.10.56 to 0.10.70 in /nym-wallet](https://github.com/nymtech/nym/pull/5422)
- [build(deps): bump hyper from 1.4.1 to 1.6.0](https://github.com/nymtech/nym/pull/5416)
- [build(deps): bump publicsuffix from 2.2.3 to 2.3.0](https://github.com/nymtech/nym/pull/5367)
## `v2025.3-ruta`
- [Release Binaries](https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.3-ruta)
@@ -309,7 +97,7 @@ As we announced in [`hu` release notes](#service-grant-program-v2), we are opene
##### Locations
These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio.
These locations and slots are approximate and constantly change based on new operators submissions. Please keep in mind that we are going to chose people with respect to empty slots in the given location at the time of their submission. In case of competing submissions in the same location we will take the one with better specs vs price ratio.
| LOCATION | SLOTS |
| :-- | --: |
@@ -363,7 +151,7 @@ These locations and slots are approximate and constantly change based on new ope
- [Send shutdown instead of panic when reaching max fail](https://github.com/nymtech/nym/pull/5398): Remove a panic and an unwrap inside `client-core` that is hit occasionally in the vpn client. This is a change that can have wide ranging impact since it changes the task handling and it's inside `client-core`, which is used in many components and services, so preventing regressions is important.
- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo.
- [Relocate a validator api function](https://github.com/nymtech/nym/pull/5401): Adds a function to the `nym-validator-client` crate that hits the network details endpoint and returns an object parsed from `json`. This was floating loose in the `nym-vpn-client` repo.
- [Bump the patch-updates group across 1 directory with 9 updates](https://github.com/nymtech/nym/pull/5406)
@@ -411,7 +199,7 @@ From `nym-node v1.3.0` operators can technically choose multiple functionalities
- Updated maintenance guides to [backup](nodes/maintenance#backup-a-node), [restore](nodes/maintenance#restoring-a-node) and [move](nodes/maintenance#moving-a-node) a node, containing a new and important commands to backup and restore `clients.sqlite` database.
- [New explanation of `nym-node` functionalities](nodes/nym-node/setup#functionality-mode) describing how Gateways get selected in Mixnet mode and Wireguard mode.
- [New explanation of `nym-node` functionalities](nodes/nym-node/setup#functionality-mode) describing how Gateways get selected in Mixnet mode and Wireguard mode.
<Callout type="warning">
Wireguard nodes route data directly to the open internet. Therefore it exposes IP of operators server (VPS) to abuse complains. Before you decide to run a node with active wireguard routing, please read our [Community Counsel pages](community-counsel/exit-gateway) containing more information and some legal content.
@@ -435,7 +223,7 @@ We have been notified that a handful of nodes have been taken down by abuse repo
- Join [Community legal counsel](https://nym.com/docs/operators/community-counsel) - our collective knowledge hub. Add your findings by opening a [Pull Request](https://nym.com/docs/operators/add-content)
- While we are working on a new list of more friendly providers, consider to move away from these provides as soon as possible:
- Servinga / VPS2day (AS39378)
- Frantech / Ponynet / BuyVM (AS53667)
- OVH SAS / OVHcloud (AS16276)
@@ -445,7 +233,7 @@ We have been notified that a handful of nodes have been taken down by abuse repo
- Psychz Networks (AS40676)
- 1337 Services GmbH / RDP.sh (AS210558)
- Backup your nodes to have access to `.nym` directory locally. Follow [node](nodes/maintenance#backup-a-node) and [proxy configuration](nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](nodes/maintenance#restoring-a-node) later on on another machine, without losing your delegation.
- Backup your nodes to have access to `.nym` directory locally. Follow [node](nodes/maintenance#backup-a-node) and [proxy configuration](nodes/maintenance#backup-proxy-configuration) backup guides to be able to [restore your node](nodes/maintenance#restoring-a-node) later on on another machine, without losing your delegation.
- We would like to ask operators who use reverse proxy and a domain (required for Gateways) to start using a common convention starting with `nym-exit` for their nodes URL. The entire address should have this new format:
```
@@ -470,7 +258,7 @@ nym-exit.mysquad.org
**The `NYM-EXIT` part in the beginning is what's important.**
- When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report.
- When registering a domain, check [Top Level Domain (TLD)](https://www.techopedia.com/definition/1348/top-level-domain-tld) terms and conditions. For example `.icu` is a no go. Having a wrong TLD may lead to your domain being taken away from you when facing a DMCA report.
- Write a message to your provider and introduce your intention to run a Nym Node on their service
<AccordionTemplate name="Email template: Introduce yourself to your VPS provider">
@@ -534,7 +322,7 @@ Undelegated due to high saturation:
#### Service Grant Program v2
Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to support Exit Gateway operators before they will be rewarded by collecting [zk-nym tickets](../network/cryptography/zk-nym) from users subscription. Operators included in SGP are long term active community members with the highest requirements on the technical setup and upgrading pace. We are about to start a second iteration of SGP very soon (SGPv2). The final slots and locations are yet to be concluded. Priority to participate in SGPv2 will be given to the current operators in SGP. Based on the number of slots, we will then determine how many more operators can sign up.
Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to support Exit Gateway operators before they will be rewarded by collecting [zk-nym tickets](../network/cryptography/zk-nym) from users subscription. Operators included in SGP are long term active community members with the highest requirements on the technical setup and upgrading pace. We are about to start a second iteration of SGP very soon (SGPv2). The final slots and locations are yet to be concluded. Priority to participate in SGPv2 will be given to the current operators in SGP. Based on the number of slots, we will then determine how many more operators can sign up.
##### Rules of SGPv2
@@ -542,7 +330,7 @@ Aside from delegating on top of nodes, Nym runs a Service Grant Program (SGP) to
**We will share more info soon in the channels. The rules are not set in stone and could potentially be altered or updated in the future! Do *not* purchase new servers neither migrate your nodes just yet.**
</Callout>
As we finalising last details of *"Project Smoosh"*, where one binary - `nym-node` - can run as an `entry-gateway`, `mixnode` or `exit-gateway` in Mixnet mode as well as `entry-gateway` or `exit-gateway` in Wireguard mode, we plan to step up the game. SGPv2 grants will be higher if operators can meet new requirements.
As we finalising last details of *"Project Smoosh"*, where one binary - `nym-node` - can run as an `entry-gateway`, `mixnode` or `exit-gateway` in Mixnet mode as well as `entry-gateway` or `exit-gateway` in Wireguard mode, we plan to step up the game. SGPv2 grants will be higher if operators can meet new requirements.
**Minimum Specs & Requirements**
@@ -614,7 +402,7 @@ These are minimum requirements to become a part of SGPv2. We aim to have nodes o
- [build(deps): bump criterion from `0.4.0` to `0.5.1`](https://github.com/nymtech/nym/pull/4911): Bumps [criterion](https://github.com/bheisler/criterion.rs) from `0.4.0` to `0.5.1`.
- [NS API: add mixnet scraper](https://github.com/nymtech/nym/pull/5200)
- [NS API: add mixnet scraper](https://github.com/nymtech/nym/pull/5200)
- [build(deps): bump http from `1.1.0` to `1.2.0`](https://github.com/nymtech/nym/pull/5228): Bumps [http](https://github.com/hyperium/http) from `1.1.0` to `1.2.0`.
@@ -622,41 +410,41 @@ These are minimum requirements to become a part of SGPv2. We aim to have nodes o
- [Add windows to CI builds](https://github.com/nymtech/nym/pull/5269)
- [nym topology revamp](https://github.com/nymtech/nym/pull/5271): This PR changes the internals of the `NymTopology` to blur the lines between explicit mixnodes and gateways so that what used to be considered a "mixnode" could be a valid egress point of the network. `NymTopology` is no longer divided into `BTreeMap<MixLayer, Vec<mix::Node>>` and `Vec<gateway::Node>`. instead there's information about the current rewarded set (to support future VRF work) and a simple map of `HashMap<NodeId, RoutingNode>`. The new features are mostly controlled via 2 new flags/config values:
- [nym topology revamp](https://github.com/nymtech/nym/pull/5271): This PR changes the internals of the `NymTopology` to blur the lines between explicit mixnodes and gateways so that what used to be considered a "mixnode" could be a valid egress point of the network. `NymTopology` is no longer divided into `BTreeMap<MixLayer, Vec<mix::Node>>` and `Vec<gateway::Node>`. instead there's information about the current rewarded set (to support future VRF work) and a simple map of `HashMap<NodeId, RoutingNode>`. The new features are mostly controlled via 2 new flags/config values:
- `use_extended_topology` that tells the client to retrieve **all** network nodes rather than the ones that got assigned "active" mixnode role (or support being a gateway)
- `ignore_egress_epoch_role` that tells the client it's fine to construct egress packets to nodes that are **not** assigned entry or exit gateway role
- [Nyx Chain Watcher](https://github.com/nymtech/nym/pull/5274)
- [Include `IPINFO_API_TOKEN` in nightly CI](https://github.com/nymtech/nym/pull/5285)
- [Move tun constants to network defaults](https://github.com/nymtech/nym/pull/5286):
- [Move tun constants to network defaults](https://github.com/nymtech/nym/pull/5286):
<AccordionTemplate name={<TestingSteps/>}>
1. **Regression Testing**:
- Verified no issues arose when running tests for the affected files.
- Tested TUN behaviour with new nym-nodes in the hu branch.
- Verified no issues arose when running tests for the affected files.
- Tested TUN behaviour with new nym-nodes in the hu branch.
**Results**:
**Results**:
- **No bugs detected**.
- Tunnels are functioning as expected, with traffic routing and IP generation working seamlessly.
</AccordionTemplate>
- **No bugs detected**.
- Tunnels are functioning as expected, with traffic routing and IP generation working seamlessly.
</AccordionTemplate>
- [Add dependabot assignes for the root cargo ecosystem](https://github.com/nymtech/nym/pull/5297)
- [build(deps): bump the patch-updates group across 1 directory with 35 updates](https://github.com/nymtech/nym/pull/5310): Bumps the `patch-updates` group with 33 updates
- [Periodically remove stale gateway messages](https://github.com/nymtech/nym/pull/5312): This PR introduces a simple task that removes gateway messages that haven't been retrieved in (by default) 24h.
- [Periodically remove stale gateway messages](https://github.com/nymtech/nym/pull/5312): This PR introduces a simple task that removes gateway messages that haven't been retrieved in (by default) 24h.
<AccordionTemplate name={<TestingSteps/>}>
**Automation Script for Data Cleanup Validation**
Test Objective: Validate that the stale message cleanup mechanism in the database correctly removes records older than the configured threshold (24 hours).
Test Setup:
1. Environment:
* SQLite database
* Bash script: used to insert data.
Steps Performed:
1. Ran the insert_data.sh script to populate the database with test data:
* Recent records inserted successfully.
@@ -664,8 +452,8 @@ Steps Performed:
3. Confirmed that all 20 records (10 recent + 10 stale) were present.
4. Allowed the system to run for 24 hours to trigger the cleanup mechanism.
5. Queried the database again after 24 hours: sqlite3 gateway_storage.db "SELECT * FROM message_store;"
6.
6.
Expected Result:
* All stale records (older than 24 hours) should be removed.
* Recent records should remain in the database.
@@ -676,18 +464,18 @@ Actual Result:
- [Use expect in geodata test to give error message on failure](https://github.com/nymtech/nym/pull/5314): Keep hitting this error on CI, from what I think is network hickup. But it's hard to tell form the log since the error is swallowed. Explicitly unwrap the result so we get a more detailed error output.
<AccordionTemplate name={<TestingSteps/>}>
**Quick Code Review**
**Summary**
**Quick Code Review**
**Summary**
1. **CI Workflow**: Adjusted paths to optimise build triggers, avoiding unnecessary CI runs while ensuring coverage for key directories
2. **Geolocation Test**: Improved error handling by replacing assertions with `.expect` for clearer debugging in API regression tests
**Conclusion**
**Conclusion**
Regression testing confirms everything works as intended. **Approved**.
</AccordionTemplate>
- [`CancellationToken`-based shutdowns](https://github.com/nymtech/nym/pull/5325): This PR introduces scaffolding for using `CancellationToken` and `TaskTracker` for our graceful shutdowns rather than the existing `TaskClient` and `TaskManager`.
- [`CancellationToken`-based shutdowns](https://github.com/nymtech/nym/pull/5325): This PR introduces scaffolding for using `CancellationToken` and `TaskTracker` for our graceful shutdowns rather than the existing `TaskClient` and `TaskManager`.
- [Introduce `/load` endpoint for self-reported quantised Nym Node load](https://github.com/nymtech/nym/pull/5326): This PR introduces a new `/load` endpoint on a `NymNode` to return its current load. It returns the following data:
```rust
@@ -717,7 +505,7 @@ The actual values for`NodeLoad` are determined as follows:
- Thus we calculate two additional auxiliary `Load` values, for memory usage and swap usage, i.e.: `used_memory / total_memory` and `used_swap / total_swap` respectively.
- Then we check whether either of the `MemoryLoad` or `SwapLoad` is bigger than the current base `Load` of the machine we have determined, if so, it's increased by one tier / bucket. For example, say the current machine load is `Load::Low`, but the memory usage is at 90% (`Load::VeryHigh`). that would result in the reported `Load` being bumped up to `Load::Medium` instead. The same logic applies with swap load, **however, only if the total swap > 1GB**. this is to prevent weird edge cases where the machine has hardly any swap.
- Finally, the `.total` `Load` uses the same "tier bumping" behaviour using the `.total` and `.network` loads, i.e. `if network > machine`, then `total = machine + 1`. for example if `machine` `Load` is `Load::Low`, but `network` `Load` is `Load::Medium`, then the `total` `Load` is set to `Load::Medium` instead.
</AccordionTemplate>
</AccordionTemplate>
- [Bump the `patch-updates` group with 8 updates](https://github.com/nymtech/nym/pull/5336)
@@ -729,29 +517,29 @@ The actual values for`NodeLoad` are determined as follows:
- [Bump mikefarah/yq from `4.44.6` to `4.45.1`](https://github.com/nymtech/nym/pull/5342)
- [Update `indexed_db_futures`](https://github.com/nymtech/nym/pull/5347): Updates the `indexed_db_futures` dependency to stop relying on the fork.
- [Update `indexed_db_futures`](https://github.com/nymtech/nym/pull/5347): Updates the `indexed_db_futures` dependency to stop relying on the fork.
- [Refresh wasm sdk](https://github.com/nymtech/nym/pull/5353): This PR refreshes the wasm clients to make them usable in the current network
- [Client gateway selection](https://github.com/nymtech/nym/pull/5358): Changed how gateway is selected.
- For init the target gateway can't support mixing
- For egress, unless `ignore_epoch_roles` is specified, the gateway can't be currently assigned to a mixing layer. But it can be standby or inactive
- [Exposed `NymApiClient` method for obtaining node performance history](https://github.com/nymtech/nym/pull/5360)
- [Bind to `[::]` on `nym-node` for both IP versions](https://github.com/nymtech/nym/pull/5361)
<AccordionTemplate name={<TestingSteps/>}>
**IPv4 Configuration and Migration Testing**
Testing Steps:
- Initiated and ran a nym-node with version 1.3.1 on an IPv4-only machine, then updated it to the new 'hu', 1.4.0 version.
- Initiated and ran a new nym-node with 'hu', 1.4.0 always on a machine with only IPv4.
- Initiated and ran a new nym-node with 'hu', 1.4.0 on a machine with both IPv4 and IPv6 for regression testing.
Results:
- No functional issues during version updates.
- Logged message on all versions: "no registered client for destination: ff02::2"
Status: Pass
</ AccordionTemplate>
@@ -766,10 +554,10 @@ Status: Pass
- Ensured a client is able to select a node which aside from a gateway, can also act as a mixnode
- Verified 'ignore_epoch_roles' is the default mode
- _note; this is most likely not going to be a permanent solution_
**Results:**
- Clients and topology are behaving correctly
- Clients and topology are behaving correctly
Status: Pass
</ AccordionTemplate>
@@ -824,7 +612,7 @@ We are developing a design where operators can enable multiple modes, and let th
- Moved top level `authenticator` section to `service_providers` so that it'd live alongside NR and IPR
- Added general `debug` section
- Added `metrics` section
- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation.
- All documentation migrated to a new URL [nym.com/docs](https://nym.com/docs) alongside the rebranding of Nym organisation.
- Updated [network architecture diagrams](https://nym.com/docs/network/architecture)
- New blow-by-blow mixnet [traffic flow](https://nym.com/docs/network/architecture) section
- [Winter Nym Squad League started](https://forum.nym.com/t/nym-squad-league-farewell-fall-welcome-winter/977)
@@ -860,11 +648,11 @@ We are developing a design where operators can enable multiple modes, and let th
- Everything in `mixnode` directory has been removed because there was nothing really left there. The mixing socket listener was unified in `nym-node` and similarly `verloc` was also moved there
- `gateway` directory was similarly reduced in size. Now it also creates appropriate tasks as opposed to the whole gateway process. eventually it might also be further stripped, but today is not that day.
- Removed the generic parameter on the `GatewayStorage` to simplify all the generics down the stack. it wasn't used anyway
CLI:
- Added `--modes` argument to specify all node modes with a single command (or `env` variable). for example: `--modes="mixnode,entry"`. Can't be used alongside `--modes`
- Extended `--mode` argument to allow specifying it multiple times, for example: `--mode mixnode --mode entry`. can't be used alongside `--mode`
Config changes:
- Replaced `mode` with `modes` to allow setting the node to run with say, `entry` + `mixnode` roles simultaneously
- Added `maximum_forward_packet_delay` to `mixnet.debug` section
@@ -889,17 +677,17 @@ Config changes:
- [Remove unneeded async function annotation](https://github.com/nymtech/nym/pull/5246)
- [Add control messages to `GatewayTransciver`](https://github.com/nymtech/nym/pull/5247)
<AccordionTemplate name={<TestingSteps/>}>
**Review and Testing: Forget Me Implementation**
**Review and Testing: Forget Me Implementation**
- Validated the encryption and delivery of `ForgetMe` control messages to the gateway
- Validated the encryption and delivery of `ForgetMe` control messages to the gateway
**Testing: MixTrafficController Integration**
**Testing: MixTrafficController Integration**
- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown
- Tested behaviour for gateway transceiver failures while sending control messages
**Testing: Gateway Storage Updates**
- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage
- Verified that the `MixTrafficController` invokes `ForgetMe` logic correctly during shutdown
- Tested behaviour for gateway transceiver failures while sending control messages
**Testing: Gateway Storage Updates**
- Confirmed successful deletion of client data (e.g., inbox messages, bandwidth allocations) from persistent storage
</AccordionTemplate>
- [Add conversion unit tests for auth msg](https://github.com/nymtech/nym/pull/5251)
@@ -916,13 +704,13 @@ Config changes:
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/credential-storage/src/backends/sqlite.rs`**
- Verified addition of `close` method for the SQLite backend
2. **Review File: `common/credential-storage/src/ephemeral_storage.rs`**
- Confirmed addition of `close` method for ephemeral storage with no action required
3. **Review File: `common/credential-storage/src/persistent_storage/mod.rs`**
- Ensured `close` method integration for persistent storage
4. **Review File: `common/credential-storage/src/storage.rs`**
- Verified updates to the `Storage` trait to include `close` and `cleanup_expired` methods
</AccordionTemplate>
@@ -931,15 +719,15 @@ Config changes:
<AccordionTemplate name={<TestingSteps/>}>
1. **Review File: `common/network-defaults/src/constants.rs`**
- Confirmed updated `mixnet_vpn` constants were added.
2. **Review File: `service-providers/ip-packet-router/src/constants.rs`**
- Checked replacement of legacy `TUN_*` constants with new `mixnet_vpn` constants.
- Validated alignment of routing traffic configurations.
3. **Review File: `service-providers/ip-packet-router/src/ip_packet_router.rs`**
- Ensured new `nym_network_defaults::constants::mixnet_vpn` constants replaced old references.
- Verified `TunDeviceConfig` consistency.
4. **Review File: `service-providers/ip-packet-router/src/util/generate_new_ip.rs`**
- Confirmed substitution of `TUN_DEVICE_*` constants with `NYM_TUN_DEVICE_*` constants.
- Tested functionality for generating random IPs within subnet.
@@ -955,54 +743,54 @@ Config changes:
- `nym_node_mixnet_ingress_excessive_delay_packets`
- `nym_node_mixnet_ingress_forward_hop_packets_dropped`
- `nym_node_mixnet_ingress_final_hop_packets_dropped`
- `nym_node_mixnet_ingress_forward_hop_packets_received_rate`
- `nym_node_mixnet_ingress_final_hop_packets_received_rate`
- `nym_node_mixnet_ingress_malformed_packets_received_rate`
- `nym_node_mixnet_ingress_excessive_delay_packets_rate`
- `nym_node_mixnet_ingress_final_hop_packets_received_rate`
- `nym_node_mixnet_ingress_malformed_packets_received_rate`
- `nym_node_mixnet_ingress_excessive_delay_packets_rate`
- `nym_node_mixnet_ingress_forward_hop_packets_dropped_rate`
- `nym_node_mixnet_ingress_final_hop_packets_dropped_rate`
- egress:
- `nym_node_mixnet_egress_stored_on_disk_final_hop_packets`
- `nym_node_mixnet_egress_forward_hop_packets_sent`
- `nym_node_mixnet_egress_ack_packets_sent`
- `nym_node_mixnet_egress_forward_hop_packets_dropped`
- `nym_node_mixnet_egress_forward_hop_packets_sent_rate`
- `nym_node_mixnet_egress_ack_packets_sent_rate`
- `nym_node_mixnet_egress_forward_hop_packets_dropped_rate`
- client sessions
- `nym_node_entry_client_sessions_unique_users`
- `nym_node_entry_client_sessions_sessions_started`
- `nym_node_entry_client_sessions_finished_sessions`
- `nym_node_entry_client_sessions_durations_{TYP}` (histogram), for example `nym_node_entry_client_sessions_durations_vpn`
- wireguard:
- `nym_node_wireguard_bytes_rx`
- `nym_node_wireguard_bytes_tx`
- `nym_node_wireguard_bytes_total_peers`
- `nym_node_wireguard_bytes_active_peers`
- `nym_node_wireguard_bytes_rx_rate`
- `nym_node_wireguard_bytes_tx_rate`
- network
- `nym_node_network_active_ingress_mixnet_connections`
- `nym_node_network_active_ingress_web_socket_connections`
- `nym_node_network_active_egress_mixnet_connections`
- process
- `nym_node_process_forward_hop_packets_being_delayed`
- `nym_node_process_packet_forwarder_queue_size`
- `nym_node_process_topology_query_resolution_latency` (histogram)
- `nym_node_process_final_hop_packets_pending_delivery`
- `nym_node_process_forward_hop_packets_pending_delivery`
- `nym_node_process_forward_hop_packets_pending_delivery`
</AccordionTemplate>
- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb
- [Amend 250gb limit](https://github.com/nymtech/nym/pull/5313): Change bandwidth cap to 250gb
- [Warn users if node is run in exit mode only](https://github.com/nymtech/nym/pull/5320): Throws a warning if node is run in "exit" mode only as by default, this will **NOT** enable entry capabilities, i.e. opening the websocket. thus making it ineligible for rewarded set selection (and rewards)
- [Reduce log severity for number of packets being delayed](https://github.com/nymtech/nym/pull/5321)
- [Apply 1.84 linter suggestions](https://github.com/nymtech/nym/pull/5330)
@@ -1018,7 +806,7 @@ Config changes:
- [Make sure to apply gateway score filtering when choosing initial node](https://github.com/nymtech/nym/pull/5256)
- [Fixed client session histogram buckets](https://github.com/nymtech/nym/pull/5316)
- [Contract version assignment](https://github.com/nymtech/nym/pull/5318): This PR fixes updates to current nym-node version as well as introduces migration to fix the existing state of the mainnet contract
- [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness)
- [Make sure refresh data key matches bond info](https://github.com/nymtech/nym/pull/5329): This is to forbid operators from reusing the same underlying identity key for multiple nodes by overwriting the describe data. the reported key has to always match what the node has bonded with (and the contract enforces uniqueness)
## Archived Changelog
@@ -128,15 +128,10 @@ mkdir -pv <PATH_TO_TARGET_DIRECTORY>
###### 2. Backup `clients.sqlite` database
- Install `sqlite3`
```sh
apt install sqlite3
```
- **Stop your node**
```sh
service nym-node stop
```
- Open sqlite CLI shell inside `clients.sqlite` database
```sh
sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
@@ -156,14 +151,10 @@ sqlite3 ~/.nym/nym-nodes/default-nym-node/data/clients.sqlite
scp -r <SOURCE_USER_NAME>@<SOURCE_HOST_ADDRESS>:~/.nym/nym-nodes/<ID> <PATH_TO_TARGET_DIRECTORY>
```
###### 4. Verify the success of the backup & start your node
###### 4. Verify the success of the backup
The `scp` command should print logs, an operator can see directly whether it was successful or if it encountered any error. However, double check that all your needed configuration is in the backup target directory.
- Start your node
```sh
service nym-node start && journalctl -u nym-node -f
```
</Steps>
Now you have everything needed to restore your `nym-node` on another server. If you are in a need of doing so, follow the steps in [*Restoring a node*](#restoring-a-node) chapter below.
@@ -369,7 +360,7 @@ mkdir ~/.nym/nym-nodes
```
###### 2. Backup `clients.sqlite` database
- **Stop your node**
- Stop your node
```sh
service nym-node stop
```
@@ -20,12 +20,12 @@ This documentation page provides a guide on how to set up and run a [NYM NODE](.
```sh
nym-node
Binary Name: nym-node
Build Timestamp: 2025-03-06T20:32:36.922212778Z
Build Version: 1.6.2
Commit SHA: 247ebb7c4339de0a298a7fcb2574122a8306c3b8
Commit Date: 2025-03-06T21:26:16.000000000+01:00
Build Timestamp: 2025-02-13T11:49:34.670488195Z
Build Version: 1.5.0
Commit SHA: a3e19b4563843055b305ea9a397eb1ad84b5c378
Commit Date: 2025-02-10T18:14:47.000000000+01:00
Commit Branch: HEAD
rustc Version: 1.85.0
rustc Version: 1.84.1
rustc Channel: stable
cargo Profile: release
```
@@ -3,9 +3,8 @@ import { VarInfo } from 'components/variable-info.tsx';
import { Steps } from 'nextra/components';import { Tabs } from 'nextra/components';
import { MyTab } from 'components/generic-tabs.tsx';
import PortsNymNode from 'components/operators/snippets/ports-nym-node.mdx';
import PortsValidator from 'components/operators/snippets/ports-validator.mdx';
import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx';
import NTPSync from 'components/operators/snippets/ntp-time-sync.mdx'
import PortsValidator from 'components/operators/snippets/ports-validator.mdx'
import NymNodeSpecs from 'components/operators/snippets/nym-node-specs.mdx'
# VPS Setup & Configuration
@@ -43,18 +42,14 @@ apt update -y && apt --fix-broken install
```
- Install dependencies
```sh
apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git ntp ntpdate
apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git
```
- Double check ufw is installed correctly
```sh
apt install ufw --fix-missing
```
###### 2. Synchronize time of your server
<NTPSync />
###### 3. Configure your firewall using Uncomplicated Firewall (UFW)
###### 2. Configure your firewall using Uncomplicated Firewall (UFW)
For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server. The following commands will allow you to set up a firewall using `ufw`.
@@ -75,7 +70,7 @@ ufw enable
ufw status
```
###### 4. Open all needed ports to have your firewall for `nym-node` working correctly
###### 3. Open all needed ports to have your firewall for `nym-node` working correctly
<div>
<Tabs items={[
@@ -1,746 +0,0 @@
import { Callout } from 'nextra/components';
import { Tabs } from 'nextra/components';
import { VarInfo } from 'components/variable-info.tsx';
import { Steps } from 'nextra/components';
import {Accordion, AccordionItem} from "@nextui-org/react";
import { MyTab } from 'components/generic-tabs.tsx';
import { AccordionTemplate } from 'components/accordion-template.tsx';
# Advanced Server Administration
This page is for experienced operators and aspiring sys-admins who seek for higher optimisation and better efficiency of their work managing Nym infrastructure. The steps shared on this page cannot be simply copy-pasted, they ask you for more attention and consideration all the way from choosing server and OS to specs per VM allocation.
<VarInfo />
## Virtualising a Dedicated Server
Some operators or squads of operators orchestrate multiple Nym nodes. Among other benefits (which are out of scope of this page), these operators can decide to acquire one larger dedicated (or bare-metal) server with enough specs (CPU, RAM, storage, bandwidth and port speed) to meet [minimum requirements](../../../nodes#minimum-requirements) for multiple nodes run in parallel.
This guide explains how to prepare your server in order to be able to host multiple nodes running on separated VMs.
<Callout type="info">
This guide is based on Ubuntu 22.04, in case you prefer another OS, you may have to do a bit of your own research to troubleshoot networking configuration and other parameters.
</Callout>
### Installing KVM on a Server with Ubuntu 22.04
**KVM** stands for **Kernel-based Virtual Machine**. It is a virtualization technology for Linux that allows a user to run multiple virtual machines (VMs) on a single physical machine. KVM turns the Linux kernel into a hypervisor, enabling it to manage multiple virtualised systems.
Follow the steps below to install KVM on Ubuntu 22.04 LTS.
#### Prerequisites
<Callout type="warning">
Operators aiming to run Nym node as mixnet [Exit Gateway](../../../community-counsel/exit-gateway) or with wireguard enabled should familiarize themselves with the challenges possibly coming along `nym-node` operation, described in our [community counsel](../../../community-counsel) and follow up with [legal suggestions](../../../community-counsel/legal). Particularly important is to [introduce yourself](../../../community-counsel/legal#introduce-nym-node-to-your-provider) and your intentions to run a Nym node to your provider.
This step is essential part of legal self defense because it may prevent your provider immediately shutting down your entire service (with all the VMs on it) when receiving first abuse report.
Additionally, before purchasing a large server, **contact the provider and ask if the offered CPU supports Virtualization Technology (VT)**, without this feature you will not be able to proceed.
</Callout>
Start with obtaining a server with Ubuntu 22.04 LTS:
- Make sure that your server meets [minimum requirements](../vps-setup#nym-node---dedicated-server) multiplied by number of `nym-node` instance you aim to run on it.
- Most people rent a server from a provider and it comes with a pre-installed OS (in this guide we use Ubuntu 22.04). In case your choice is a bare-metal machine, you probably know what you are doing, there are some useful guides to install a new OS, like [this one on ostechnix.com](https://ostechnix.com/install-ubuntu-server/).
Make sure thay your system actually supports hardware virtualisation:
- Check out the methods documented in [this guide by ostechnix.com](https://ostechnix.com/how-to-find-if-a-cpu-supports-virtualization-technology-vt/).
Order enough IPv4 and IPv6 (static and public) addresses to have one of each for each planned VM plus one extra for the main machine.
When you have your OS installed, validated CPU virtualisation support and obtained IP addresses, you can start configuring your VMs, following the steps below.
> Note that the commands below require root permission. You can either go through the setup as `root` or use `sudo` prefix with the commands used in the guide. You can switch to `root` shell by entering one of these commands `sudo su` or `sudo -i`.
<Steps>
##### 1. Install KVM
- Install KVM and required components:
```sh
apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst
```
<br/>
<AccordionTemplate name="Component breakdown">
- `qemu-kvm`: Provides the core **KVM virtualization** support using QEMU.
- `libvirt-daemon-system`: Manages virtual machines via the **libvirt daemon**.
- `libvirt-clients` Provides command-line tools like `virsh` to manage VMs.
- `bridge-utils`: Enables **network bridging**, allowing VMs to communicate over the network.
- `virtinst`: Includes `virt-install` for **creating virtual machines** via CLI.
</AccordionTemplate>
- Start the `libvertd` service:
```sh
systemctl enable libvirtd
systemctl start libvirtd
```
- Validate by checking status of `libvirt` service:
```sh
systemctl status libvirtd
```
<br/>
<AccordionTemplate name="Console output">
The command output should look similar to this one:
```
root@nym-exit:~# systemctl status libvirtd
● libvirtd.service - Virtualization daemon
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2025-02-27 14:25:28 MSK; 2min 1s ago
TriggeredBy: ● libvirtd-ro.socket
● libvirtd.socket
● libvirtd-admin.socket
Docs: man:libvirtd(8)
https://libvirt.org
Main PID: 6232 (libvirtd)
Tasks: 21 (limit: 32768)
Memory: 11.8M
CPU: 852ms
CGroup: /system.slice/libvirtd.service
├─6232 /usr/sbin/libvirtd
├─6460 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
└─6461 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
Feb 27 14:25:28 nym-exit.example.com systemd[1]: Started Virtualization daemon.
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: started, version 2.90 cachesize 150
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth cryptohash DNSSEC loop-detect inotify dump>
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, IP range 192.168.122.2 -- 192.168.122.254, lease time 1h
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: DHCP, sockets bound exclusively to interface virbr0
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: reading /etc/resolv.conf
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: using nameserver 127.0.0.53#53
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /etc/hosts - 8 names
Feb 27 14:25:30 nym-exit.example.com dnsmasq[6460]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 names
Feb 27 14:25:30 nym-exit.example.com dnsmasq-dhcp[6460]: read /var/lib/libvirt/dnsmasq/default.hostsfile
```
</AccordionTemplate>
- In case you don't configure KVM as `root`, add your current user to the `kvm` and `libvirt` groups to enable VM creation and management using the `virsh` command-line tool or the `virt-manager` GUI:
```bash
usermod -aG kvm $USER
usermod -aG libvirt $USER
```
##### 2. Setup Bridge Networking with KVM
A **bridged network** lets VMs share the hosts network interface, allowing direct IPv4/IPv6 access like a physical machine.
By default, KVM sets up a **private virtual bridge**, enabling VM-to-VM communication within the host. It provides its own subnet, DHCP, and NAT for external access.
Check the IP of KVMs default virtual interfaces with:
```bash
ip a
```
<br/>
<AccordionTemplate name="Console output">
The command output should look similar to this one:
```
root@nym-exit:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
altname enp2s0f0
3: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
altname enp4s0f0
inet 31.222.238.222/24 brd 31.222.238.255 scope global eno49
valid_lft forever preferred_lft forever
inet6 fe80::3a63:bbff:fe2e:9d20/64 scope link
valid_lft forever preferred_lft forever
4: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
altname enp2s0f1
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
altname enp2s0f3
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
```
</AccordionTemplate>
By default, KVM uses the `virbr0` network with `<IPv4_ADDRESS>.1/24`, assigning guest VMs IPs in the `<IPv4_ADDRESS>.0/24` range. The host OS is reachable at `<IPv4_ADDRESS>.1`, allowing SSH and file transfers (`scp`) between the host and guests.
This setup works if you only access VMs from the host. However, remote systems on a different subnet (e.g., `<IPv4_ADDRESS_ALT>.0/24`) **cannot** reach the VMs.
To enable external access, we need a *public bridge* that connects VMs to the hosts main network, using its DHCP. This ensures VMs get IPs in the same range as the host.
Before configuring a public bridge, **disable Netfilter** on bridges for better performance and security, as it is enabled by default.
- Create a file located at `/etc/sysctl.d/bridge.conf`:
```bash
nano /etc/sysctl.d/bridge.conf
# in case of using custom editor, replace nano in the syntax
```
- Paste inside the following block, save and exit:
```ini
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
```
- Create a file `/etc/udev/rules.d/99-bridge.rules`:
```bash
nano /etc/udev/rules.d/99-bridge.rules
```
- Paste this line, save and exit:
```bash
ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"
```
This disables Netfilter on bridges at startup. Save, exit, and reboot to apply changes.
- Disable KVMs default networking. Find the default network interface with:
```bash
ip link
```
<br/>
<AccordionTemplate name="Console output">
The command output should look similar to this one:
```
root@nym-exit:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
altname enp2s0f0
3: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
altname enp2s0f1
4: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
altname enp4s0f0
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
altname enp2s0f3
8: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether 52:54:00:ac:d3:ba brd ff:ff:ff:ff:ff:ff
```
The `virbr0` interface is KVMs default network. Note your physical interfaces MAC address (e.g., `eno49`). It's the only interface that is currently `UP` and running (`LOWER_UP` state). Other interfaces are `DOWN` and not in use.
</AccordionTemplate>
- Remove the default KVM network:
```bash
virsh net-destroy default
```
- Remove the default network configuration:
```bash
virsh net-undefine default
```
- In case last two commands didn't work, try this:
```bash
ip link delete virbr0 type bridge
```
- Verify that the `virbr0` and `virbr0-nic` interfaces are deleted:
```bash
ip link
```
<AccordionTemplate name="Console output">
The command output should look similar to this one:
```
root@nym-exit:~# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
altname enp2s0f0
3: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
altname enp2s0f1
4: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
altname enp4s0f0
5: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
altname enp2s0f2
6: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
altname enp4s0f1
7: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
altname enp2s0f3
```
KVM network is gone.
</AccordionTemplate>
##### 3. Setup KVM public bridge for new VMs
To create a KVM network bridge on Ubuntu, edit a config file located in `/etc/netplan/` either called `00-installer.yaml` or `00-installer-config.yaml` and add the bridge details.
- Before you edit the file, make a backup to stay on the save side:
```bash
cp /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.bak
# or
cp /etc/netplan/00-installer.yaml /etc/netplan/00-installer.yaml.bak
```
- Open `00-installer-config.yaml` or `00-installer.yaml.`config in a text editor:
```bash
nano /etc/netplan/00-installer.yaml
# or
nano /etc/netplan/00-installer-config.yaml
```
- Edit the block below and paste it to the config file, save and exit:
```ini
#####################################################
######## CHANGE ALL VARIABLES IN <> BRACKETS ########
#####################################################
# <INTERFACE> is your own one, you can get with command ip link show
# <HOST> is your server main IPv4 address
# <GATEWAY> value can be found by running: ip route | grep default
# This is the network config written by 'subiquity'
network:
version: 2
ethernets:
<INTERFACE>:
dhcp4: false
dhcp6: false
# Bridge interface configuration
bridges:
br0:
interfaces: [<INTERFACE>]
addresses: [<HOST>/24]
routes:
- to: default
via: <GATEWAY>
mtu: 1500
nameservers:
addresses:
- 8.8.8.8
- 1.1.1.1
- 77.88.8.8
parameters:
stp: false # Disable STP unless multiple bridges exist
forward-delay: 15 # Can be shortened, 15 sec is a common default
```
<Callout type="warning">
Ensure the indentation matches exactly as shown above. Incorrect spacing will prevent the bridged network interface from activating.
</Callout>
- Validate `netplan` configuration without applying to prevent breaking network changes:
```bash
netplan generate
# Correct configuration output will show nothing
```
- Safety test your changes to catch syntax errors before applying:
```bash
netplan try
```
- Apply your changes:
```bash
netplan --debug apply
```
- In case of proubems try some of these steps:
<AccordionTemplate name="Netplan configuration troubleshooting">
- Validate YAML configuration, given that YAML is syntax sensitive:
```bash
apt install yamllint -y
yamllint /etc/netplan/00-installer.yaml
# or
yamllint /etc/netplan/00-installer-config.yaml
```
- Apply correct permissions:
```bash
chmod 600 /etc/netplan/00-installer.yaml
chown root:root /etc/netplan/00-installer.yaml
```
- Manually bring up the bridge:
```bash
ip link add name br0 type bridge
ip link set br0 up
ip a show br0
```
- ensure `systemd-networkd` is enabled:
```bash
systemctl restart systemd-networkd
systemctl status systemd-networkd
# if inactive, enable it:
systemctl enable --now systemd-networkd
```
</AccordionTemplate>
- If things went wrong, you can always revert from the backed up file:
```bash
cp /etc/netplan/00-installer-config.yaml.bak /etc/netplan/00-installer-config.yaml
# or
cp /etc/netplan/00-installer.yaml.bak /etc/netplan/00-installer.yaml
# and
netplan apply
```
<Callout type="warning">
Using different IPs for your physical NIC and KVM bridge will disconnect SSH when applying changes. Reconnect using the bridge's new IP. If both share the same IP, no disruption occurs.
</Callout>
- Verify that the IP address has been assigned to the bridge interface:
```bash
ip a
```
<AccordionTemplate name="Console output">
The command output should look similar to this one:
```
root@nym-exit:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:14 brd ff:ff:ff:ff:ff:ff
altname enp2s0f0
3: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:15 brd ff:ff:ff:ff:ff:ff
altname enp2s0f1
4: eno3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:16 brd ff:ff:ff:ff:ff:ff
altname enp2s0f2
5: eno49: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br0 state UP group default qlen 1000
link/ether 38:63:bb:2e:9d:20 brd ff:ff:ff:ff:ff:ff
altname enp4s0f0
6: eno4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 14:02:ec:35:2e:17 brd ff:ff:ff:ff:ff:ff
altname enp2s0f3
7: eno50: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 38:63:bb:2e:9d:24 brd ff:ff:ff:ff:ff:ff
altname enp4s0f1
8: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 46:50:aa:c0:49:a5 brd ff:ff:ff:ff:ff:ff
inet 31.222.238.222/24 brd 31.222.238.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fe80::4450:aaff:fec0:49a5/64 scope link
valid_lft forever preferred_lft forever
```
The bridged interface `br0` now has the IP `<HOST>`, and `<INTERFACE>` shows `master br0`, indicating it is part of the bridge.
</AccordionTemplate>
Alternatively you can use `brctl` command to display the KVM bridge network status:
```bash
brctl show br0
```
##### 4. Add Bridge Network to KVM
- Configure KVM to use the bridge by creating `host-bridge.xml`, open a text editor and pate the block below:
```bash
nano host-bridge.xml
```
```xml
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
```
- Start the new bridge and set it as the default for VMs:
```bash
virsh net-define host-bridge.xml
virsh net-start host-bridge
virsh net-autostart host-bridge
```
- Verify that the KVM bridge is active:
```bash
virsh net-list --all
```
<AccordionTemplate name="Console output">
```bash
root@nym-exit:~# virsh net-list --all
Name State Autostart Persistent
------------------------------------------------
host-bridge active yes yes
```
</AccordionTemplate>
KVM bridge networking is successfully set up and active!
Your KVM installation is now ready to deploy and manage VMs.
</Steps>
### Setting Up Virtual Machines
After finishing the [installation of KVM](#installing-kvm-on-a-server-with-ubuntu-2204), we can move to the virtualisation configuration.
> **The steps below will guide you through a setup of one VM, therefore you will have to repeat this process for each VM**. That also means that you have to be mindful of space and memory allocation.
<Steps>
##### 1. Install OS for VMs
This is the OS on which the nodes themselves will run. You can chose any GNU/Linux of your preference. For this guide we are going to be using Ubuntu 24.04 LTS (Noble Numbat) cloud image from [cloud-images.ubuntu.com](https://cloud-images.ubuntu.com/noble/current/).
- Download Ubuntu Cloud image:
```bash
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
```
- Copy the image to to `/var/lib/libvirt/images/` asigning to it a name your VM
```bash
cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/<VM_NAME>.img
# for example:
# cp noble-server-cloudimg-amd64.img /var/lib/libvirt/images/ubuntu-1.img
```
##### 2. Create and resize a virtual machine
- Get `guestfs-tools` to be able to customize your login credentials:
```bash
apt install guestfs-tools
```
- Define login credentials:
```bash
virt-customize -a /var/lib/libvirt/images/<VM_NAME>.img --root-password password:<PASSWORD>
# for example
# virt-customize -a /var/lib/libvirt/images/ubuntu-1.img --root-password password:makesuretosaveyourpasswordslocallytoapasswordmanager
```
- Use `qemu-img` tool with a command `resize` to create a VM according your needs. You can see `qemu` [documentation page`](https://www.qemu.org/docs/master/tools/qemu-img.html) for more info on how to use it correctly.
```bash
qemu-img resize /var/lib/libvirt/images/<VM_NAME>.img +<SIZE_IN_GB>G
# for example
# qemu-img resize /var/lib/libvirt/images/ubuntu-1.img +100G
```
- Resize it from within it after `virt-install` command:
```bash
virt-install \
--name <VM_NAME> \
--ram=<SIZE_IN_MB> \
--vcpus=<NUMBER_OF_VIRTUAL_CPUS> \
--cpu host \
--hvm \
--disk bus=virtio,path=/var/lib/libvirt/images/<VM_NAME>.img \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo <YOUR_CHOSEN_OS_NAME> \
--import
```
- In our example we go with 4 GB RAM on the same machine as before:
<br/>
<AccordionTemplate name="Command example">
```bash
virt-install \
--name ubuntu-1 \
--ram=4096 \
--vcpus=4 \
--cpu host \
--hvm \
--disk bus=virtio,path=/var/lib/libvirt/images/ubuntu-1.img \
--network bridge=br0 \
--graphics none \
--console pty,target_type=serial \
--osinfo ubuntunoble \
--import
```
</AccordionTemplate>
- After loading you should see a login console, you can also initiate it by:
```bash
virsh console <VM_NAME>
# for example
# virsh console ubuntu-1
```
- Log in to your new VM using your credentials.
##### 3. Validate your setup
- Make sure the `root` disk has the expected space by running:
```bash
df -h
```
- If not, run:
```bash
growpart /dev/vda 1
resize2fs /dev/vda1
```
##### 4. Configure networking for the VM
As this guide is based on a newer Ubuntu, we use `netplan`, this may be different on different OS.
- Open `/etc/netplan/01-network-config.yaml` in your favourite text editor:
```bash
nano /etc/netplan/01-network-config.yaml
```
- Insert this config, using your correct IP configuration, save and exit:
```ini
network:
version: 2
renderer: networkd
ethernets:
<INTERFACE>:
dhcp4: false
dhcp6: false # Set to true if you want automatic IPv6 assignment
addresses:
- <IPv4_VM>/24 # Assign IPv4 address to the VM
- <IPv6_VM>/64 # Assign IPv6 address to the VM
routes:
- to: default
via: <IPv4_GATEWAY_HOST_SERVER> # IPv4 gateway (host machine)
- to: default
via: <IPv6_GATEWAY_HOST_SERVER> # IPv6 gateway (host machine)
nameservers:
addresses:
- 1.1.1.1 # Cloudflare IPv4 DNS
- 8.8.8.8 # Google IPv4 DNS
- 2606:4700:4700::1111 # Cloudflare IPv6 DNS
- 2001:4860:4860::8888 # Google IPv6 DNS
```
- Fix wide permissions on the config file:
```bash
chmod 600 /etc/netplan/01-network-config.yaml
```
- Check if the config has any errors:
```bash
netplan generate
```
- Apply the configuration:
```bash
netplan --debug apply
```
- Verify by checking if IPv4 and IPv6 are assigned correctly and if they route:
```bash
ip -4 a
ip -6 a
```
```bash
ip -4 r
ip -6 r
```
```bash
# to ping through IPv6, use:
ping6 nym.com
```
- You should be able to ping your new VM from a local machine:
```bash
ping <IPv4_VM>
ping6 <IPv6_VM>
```
</Steps>
Your VM should be working and fully routable. To be able to use it properly, we will create a direct SSH access to the VM.
#### Configure VM SSH access
<Steps>
##### 1. Log in to your VM, update and upgrade your OS:
- Log in to your server using as `root` or as a non-root user with `sudo` privileges
```bash
apt update; apt upgrade
```
##### 2. Generate new host SSH keys
Since we used a `cloud-init` image without an SSH server, we need to generate SSH host keys for client authentication and server identity verification. All of them will be saved to this location: `/etc/ssh/<KEY>`.
- Generate a new RSA host key:
```bash
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
```
- Generate a new DSA host key:
```bash
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
```
- Generate a new ECDSA host key:
```bash
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
```
- Finally, generate a new ED25519 host key:
```bash
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
```
##### 3. Restart the SSH service on the server
- Run:
```bash
systemctl restart ssh.service
```
##### 4. Check if the SSH serice is active
- Run:
```bash
systemctl status ssh.service
```
##### 5. Create file `~/.ssh/authorized_keys` and add you public key:
- Create `.ssh` directory:
```bash
mkdir ~/.ssh
```
- Open with your favourite text editor:
```bash
nano ~/.ssh/authorized_keys
```
- Paste your SSH public key, save and exit
- In case of non-root, setup a correct ownership and permissions:
```bash
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chown : ~/.ssh
```
##### 5. Test by connecting via SSH
- Now you should be able to connect to the VM directly from your local terminal
```bash
ssh root@<IPv4> -i ~/.ssh/your_ssh_key
```
</Steps>
Now your VM is almost ready for `nym-node` [setup](../../nym-node/setup). Before you proceed, ssh in and [configure all prerequisities](../vps-setup#vps-configuration) needed for `nym-node` installation and operation.
-7
View File
@@ -1,7 +0,0 @@
{
"git": {
"deploymentEnabled": {
"master": false
}
}
}
-3
View File
@@ -1,3 +0,0 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
-40
View File
@@ -1,40 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
-36
View File
@@ -1,36 +0,0 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
-33
View File
@@ -1,33 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": ["node_modules", ".next", "public"]
},
"formatter": {
"enabled": true,
"indentStyle": "space"
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"suspicious": {
"noExplicitAny": "warn"
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
}
}
-23
View File
@@ -1,23 +0,0 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
reactStrictMode: true,
basePath: "/explorer",
assetPrefix: "/explorer",
trailingSlash: false,
async redirects() {
return [
// Change the basePath to /explorer
{
source: "/",
destination: "/explorer",
basePath: false,
permanent: true,
},
]
}
};
export default nextConfig;
-64
View File
@@ -1,64 +0,0 @@
{
"name": "@nymproject/explorer-v2",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"build": "next build",
"build:prod": "yarn --cwd .. build && next build",
"start": "next start",
"lint": "biome check --fix"
},
"engines": {
"node": ">=20.0.0"
},
"dependencies": {
"@chain-registry/types": "^0.50.36",
"@cosmos-kit/keplr-extension": "^2.14.0",
"@cosmos-kit/react": "^2.20.1",
"@emotion/cache": "^11.13.5",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@interchain-ui/react": "^1.26.1",
"@mui/icons-material": "^5.16.11",
"@mui/material": "^6.1.10",
"@mui/material-nextjs": "^6.1.9",
"@mui/x-date-pickers": "^7.23.2",
"@nivo/line": "^0.88.0",
"@nymproject/contract-clients": "^1.4.1",
"@nymproject/react": "1.0.0",
"@tanstack/react-query": "^5.64.2",
"@tanstack/react-query-devtools": "^5.64.2",
"@tanstack/react-query-next-experimental": "^5.66.0",
"@tanstack/react-table": "^8.20.6",
"@types/qs": "^6.9.18",
"@uidotdev/usehooks": "^2.4.1",
"chain-registry": "^1.69.64",
"cldr-compact-number": "^0.4.0",
"date-fns": "^4.1.0",
"i18next": "^24.2.2",
"i18next-resources-to-backend": "^1.2.1",
"isomorphic-dompurify": "^2.21.0",
"material-react-table": "^3.0.3",
"next": "^15.2.0",
"openapi-fetch": "^0.13.4",
"qrcode.react": "^4.1.0",
"qs": "^6.14.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-i18next": "^15.4.0",
"react-markdown": "^9.0.3",
"react-random-avatars": "^1.3.1",
"react-world-flags": "^1.6.0",
"zod": "^3.24.1"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "15.0.3",
"lefthook": "^1.8.5",
"typescript": "^5"
}
}
-1
View File
@@ -1 +0,0 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 391 B

-1
View File
@@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

@@ -1,61 +0,0 @@
<svg
width="33"
height="32"
viewBox="0 0 33 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
width="6.4"
height="6.38019"
transform="matrix(1 1.74846e-07 1.74846e-07 -1 7.06641 25.5204)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="6.4"
height="6.38019"
transform="matrix(1 1.74846e-07 1.74846e-07 -1 0.666504 31.9006)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="6.4"
height="6.38019"
transform="matrix(1 1.74846e-07 1.74846e-07 -1 13.4663 19.1406)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="6.4"
height="6.38019"
transform="matrix(1 1.74846e-07 1.74846e-07 -1 19.8667 12.761)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M32.6663 32L26.2663 32L26.2663 6.38018L0.708989 6.38017L0.70899 -1.52588e-05L24.9863 -1.1014e-05C29.2278 -1.02724e-05 32.6663 3.43845 32.6663 7.68L32.6663 32Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

-7
View File
@@ -1,7 +0,0 @@
<svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="15" width="3" height="3" transform="rotate(-90 0 15)" fill="currentColor" />
<rect x="3" y="12" width="3" height="3" transform="rotate(-90 3 12)" fill="currentColor" />
<rect x="6" y="9" width="3" height="3" transform="rotate(-90 6 9)" fill="currentColor" />
<rect x="9" y="6" width="3" height="3" transform="rotate(-90 9 6)" fill="currentColor"/>
<path d="M0 2.19345e-05V3.00002H11.9997V15H14.9997V3.00002C14.9997 1.34317 13.6565 2.19345e-05 11.9997 2.19345e-05H0Z" fill="currentColor" />
</svg>

Before

Width:  |  Height:  |  Size: 579 B

-31
View File
@@ -1,31 +0,0 @@
<svg width="361" height="361" viewBox="0 0 361 361" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_236_24563)">
<path d="M180.789 120.41V150.41H210.789V180.41H240.789V180.41C240.789 147.273 213.926 120.41 180.789 120.41V120.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M180.789 240.487L180.789 210.487L150.789 210.487L150.789 180.487L120.789 180.487V180.487C120.789 213.624 147.652 240.487 180.789 240.487V240.487Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M120.789 180.41L150.789 180.41L150.789 150.41L180.789 150.41L180.789 120.41V120.41C147.652 120.41 120.789 147.273 120.789 180.41V180.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M240.789 180.487L210.789 180.487L210.789 210.487L180.789 210.487L180.789 240.487V240.487C213.926 240.487 240.789 213.624 240.789 180.487V180.487Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M330.773 120.41L330.773 150.41V150.41C347.342 150.41 360.773 136.979 360.773 120.41V120.41L330.773 120.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M270.789 60.4102L270.789 90.4102L300.789 90.4102L300.789 60.4102L270.789 60.4102Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M240.789 30.4102L240.789 60.4102L270.789 60.4102L270.789 30.4102L240.789 30.4102Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M60.7891 30.4102L60.7891 60.4102L90.7891 60.4102L90.7891 30.4102L60.7891 30.4102Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M30.7734 60.4102L30.7734 90.4102L60.7734 90.4102L60.7734 60.4102L30.7734 60.4102Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M90.7891 0.410156L90.7891 30.4102L240.789 30.4102L240.789 0.410181L90.7891 0.410156Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<rect width="30" height="150.466" transform="matrix(-1.62921e-07 1 1 1.62921e-07 180.789 120.41)" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<rect width="120" height="30" transform="matrix(-1.62921e-07 1 1 1.62921e-07 330.773 0.410156)" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M301.023 90.4102L301.023 120.41L331.023 120.41L331.023 90.4102L301.023 90.4102Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M30.7734 240.41L30.7734 210.41V210.41C14.2049 210.41 0.77344 223.842 0.773438 240.41V240.41L30.7734 240.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M90.7734 300.41L90.7734 270.41L60.7734 270.41L60.7734 300.41L90.7734 300.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M120.773 330.41L120.773 300.41L90.7734 300.41L90.7734 330.41L120.773 330.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M300.773 330.41L300.773 300.41L270.773 300.41L270.773 330.41L300.773 330.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M330.773 300.41L330.773 270.41L300.773 270.41L300.773 300.41L330.773 300.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M270.773 360.41L270.773 330.41L120.773 330.41L120.773 360.41L270.773 360.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<rect width="30" height="150.481" transform="matrix(1.62921e-07 -1 -1 -1.62921e-07 180.789 240.41)" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<rect width="120" height="30" transform="matrix(1.62921e-07 -1 -1 -1.62921e-07 30.7734 360.41)" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
<path d="M60.5391 270.41L60.5391 240.41L30.5391 240.41L30.5391 270.41L60.5391 270.41Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
</g>
<defs>
<clipPath id="clip0_236_24563">
<rect width="360" height="360" fill="white" style="fill:white;fill-opacity:1;" transform="translate(0.773438 0.410156)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

-13
View File
@@ -1,13 +0,0 @@
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M3 3L-4.47035e-08 3L-8.31509e-07 6L3 6L3 3Z" fill="currentColor" />
<path d="M6 6L3 6L3 9L6 9L6 6Z" fill="currentColor" />
<path d="M9 9L6 9L6 12L9 12L9 9Z" fill="currentColor" />
<path d="M12 6L9 6L9 9L12 9L12 6Z" fill="currentColor" />
<path d="M15 3L12 3L12 6L15 6L15 3Z" fill="currentColor" />
</svg>

Before

Width:  |  Height:  |  Size: 431 B

-14
View File
@@ -1,14 +0,0 @@
<svg
width="9"
height="5"
viewBox="0 0 9 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0.828125 0.828125L4.5 4.5L8.17188 0.828125"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

Before

Width:  |  Height:  |  Size: 256 B

-35
View File
@@ -1,35 +0,0 @@
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.6668 13.3333V14.6667H10.0002V15.3333H2.00016V14.6667H1.3335V3.99999H2.00016V3.33333H4.00016V13.3333H10.6668Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M10.6665 4.66667V0.666672H5.33317V1.33334H4.6665V12H5.33317V12.6667H13.9998V12H14.6665V4.66667H10.6665ZM13.3332 11.3333H5.99984V2.00001H9.33317V6.00001H13.3332V11.3333Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M14.6668 3.33334V4H11.3335V0.666672H12.0002V1.33334H12.6668V2.00001H13.3335V2.66667H14.0002V3.33334H14.6668Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
</svg>

Before

Width:  |  Height:  |  Size: 967 B

-135
View File
@@ -1,135 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
>
<g clip-path="url(#clip0_8428_65000)">
<rect
y="3"
width="3"
height="3"
transform="rotate(-90 0 3)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
y="15"
width="3"
height="3"
transform="rotate(-90 0 15)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="12"
y="3"
width="3"
height="3"
transform="rotate(-90 12 3)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="9"
y="12"
width="3"
height="3"
transform="rotate(-90 9 12)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="12"
y="15"
width="3"
height="3"
transform="rotate(-90 12 15)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="3"
y="6"
width="3"
height="3"
transform="rotate(-90 3 6)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="3"
y="12"
width="3"
height="3"
transform="rotate(-90 3 12)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="9"
y="6"
width="3"
height="3"
transform="rotate(-90 9 6)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
x="6"
y="9"
width="3"
height="3"
transform="rotate(-90 6 9)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
</g>
<defs>
<clipPath id="clip0_8428_65000">
<rect
width="15"
height="15"
fill="white"
style="fill: white; fill-opacity: 1"
/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.8343 11.2552C23.7199 14.0472 24.6511 17.1964 24.303 20.8219C24.3015 20.8372 24.2936 20.8513 24.2811 20.8606C22.8532 21.9165 21.4697 22.5573 20.1057 22.9823C20.0951 22.9855 20.0837 22.9853 20.0732 22.9817C20.0627 22.9782 20.0535 22.9714 20.047 22.9623C19.7319 22.5207 19.4456 22.0552 19.1947 21.5663C19.1803 21.5375 19.1935 21.5028 19.2231 21.4915C19.6779 21.3189 20.1103 21.1121 20.5262 20.8673C20.559 20.8479 20.5611 20.8007 20.5308 20.778C20.4425 20.712 20.3551 20.6426 20.2714 20.5733C20.2557 20.5604 20.2347 20.5579 20.2169 20.5665C17.5166 21.8223 14.5586 21.8223 11.8263 20.5665C11.8086 20.5585 11.7875 20.5613 11.7723 20.5739C11.6888 20.6432 11.6011 20.712 11.5137 20.778C11.4834 20.8007 11.4859 20.8479 11.5189 20.8673C11.9349 21.1075 12.3673 21.3189 12.8214 21.4923C12.8508 21.5037 12.8648 21.5375 12.8502 21.5663C12.6048 22.0558 12.3184 22.5213 11.9975 22.9629C11.9835 22.9808 11.9605 22.989 11.9388 22.9823C10.5813 22.5573 9.19781 21.9165 7.76992 20.8606C7.75802 20.8513 7.74947 20.8366 7.74822 20.8213C7.45729 17.6853 8.0502 14.51 10.2146 11.2546C10.2198 11.246 10.2277 11.2393 10.2369 11.2353C11.3019 10.743 12.4428 10.3809 13.6353 10.1741C13.657 10.1707 13.6787 10.1808 13.69 10.2002C13.8373 10.4629 14.0057 10.7998 14.1197 11.0751C15.3767 10.8818 16.6532 10.8818 17.9365 11.0751C18.0505 10.8057 18.213 10.4629 18.3597 10.2002C18.365 10.1906 18.3731 10.1829 18.3829 10.1782C18.3927 10.1735 18.4037 10.1721 18.4144 10.1741C19.6075 10.3815 20.7485 10.7437 21.8126 11.2353C21.822 11.2393 21.8297 11.246 21.8343 11.2552V11.2552ZM14.7587 17.2178C14.7719 16.2908 14.1007 15.5236 13.2582 15.5236C12.4226 15.5236 11.7579 16.284 11.7579 17.2178C11.7579 18.1514 12.4357 18.9118 13.2582 18.9118C14.094 18.9118 14.7587 18.1514 14.7587 17.2178V17.2178ZM20.3062 17.2178C20.3194 16.2908 19.6482 15.5236 18.8059 15.5236C17.9701 15.5236 17.3054 16.284 17.3054 17.2178C17.3054 18.1514 17.9833 18.9118 18.8059 18.9118C19.6482 18.9118 20.3062 18.1514 20.3062 17.2178V17.2178Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

-10
View File
@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<g clip-path="url(#clip0_6568_5882)">
<path d="M4 8H8V9H4V8ZM4 6H8V7H4V6ZM7 1H3C2.45 1 2 1.45 2 2V10C2 10.55 2.445 11 2.995 11H9C9.55 11 10 10.55 10 10V4L7 1ZM9 10H3V2H6.5V4.5H9V10Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
</g>
<defs>
<clipPath id="clip0_6568_5882">
<rect width="12" height="12" fill="white" style="fill:white;fill-opacity:1;"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 526 B

-4
View File
@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M2.5 5H2V4H3V4.5H3.5V5H4V5.5H4.5V6H5V6.5H5.5V0.5H6.5V6.5H7V6H7.5V5.5H8V5H8.5V4.5H9V4H10V5H9.5V5.5H9V6H8.5V6.5H8V7H7.5V7.5H7V8H6.5V8.5H5.5V8H5V7.5H4.5V7H4V6.5H3.5V6H3V5.5H2.5V5Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
<path d="M11 10.5H1V11.5H11V10.5Z" fill="#242B2D" style="fill:#242B2D;fill:color(display-p3 0.1412 0.1686 0.1765);fill-opacity:1;"/>
</svg>

Before

Width:  |  Height:  |  Size: 520 B

-22
View File
@@ -1,22 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="25"
viewBox="0 0 24 25"
fill="none"
>
<circle cx="12" cy="12.5" r="10" fill="url(#paint0_angular_2549_7570)" />
<defs>
<radialGradient
id="paint0_angular_2549_7570"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(12 12.5) rotate(90) scale(12)"
>
<stop stopColor="#22D27E" />
<stop offset="1" stopColor="#9002FF" />
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 515 B

@@ -1,3 +0,0 @@
<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M63 0L56 -2.44784e-06L56 7L63 7L70 7H77V14V21L77 28L84 28V21V14C84 6.26801 77.732 0 70 0H63ZM7 14L7 7H14H21L28 7L28 2.14186e-06L21 0H14C6.26801 0 0 6.26801 0 14V21L-3.87835e-06 28L7 28L7 21V14ZM84 70C84 77.732 77.732 84 70 84H63H56L56 77H63H70H77V70L77 63L77 56L84 56V63V70ZM21 77H14L14 70L21 70L21 63H28L28 56H35L35 63H42H49L49 56H56L56 49L63 49L63 42V35L56 35V28L49 28L49 21L42 21H35L35 28L28 28L28 35H21L21 42V49L28 49L28 56H21L21 63L14 63L14 70H7L7 77L7 70L7 63L7 56L0 56L-3.87835e-06 63L0 70C0 77.732 6.26801 84 14 84H21H28L28 77H21ZM28 49L28 42L28 35H35L35 28H42L49 28L49 35L56 35V42L56 49H49V56L42 56H35V49H28Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
</svg>

Before

Width:  |  Height:  |  Size: 869 B

-79
View File
@@ -1,79 +0,0 @@
<svg
width="84"
height="84"
viewBox="0 0 84 84"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
width="7"
height="56"
transform="matrix(-2.36041e-07 1 1 7.28523e-08 28 77)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="7"
height="56"
transform="matrix(1 0 -1.63189e-07 -1 0 56)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M63 0L63 21L84 21L84 28L63 28C59.134 28 56 24.866 56 21L56 0H63Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="7"
height="42"
transform="matrix(1 0 -1.63189e-07 -1 28 42)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<rect
width="7"
height="35"
transform="matrix(-2.36041e-07 1 1 7.28523e-08 49 49)"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M28 84L28 77L7 77L7 56L-1.89145e-06 56L-2.80939e-06 77C-2.97838e-06 80.866 3.134 84 7 84L28 84Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
<path
d="M56 56L56 49L35 49L35 28L28 28L28 49C28 52.866 31.134 56 35 56L56 56Z"
fill="#242B2D"
style="
fill: #242b2d;
fill: color(display-p3 0.1412 0.1686 0.1765);
fill-opacity: 1;
"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9408 7.86426C10.9716 7.86426 6.94678 11.8731 6.94678 16.8225C6.94678 20.7866 9.52132 24.1347 13.0965 25.3217C13.5462 25.4001 13.7148 25.1313 13.7148 24.8962C13.7148 24.6834 13.7035 23.9779 13.7035 23.2277C11.4438 23.642 10.8592 22.679 10.6793 22.1751C10.5781 21.9175 10.1397 21.1225 9.75741 20.9097C9.44262 20.7418 8.99292 20.3274 9.74617 20.3162C10.4545 20.3051 10.9604 20.9657 11.129 21.2345C11.9385 22.5894 13.2314 22.2087 13.7485 21.9735C13.8272 21.3912 14.0633 20.9993 14.3219 20.7754C12.3207 20.5514 10.2296 19.7788 10.2296 16.3522C10.2296 15.378 10.5781 14.5718 11.1515 13.9447C11.0616 13.7207 10.7468 12.8025 11.2414 11.5707C11.2414 11.5707 11.9947 11.3356 13.7148 12.489C14.4343 12.2874 15.1988 12.1866 15.9633 12.1866C16.7278 12.1866 17.4923 12.2874 18.2118 12.489C19.9319 11.3244 20.6852 11.5707 20.6852 11.5707C21.1798 12.8025 20.8651 13.7207 20.7751 13.9447C21.3485 14.5718 21.697 15.3668 21.697 16.3522C21.697 19.79 19.5946 20.5514 17.5935 20.7754C17.9195 21.0553 18.2006 21.5928 18.2006 22.4326C18.2006 23.6308 18.1893 24.5938 18.1893 24.8962C18.1893 25.1313 18.358 25.4113 18.8077 25.3217C22.3603 24.1347 24.9349 20.7754 24.9349 16.8225C24.9349 11.8731 20.91 7.86426 15.9408 7.86426Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-14
View File
@@ -1,14 +0,0 @@
<svg viewBox="0 0 89 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0 2.73999C0 1.50288 1.00579 0.5 2.2465 0.5H10.4256C11.8792 0.5 13.1513 1.47412 13.5263 2.87439L18.7506 22.3815C18.8474 22.7432 19.3816 22.6733 19.3816 22.299V0.5H25.8001V22.2599C25.8001 23.497 24.7943 24.4999 23.5536 24.4999H15.314C13.8643 24.4999 12.5946 23.5308 12.216 22.1355L7.04928 3.0892C6.95141 2.72844 6.41855 2.79902 6.41855 3.17275V24.4999H0V2.73999Z"
fill="currentColor"
/>
<path
d="M55.5159 0.500025C54.2752 0.500025 53.2694 1.5029 53.2694 2.74002V24.4999H59.6879V3.18233C59.6879 2.79548 60.2483 2.74066 60.3237 3.12013L64.0601 21.9219C64.3579 23.4203 65.6762 24.4999 67.2082 24.4999L74.6942 24.4999C76.2294 24.4999 77.5496 23.4158 77.8439 21.9135L81.5171 3.16662C81.5916 2.78643 82.153 2.84061 82.153 3.22798V24.4999H88.5714V2.74002C88.5714 1.5029 87.5656 0.500025 86.3249 0.500025L78.3813 0.50002C76.859 0.500019 75.5461 1.56646 75.2383 3.05306L71.2361 22.3844C71.1655 22.7251 70.6773 22.7246 70.6074 22.3838L66.6405 3.05837C66.3349 1.56926 65.0208 0.500019 63.4964 0.50002L55.5159 0.500025Z"
fill="currentColor"
/>
<path
d="M26.5569 0.50009H33.3531L39.2253 13.0169C39.4563 13.5093 40.1589 13.5085 40.3888 13.0155L46.2237 0.50009H53.1458L41.8949 24.5H34.9858L39.4713 14.9H35.3564C34.1107 14.9 32.9775 14.1813 32.4496 13.0563L26.5569 0.50009Z"
fill="currentColor"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1,3 +0,0 @@
<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M63 0H56V7H63H70H77V14V21V28H84V21V14C84 6.26801 77.732 0 70 0H63ZM7 77H14H21H28V84H21H14C6.26801 84 0 77.732 0 70V63V56H7L7 63L7 70L7 77ZM70 84C77.732 84 84 77.732 84 70V63V56H77V63V70V77H70H63H56V84H63H70ZM7 7L7 14L7 21L7 28H0V21V14C1.93187e-06 6.26801 6.26802 0 14 0H21H28V7L21 7L14 7L7 7ZM63 21L63 28L56 28L56 21L63 21ZM63 21V14L70 14L70 21L63 21ZM49 35V28L56 28V35H49ZM49 49V42L49 35L42 35L35 35L35 28L28 28L28 21L21 21L21 14L14 14L14 21L21 21L21 28L28 28V35L35 35V42V49L28 49L28 56L21 56L21 63H14L14 70H21L21 63L28 63L28 56H35V49H42L49 49ZM56 56H49L49 49L56 49V56ZM63 63L56 63V56L63 56L63 63ZM63 63H70V70H63L63 63Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
</svg>

Before

Width:  |  Height:  |  Size: 872 B

-3
View File
@@ -1,3 +0,0 @@
<svg width="84" height="84" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M84 14C84 6.26801 77.732 0 70 0H63H56V7H63H70H77V14V21V28H84V21V14ZM28 14C20.268 14 14 20.268 14 28C14 35.732 20.268 42 28 42C20.268 42 14 48.268 14 56C14 63.732 20.268 70 28 70C35.7299 70 41.9966 63.7354 42 56.0062C42.0034 63.7353 48.2701 70 56 70C63.732 70 70 63.732 70 56C70 48.2701 63.7353 42.0034 56.0062 42C63.7353 41.9966 70 35.7299 70 28C70 20.268 63.732 14 56 14C48.268 14 42 20.268 42 28C42 20.268 35.732 14 28 14ZM49 28V35L56 35H63V28V21L56 21H49V28ZM42 28.0062C41.9966 35.7329 35.7339 41.996 28.0074 42C35.736 42.004 42 48.2705 42 56C42 48.268 48.268 42 56 42C48.2701 42 42.0034 35.7353 42 28.0062ZM56 63H63V56V49L56 49H49V56V63L56 63ZM28 35H35V28V21L28 21H21V28L21 35L28 35ZM21 49V56L21 63L28 63H35V56V49L28 49H21ZM7 77H14H21H28V84H21H14C6.26801 84 0 77.732 0 70V63V56H7L7 63L7 70L7 77ZM70 84C77.732 84 84 77.732 84 70V63V56H77V63V70V77H70H63H56V84H63H70ZM7 7L7 14L7 21L7 28H0V21V14C1.93187e-06 6.26801 6.26802 0 14 0H21H28V7L21 7L14 7L7 7Z" fill="#14E76F" style="fill:#14E76F;fill:color(display-p3 0.0784 0.9059 0.4353);fill-opacity:1;"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.90246 15.9332C8.90246 15.9332 15.4128 13.1912 17.6706 12.2256C18.5362 11.8394 21.4715 10.6036 21.4715 10.6036C21.4715 10.6036 22.8262 10.0629 22.7133 11.376C22.6757 11.9167 22.3746 13.8091 22.0736 15.8559C21.622 18.7525 21.1328 21.9194 21.1328 21.9194C21.1328 21.9194 21.0575 22.8077 20.4178 22.9621C19.7781 23.1166 18.7243 22.4215 18.5362 22.267C18.3856 22.1511 15.7138 20.4132 14.7354 19.5635C14.4719 19.3318 14.1709 18.8684 14.773 18.3277C16.1278 17.0532 17.7459 15.4698 18.7243 14.4656C19.1759 14.0022 19.6275 12.9208 17.7459 14.2339C15.0741 16.1263 12.4398 17.9029 12.4398 17.9029C12.4398 17.9029 11.8377 18.289 10.7088 17.9414C9.57979 17.5939 8.26268 17.1304 8.26268 17.1304C8.26268 17.1304 7.35957 16.5511 8.90246 15.9332Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 845 B

-23
View File
@@ -1,23 +0,0 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="25"
viewBox="0 0 24 25"
fill="none"
>
<g clipPath="url(#clip0_2549_7563)">
<path
d="M20.4841 4.01607C15.8041 -0.67593 8.19607 -0.67593 3.51607 4.01607C-1.17593 8.70807 -1.17593 16.3041 3.51607 20.9841C8.20807 25.6761 15.8041 25.6761 20.4841 20.9841C25.1761 16.3041 25.1761 8.69607 20.4841 4.01607ZM19.4521 19.9521C15.3361 24.0681 8.65207 24.0681 4.53607 19.9521C0.42007 15.8361 0.42007 9.15207 4.53607 5.03607C8.65207 0.92007 15.3361 0.92007 19.4521 5.03607C23.5801 9.16407 23.5801 15.8361 19.4521 19.9521Z"
fill="black"
/>
<path
d="M18.48 19.4965V5.50447C17.868 4.92847 17.184 4.42447 16.452 4.02847V17.4085L7.62002 3.98047C6.85202 4.38847 6.14402 4.89247 5.52002 5.49247V19.4965C6.13202 20.0725 6.81602 20.5765 7.54802 20.9725V7.59247L16.38 21.0205C17.148 20.6125 17.856 20.0965 18.48 19.4965Z"
fill="black"
/>
</g>
<defs>
<clipPath id="clip0_2549_7563">
<rect width="24" height="24" fill="white" transform="translate(0 0.5)" />
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

-4
View File
@@ -1,4 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.4206 15.4955L22.9798 9.03333H21.6625L16.8354 14.6444L12.98 9.03333H8.5332L14.3633 17.5182L8.5332 24.2948H9.85065L14.9482 18.3694L19.0198 24.2948H23.4665L17.4202 15.4955H17.4206ZM15.6161 17.593L15.0254 16.7481L10.3253 10.0251H12.3489L16.1419 15.4507L16.7326 16.2956L21.6631 23.3482H19.6396L15.6161 17.5933V17.593Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 453 B

-5
View File
@@ -1,5 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.9004 12.0986C24.6915 11.3132 24.0734 10.6936 23.2871 10.4812C21.8652 10.1001 16.1605 10.1001 16.1605 10.1001C16.1605 10.1001 10.4587 10.1001 9.03399 10.4812C8.25053 10.6906 7.63247 11.3103 7.42065 12.0986C7.04053 13.5241 7.04053 16.5001 7.04053 16.5001C7.04053 16.5001 7.04053 19.4761 7.42065 20.9016C7.62957 21.687 8.24763 22.3066 9.03399 22.519C10.4587 22.9001 16.1605 22.9001 16.1605 22.9001C16.1605 22.9001 21.8652 22.9001 23.2871 22.519C24.0705 22.3096 24.6886 21.6899 24.9004 20.9016C25.2805 19.4761 25.2805 16.5001 25.2805 16.5001C25.2805 16.5001 25.2805 13.5241 24.9004 12.0986Z" fill="currentColor"/>
<path d="M14.3383 19.2434L19.0767 16.5001L14.3383 13.7568V19.2434Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 810 B

@@ -1,4 +0,0 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.9004 12.0986C24.6915 11.3132 24.0734 10.6936 23.2871 10.4812C21.8652 10.1001 16.1605 10.1001 16.1605 10.1001C16.1605 10.1001 10.4587 10.1001 9.03399 10.4812C8.25053 10.6906 7.63247 11.3103 7.42065 12.0986C7.04053 13.5241 7.04053 16.5001 7.04053 16.5001C7.04053 16.5001 7.04053 19.4761 7.42065 20.9016C7.62957 21.687 8.24763 22.3066 9.03399 22.519C10.4587 22.9001 16.1605 22.9001 16.1605 22.9001C16.1605 22.9001 21.8652 22.9001 23.2871 22.519C24.0705 22.3096 24.6886 21.6899 24.9004 20.9016C25.2805 19.4761 25.2805 16.5001 25.2805 16.5001C25.2805 16.5001 25.2805 13.5241 24.9004 12.0986Z" fill="currentColor"/>
<path d="M14.3383 19.2434L19.0767 16.5001L14.3383 13.7568V19.2434Z" fill="#242B2D"/>
</svg>

Before

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

-1
View File
@@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 128 B

-1
View File
@@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

Before

Width:  |  Height:  |  Size: 385 B

Some files were not shown because too many files have changed in this diff Show More