Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a5c760d8ff |
@@ -5,6 +5,7 @@ on:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'nym-api/**'
|
||||
@@ -38,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ arc-ubuntu-22.04, custom-windows-11, custom-macos-15 ]
|
||||
os: [ arc-ubuntu-22.04, custom-windows-11, custom-runner-mac-m1 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
@@ -44,10 +44,8 @@ jobs:
|
||||
echo "Tag is empty"
|
||||
exit 1
|
||||
fi
|
||||
# first, list all tags for logging purposes
|
||||
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
|
||||
# check if there's a matching tag
|
||||
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq -r --arg tag "$TAG" 'any(.tags[]; . == $tag)' )
|
||||
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
|
||||
@@ -55,5 +53,5 @@ jobs:
|
||||
echo "Version '$TAG' doesn't exist on the remote"
|
||||
else
|
||||
echo "Unknown output '$exists'"
|
||||
exit 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -44,10 +44,8 @@ jobs:
|
||||
echo "Tag is empty"
|
||||
exit 1
|
||||
fi
|
||||
# first, list all tags for logging purposes
|
||||
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
|
||||
# check if there's a matching tag
|
||||
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq -r --arg tag "$TAG" 'any(.tags[]; . == $tag)' )
|
||||
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
|
||||
@@ -55,5 +53,5 @@ jobs:
|
||||
echo "Version '$TAG' doesn't exist on the remote"
|
||||
else
|
||||
echo "Unknown output '$exists'"
|
||||
exit 2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -57,7 +57,6 @@ jobs:
|
||||
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_ecash.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_pool_contract.wasm $OUTPUT_DIR
|
||||
cp contracts/target/wasm32-unknown-unknown/release/nym_performance_contract.wasm $OUTPUT_DIR
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -19,11 +19,7 @@ jobs:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: arc-ubuntu-22.04
|
||||
target: x86_64-unknown-linux-gnu
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: arc-ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
@@ -70,6 +66,7 @@ jobs:
|
||||
with:
|
||||
name: my-artifact
|
||||
path: |
|
||||
target/release/explorer-api
|
||||
target/release/nym-client
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-api
|
||||
@@ -78,13 +75,14 @@ jobs:
|
||||
target/release/nymvisor
|
||||
target/release/nym-node
|
||||
retention-days: 30
|
||||
|
||||
|
||||
- id: create-release
|
||||
name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
target/release/explorer-api
|
||||
target/release/nym-client
|
||||
target/release/nym-socks5-client
|
||||
target/release/nym-api
|
||||
|
||||
@@ -40,6 +40,7 @@ validator-config
|
||||
validator-api-config.toml
|
||||
dist
|
||||
storybook-static
|
||||
envs/qwerty.env
|
||||
.parcel-cache
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
|
||||
@@ -4,30 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.11-cheddar] (2025-06-10)
|
||||
|
||||
- No autoremoval of peers ([#5831])
|
||||
- Set cached storage counters to 0 ([#5812])
|
||||
- hack: temporarily use next.config.js instead of next.config.ts ([#5805])
|
||||
- chore: resolve 1.87 clippy warnings ([#5802])
|
||||
- Nym Statistics API ([#5800])
|
||||
- QoL: RequestPath trait for http-api-client ([#5788])
|
||||
- Fix contains ticketbook function that always returned true ([#5787])
|
||||
- swap a decode into a fromrow to please future postgres feature ([#5785])
|
||||
- Make address cache configurable ([#5784])
|
||||
- Track wireguard credential retries ([#5783])
|
||||
|
||||
[#5831]: https://github.com/nymtech/nym/pull/5831
|
||||
[#5812]: https://github.com/nymtech/nym/pull/5812
|
||||
[#5805]: https://github.com/nymtech/nym/pull/5805
|
||||
[#5802]: https://github.com/nymtech/nym/pull/5802
|
||||
[#5800]: https://github.com/nymtech/nym/pull/5800
|
||||
[#5788]: https://github.com/nymtech/nym/pull/5788
|
||||
[#5787]: https://github.com/nymtech/nym/pull/5787
|
||||
[#5785]: https://github.com/nymtech/nym/pull/5785
|
||||
[#5784]: https://github.com/nymtech/nym/pull/5784
|
||||
[#5783]: https://github.com/nymtech/nym/pull/5783
|
||||
|
||||
## [2025.10-brie] (2025-05-27)
|
||||
|
||||
- Backport PR 5779 ([#5801])
|
||||
|
||||
Generated
+259
-703
File diff suppressed because it is too large
Load Diff
+6
-5
@@ -34,12 +34,11 @@ members = [
|
||||
"common/config",
|
||||
"common/cosmwasm-smart-contracts/coconut-dkg",
|
||||
"common/cosmwasm-smart-contracts/contracts-common",
|
||||
"common/cosmwasm-smart-contracts/contracts-common-testing",
|
||||
"common/cosmwasm-smart-contracts/easy_addr",
|
||||
"common/cosmwasm-smart-contracts/ecash-contract",
|
||||
"common/cosmwasm-smart-contracts/group-contract",
|
||||
"common/cosmwasm-smart-contracts/mixnet-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract", "common/cosmwasm-smart-contracts/nym-performance-contract",
|
||||
"common/cosmwasm-smart-contracts/multisig-contract",
|
||||
"common/cosmwasm-smart-contracts/nym-pool-contract",
|
||||
"common/cosmwasm-smart-contracts/vesting-contract",
|
||||
"common/credential-storage",
|
||||
@@ -102,6 +101,7 @@ members = [
|
||||
"common/wireguard-types",
|
||||
"documentation/autodoc",
|
||||
"gateway",
|
||||
"integrations/bity",
|
||||
"nym-api",
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-browser-extension/storage",
|
||||
@@ -127,7 +127,6 @@ members = [
|
||||
"service-providers/common",
|
||||
"service-providers/ip-packet-router",
|
||||
"service-providers/network-requester",
|
||||
"sqlx-pool-guard",
|
||||
"tools/echo-server",
|
||||
"tools/internal/contract-state-importer/importer-cli",
|
||||
"tools/internal/contract-state-importer/importer-contract",
|
||||
@@ -137,6 +136,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/nym-cli",
|
||||
"tools/nym-id-cli",
|
||||
@@ -288,7 +288,6 @@ petgraph = "0.6.5"
|
||||
pin-project = "1.1"
|
||||
pin-project-lite = "0.2.16"
|
||||
publicsuffix = "2.3.0"
|
||||
proc_pidinfo = "0.1.3"
|
||||
quote = "1"
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3"
|
||||
@@ -370,6 +369,9 @@ subtle = "2.5.0"
|
||||
# cosmwasm-related
|
||||
cosmwasm-schema = "=2.2.2"
|
||||
cosmwasm-std = "=2.2.2"
|
||||
# use 1.0.1 as that's the version used by cosmwasm-std 2.2.1
|
||||
# (and ideally we don't want to pull the same dependency twice)
|
||||
serde-json-wasm = "=1.0.1"
|
||||
# same version as used by cosmwasm
|
||||
cw-utils = "=2.0.0"
|
||||
cw-storage-plus = "=2.0.0"
|
||||
@@ -377,7 +379,6 @@ cw2 = { version = "=2.0.0" }
|
||||
cw3 = { version = "=2.0.0" }
|
||||
cw4 = { version = "=2.0.0" }
|
||||
cw-controllers = { version = "=2.0.0" }
|
||||
cw-multi-test = "=2.3.2"
|
||||
|
||||
# cosmrs-related
|
||||
bip32 = { version = "0.5.3", default-features = false }
|
||||
|
||||
@@ -133,7 +133,7 @@ clippy: sdk-wasm-lint
|
||||
# Build contracts ready for deploy
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CONTRACTS=vesting_contract mixnet_contract nym_ecash cw3_flex_multisig cw4_group nym_coconut_dkg nym_pool_contract nym_performance_contract
|
||||
CONTRACTS=vesting_contract mixnet_contract nym_ecash cw3_flex_multisig cw4_group nym_coconut_dkg nym_pool_contract
|
||||
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
|
||||
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.57"
|
||||
version = "1.1.56"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -318,7 +318,7 @@ impl Handler {
|
||||
|
||||
async fn handle_text_message(&mut self, msg: String) -> Option<WsMessage> {
|
||||
debug!("Handling text message request");
|
||||
trace!("Content: {msg:?}");
|
||||
trace!("Content: {:?}", msg);
|
||||
|
||||
self.received_response_type = ReceivedResponseType::Text;
|
||||
let client_request = ClientRequest::try_from_text(msg);
|
||||
|
||||
@@ -68,9 +68,9 @@ impl Listener {
|
||||
new_conn = tcp_listener.accept() => {
|
||||
match new_conn {
|
||||
Ok((mut socket, remote_addr)) => {
|
||||
debug!("Received connection from {remote_addr:?}");
|
||||
debug!("Received connection from {:?}", remote_addr);
|
||||
if self.state.is_connected() {
|
||||
warn!("Tried to open a duplicate websocket connection. The request came from {remote_addr}");
|
||||
warn!("Tried to open a duplicate websocket connection. The request came from {}", remote_addr);
|
||||
// if we've already got a connection, don't allow another one
|
||||
// while we only ever want to accept a single connection, we don't want
|
||||
// to leave clients hanging (and also allow for reconnection if it somehow
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.57"
|
||||
version = "1.1.56"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -137,7 +137,7 @@ impl AsyncFileWatcher {
|
||||
log::error!("the file watcher receiver has been dropped!");
|
||||
}
|
||||
} else {
|
||||
log::debug!("will not propagate information about {event:?}");
|
||||
log::debug!("will not propagate information about {:?}", event);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
@@ -11,7 +11,7 @@ impl std::fmt::Display for BandwidthStatusMessage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
BandwidthStatusMessage::RemainingBandwidth(b) => {
|
||||
write!(f, "remaining bandwidth: {b}")
|
||||
write!(f, "remaining bandwidth: {}", b)
|
||||
}
|
||||
BandwidthStatusMessage::NoBandwidth => write!(f, "no bandwidth left"),
|
||||
}
|
||||
|
||||
@@ -418,9 +418,6 @@ pub struct Traffic {
|
||||
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
|
||||
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
|
||||
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
|
||||
///
|
||||
/// This overrides the `use_legacy_sphinx_format` setting as reduced mix hops
|
||||
/// requires use of the updated SURB packet format.
|
||||
pub disable_mix_hops: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::BadGateway;
|
||||
use std::{io, path::PathBuf};
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -18,6 +19,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("failed to perform sqlx migration: {source}")]
|
||||
MigrationError {
|
||||
#[source]
|
||||
#[from]
|
||||
source: sqlx::migrate::MigrateError,
|
||||
},
|
||||
@@ -30,6 +32,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("failed to run the SQL query: {source}")]
|
||||
QueryError {
|
||||
#[source]
|
||||
#[from]
|
||||
source: sqlx::error::Error,
|
||||
},
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
client::replies::reply_storage::{fs_backend, CombinedReplyStorage, ReplyStorageBackend},
|
||||
config,
|
||||
config::Config,
|
||||
error::ClientCoreError,
|
||||
use crate::client::replies::reply_storage::{
|
||||
fs_backend, CombinedReplyStorage, ReplyStorageBackend,
|
||||
};
|
||||
use crate::config;
|
||||
use crate::config::Config;
|
||||
use crate::error::ClientCoreError;
|
||||
use log::{error, info, trace};
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_client_core_gateways_storage::OnDiskGatewaysDetails;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_validator_client::{nyxd, QueryHttpRpcNyxdClient};
|
||||
use std::{io, path::Path};
|
||||
use nym_validator_client::nyxd;
|
||||
use nym_validator_client::QueryHttpRpcNyxdClient;
|
||||
use std::path::Path;
|
||||
use std::{fs, io};
|
||||
use time::OffsetDateTime;
|
||||
use url::Url;
|
||||
|
||||
@@ -20,11 +22,11 @@ async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
db_path: P,
|
||||
surb_config: &config::ReplySurbs,
|
||||
) -> Result<fs_backend::Backend, ClientCoreError> {
|
||||
info!("Creating fresh surb database");
|
||||
info!("creating fresh surb database");
|
||||
let mut storage_backend = match fs_backend::Backend::init(db_path).await {
|
||||
Ok(backend) => backend,
|
||||
Err(err) => {
|
||||
error!("setup_fresh_backend: Failed to setup persistent storage backend for our reply needs: {err}");
|
||||
error!("failed to setup persistent storage backend for our reply needs: {err}");
|
||||
return Err(ClientCoreError::SurbStorageError {
|
||||
source: Box::new(err),
|
||||
});
|
||||
@@ -38,15 +40,14 @@ async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
surb_config.minimum_reply_surb_storage_threshold,
|
||||
surb_config.maximum_reply_surb_storage_threshold,
|
||||
);
|
||||
match storage_backend.init_fresh(&mem_store).await {
|
||||
Ok(()) => Ok(storage_backend),
|
||||
Err(err) => {
|
||||
storage_backend.shutdown().await;
|
||||
Err(ClientCoreError::SurbStorageError {
|
||||
source: Box::new(err),
|
||||
})
|
||||
}
|
||||
}
|
||||
storage_backend
|
||||
.init_fresh(&mem_store)
|
||||
.await
|
||||
.map_err(|err| ClientCoreError::SurbStorageError {
|
||||
source: Box::new(err),
|
||||
})?;
|
||||
|
||||
Ok(storage_backend)
|
||||
}
|
||||
|
||||
// fn setup_inactive_backend(surb_config: &config::ReplySurbs) -> fs_backend::Backend {
|
||||
@@ -57,11 +58,12 @@ async fn setup_fresh_backend<P: AsRef<Path>>(
|
||||
// )
|
||||
// }
|
||||
|
||||
async fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
|
||||
fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
|
||||
let db_path = db_path.as_ref();
|
||||
debug_assert!(db_path.exists());
|
||||
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
|
||||
let suffix = format!("_{now}.corrupted");
|
||||
|
||||
let new_extension =
|
||||
@@ -70,15 +72,11 @@ async fn archive_corrupted_database<P: AsRef<Path>>(db_path: P) -> io::Result<()
|
||||
} else {
|
||||
suffix
|
||||
};
|
||||
let renamed = db_path.with_extension(new_extension);
|
||||
|
||||
tokio::fs::rename(db_path, &renamed).await.inspect_err(|_| {
|
||||
error!(
|
||||
"Failed to rename corrupt database file: {} to {}",
|
||||
db_path.display(),
|
||||
renamed.display()
|
||||
);
|
||||
})
|
||||
let mut renamed = db_path.to_owned();
|
||||
renamed.set_extension(new_extension);
|
||||
|
||||
fs::rename(db_path, renamed)
|
||||
}
|
||||
|
||||
pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
@@ -89,12 +87,13 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
|
||||
// the existing one
|
||||
let db_path = db_path.as_ref();
|
||||
if db_path.exists() {
|
||||
info!("Loading existing surb database");
|
||||
info!("loading existing surb database");
|
||||
match fs_backend::Backend::try_load(db_path, surb_config.fresh_sender_tags).await {
|
||||
Ok(backend) => Ok(backend),
|
||||
Err(err) => {
|
||||
error!("setup_fs_reply_surb_backend: 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");
|
||||
archive_corrupted_database(db_path).await?;
|
||||
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");
|
||||
|
||||
archive_corrupted_database(db_path)?;
|
||||
setup_fresh_backend(db_path, surb_config).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ impl MixTrafficController {
|
||||
Some(client_request) => {
|
||||
match self.gateway_transceiver.send_client_request(client_request).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => error!("Failed to send client request: {e}"),
|
||||
Err(e) => error!("Failed to send client request: {}", e),
|
||||
};
|
||||
},
|
||||
None => {
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ impl AcknowledgementListener {
|
||||
return;
|
||||
}
|
||||
|
||||
trace!("Received {frag_id} from the mix network");
|
||||
trace!("Received {} from the mix network", frag_id);
|
||||
self.stats_tx
|
||||
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into());
|
||||
if let Err(err) = self
|
||||
|
||||
+19
-7
@@ -126,7 +126,7 @@ impl ActionController {
|
||||
fn handle_insert(&mut self, pending_acks: Vec<PendingAcknowledgement>) {
|
||||
for pending_ack in pending_acks {
|
||||
let frag_id = pending_ack.message_chunk.fragment_identifier();
|
||||
trace!("{frag_id} is inserted");
|
||||
trace!("{} is inserted", frag_id);
|
||||
|
||||
if self
|
||||
.pending_acks_data
|
||||
@@ -161,16 +161,22 @@ impl ActionController {
|
||||
let new_queue_key = self.pending_acks_timers.insert(frag_id, timeout);
|
||||
*queue_key = Some(new_queue_key)
|
||||
} else {
|
||||
debug!("Tried to START TIMER on pending ack that is already gone! - {frag_id}");
|
||||
debug!(
|
||||
"Tried to START TIMER on pending ack that is already gone! - {}",
|
||||
frag_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_remove(&mut self, frag_id: FragmentIdentifier) {
|
||||
trace!("{frag_id} is getting removed");
|
||||
trace!("{} is getting removed", frag_id);
|
||||
|
||||
match self.pending_acks_data.remove(&frag_id) {
|
||||
None => {
|
||||
debug!("Tried to REMOVE pending ack that is already gone! - {frag_id}");
|
||||
debug!(
|
||||
"Tried to REMOVE pending ack that is already gone! - {}",
|
||||
frag_id
|
||||
);
|
||||
}
|
||||
Some((_, queue_key)) => {
|
||||
if let Some(queue_key) = queue_key {
|
||||
@@ -182,7 +188,10 @@ impl ActionController {
|
||||
} else {
|
||||
// I'm not 100% sure if having a `None` key is even possible here
|
||||
// (REMOVE would have to be called before START TIMER),
|
||||
debug!("Tried to REMOVE pending ack without TIMER active - {frag_id}");
|
||||
debug!(
|
||||
"Tried to REMOVE pending ack without TIMER active - {}",
|
||||
frag_id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +200,7 @@ impl ActionController {
|
||||
// initiated basically as a first step of retransmission. At first data has its delay updated
|
||||
// (as new sphinx packet was created with new expected delivery time)
|
||||
fn handle_update_pending_ack(&mut self, frag_id: FragmentIdentifier, delay: SphinxDelay) {
|
||||
trace!("{frag_id} is updating its delay");
|
||||
trace!("{} is updating its delay", frag_id);
|
||||
// TODO: is it possible to solve this without either locking or temporarily removing the value?
|
||||
if let Some((pending_ack_data, queue_key)) = self.pending_acks_data.remove(&frag_id) {
|
||||
// this Action is triggered by `RetransmissionRequestListener` (for 'normal' packets)
|
||||
@@ -204,7 +213,10 @@ impl ActionController {
|
||||
self.pending_acks_data
|
||||
.insert(frag_id, (Arc::new(inner_data), queue_key));
|
||||
} else {
|
||||
debug!("Tried to UPDATE TIMER on pending ack that is already gone! - {frag_id}");
|
||||
debug!(
|
||||
"Tried to UPDATE TIMER on pending ack that is already gone! - {}",
|
||||
frag_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,9 +105,6 @@ pub(crate) struct Config {
|
||||
/// will be routed as usual, to the entry gateway, through three mix nodes, egressing
|
||||
/// through the exit gateway. If mix hops are disabled, traffic will be routed directly
|
||||
/// from the entry gateway to the exit gateway, bypassing the mix nodes.
|
||||
///
|
||||
/// This overrides the `use_legacy_sphinx_format` setting as reduced mix hops
|
||||
/// requires use of the updated SURB packet format.
|
||||
disable_mix_hops: bool,
|
||||
|
||||
/// Average delay a data packet is going to get delay at a single mixnode.
|
||||
@@ -162,12 +159,8 @@ impl Config {
|
||||
}
|
||||
|
||||
/// Configure whether messages senders using this config should use mix hops or not when sending messages.
|
||||
///
|
||||
/// This overrides the `use_legacy_sphinx_format` setting as disabled mix hops
|
||||
/// requires use of the updated SURB packet format.
|
||||
pub fn disable_mix_hops(mut self, disable_mix_hops: bool) -> Self {
|
||||
self.disable_mix_hops = disable_mix_hops;
|
||||
self.use_legacy_sphinx_format = false;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ where
|
||||
// well technically the message was not sent just yet, but now it's up to internal
|
||||
// queues and client load rather than the required delay. So realistically we can treat
|
||||
// whatever is about to happen as negligible additional delay.
|
||||
trace!("{frag_id} is about to get sent to the mixnet");
|
||||
trace!("{} is about to get sent to the mixnet", frag_id);
|
||||
if let Err(err) = self.sent_notifier.unbounded_send(frag_id) {
|
||||
error!("Failed to notify about sent message: {err}");
|
||||
}
|
||||
|
||||
+3
-3
@@ -164,11 +164,11 @@ impl SendingDelayController {
|
||||
self.current_multiplier()
|
||||
);
|
||||
if self.current_multiplier() > 0 {
|
||||
log::debug!("{status_str}");
|
||||
log::debug!("{}", status_str);
|
||||
} else if self.current_multiplier() > 1 {
|
||||
log::info!("{status_str}");
|
||||
log::info!("{}", status_str);
|
||||
} else if self.current_multiplier() > 2 {
|
||||
log::warn!("{status_str}");
|
||||
log::warn!("{}", status_str);
|
||||
}
|
||||
self.time_when_logged_about_elevated_multiplier = now;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,10 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
|
||||
let stored_messages = std::mem::take(&mut guard.messages);
|
||||
if !stored_messages.is_empty() {
|
||||
if let Err(err) = sender.unbounded_send(stored_messages) {
|
||||
error!("The sender channel we just received is already invalidated - {err:?}");
|
||||
error!(
|
||||
"The sender channel we just received is already invalidated - {:?}",
|
||||
err
|
||||
);
|
||||
// put the values back to the buffer
|
||||
// the returned error has two fields: err: SendError and val: T,
|
||||
// where val is the value that was failed to get sent;
|
||||
|
||||
@@ -217,14 +217,14 @@ where
|
||||
.surbs_storage_ref()
|
||||
.contains_surbs_for(&recipient_tag)
|
||||
{
|
||||
warn!("received reply request for {recipient_tag:?} but we don't have any surbs stored for that recipient!");
|
||||
warn!("received reply request for {:?} but we don't have any surbs stored for that recipient!", recipient_tag);
|
||||
return;
|
||||
}
|
||||
|
||||
trace!("handling reply to {recipient_tag:?}");
|
||||
trace!("handling reply to {:?}", recipient_tag);
|
||||
let mut fragments = self.message_handler.split_reply_message(data);
|
||||
let total_size = fragments.len();
|
||||
trace!("This reply requires {total_size:?} SURBs");
|
||||
trace!("This reply requires {:?} SURBs", total_size);
|
||||
|
||||
let available_surbs = self
|
||||
.full_reply_storage
|
||||
@@ -327,7 +327,10 @@ where
|
||||
.await
|
||||
{
|
||||
let err = err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
|
||||
warn!("failed to request additional surbs from {target:?} - {err}");
|
||||
warn!(
|
||||
"failed to request additional surbs from {:?} - {err}",
|
||||
target
|
||||
);
|
||||
return Err(err);
|
||||
} else {
|
||||
self.full_reply_storage
|
||||
@@ -406,7 +409,10 @@ where
|
||||
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
|
||||
self.re_insert_pending_retransmission(&target, to_take);
|
||||
|
||||
warn!("failed to clear pending retransmission queue for {target:?} - {err}");
|
||||
warn!(
|
||||
"failed to clear pending retransmission queue for {:?} - {err}",
|
||||
target
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -483,7 +489,7 @@ where
|
||||
let err =
|
||||
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
|
||||
self.re_insert_pending_replies(&target, to_send);
|
||||
warn!("failed to clear pending queue for {target:?} - {err}");
|
||||
warn!("failed to clear pending queue for {:?} - {err}", target);
|
||||
}
|
||||
} else {
|
||||
trace!("the pending queue is empty");
|
||||
@@ -810,7 +816,7 @@ where
|
||||
if diff > max_drop_wait {
|
||||
to_remove.push(*pending_reply_target)
|
||||
} else {
|
||||
debug!("We haven't received any surbs in {diff:?} from {pending_reply_target}. Going to explicitly ask for more");
|
||||
debug!("We haven't received any surbs in {:?} from {pending_reply_target}. Going to explicitly ask for more", diff);
|
||||
to_request.push(*pending_reply_target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ impl StatisticsControl {
|
||||
None,
|
||||
);
|
||||
if let Err(err) = self.report_tx.send(report_message).await {
|
||||
log::error!("Failed to report client stats: {err:?}");
|
||||
log::error!("Failed to report client stats: {:?}", err);
|
||||
} else {
|
||||
self.stats.reset();
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ impl<T> TransmissionBuffer<T> {
|
||||
};
|
||||
|
||||
let msg = self.pop_front_from_lane(&lane)?;
|
||||
log::trace!("picking to send from lane: {lane:?}");
|
||||
log::trace!("picking to send from lane: {:?}", lane);
|
||||
Some((lane, msg))
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ pub async fn gateways_for_init<R: Rng>(
|
||||
let gateways = client.get_all_basic_entry_assigned_nodes_v2().await?.nodes;
|
||||
info!("nym api reports {} gateways", gateways.len());
|
||||
|
||||
log::trace!("Gateways: {gateways:#?}");
|
||||
log::trace!("Gateways: {:#?}", gateways);
|
||||
|
||||
// filter out gateways below minimum performance and ones that could operate as a mixnode
|
||||
// (we don't want instability)
|
||||
@@ -121,7 +121,7 @@ pub async fn gateways_for_init<R: Rng>(
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<_>>();
|
||||
log::debug!("After checking validity: {}", valid_gateways.len());
|
||||
log::trace!("Valid gateways: {valid_gateways:#?}");
|
||||
log::trace!("Valid gateways: {:#?}", valid_gateways);
|
||||
|
||||
log::info!(
|
||||
"and {} after validity and performance filtering",
|
||||
@@ -286,7 +286,7 @@ pub(super) fn get_specified_gateway(
|
||||
gateways: &[RoutingNode],
|
||||
must_use_tls: bool,
|
||||
) -> Result<RoutingNode, ClientCoreError> {
|
||||
log::debug!("Requesting specified gateway: {gateway_identity}");
|
||||
log::debug!("Requesting specified gateway: {}", gateway_identity);
|
||||
let user_gateway = ed25519::PublicKey::from_base58_string(gateway_identity)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
|
||||
@@ -17,26 +17,15 @@ nym-crypto = { path = "../../crypto", optional = true, default-features = false
|
||||
nym-sphinx = { path = "../../nymsphinx" }
|
||||
nym-task = { path = "../../task" }
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio]
|
||||
workspace = true
|
||||
features = ["fs"]
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
workspace = true
|
||||
features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"]
|
||||
optional = true
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx-pool-guard]
|
||||
path = "../../../sqlx-pool-guard"
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { workspace = true, features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
|
||||
|
||||
[features]
|
||||
fs-surb-storage = ["sqlx", "nym-crypto", "nym-crypto/hashing"]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::{io, path::PathBuf};
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -29,6 +30,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("failed to perform sqlx migration: {source}")]
|
||||
MigrationError {
|
||||
#[source]
|
||||
#[from]
|
||||
source: sqlx::migrate::MigrateError,
|
||||
},
|
||||
@@ -41,6 +43,7 @@ pub enum StorageError {
|
||||
|
||||
#[error("failed to run the SQL query: {source}")]
|
||||
QueryError {
|
||||
#[source]
|
||||
#[from]
|
||||
source: sqlx::error::Error,
|
||||
},
|
||||
|
||||
@@ -15,11 +15,9 @@ use sqlx::{
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
use sqlx_pool_guard::SqlitePoolGuard;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StorageManager {
|
||||
connection_pool: SqlitePoolGuard,
|
||||
pub connection_pool: sqlx::SqlitePool,
|
||||
}
|
||||
|
||||
// all SQL goes here
|
||||
@@ -39,7 +37,7 @@ impl StorageManager {
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(&database_path)
|
||||
.filename(database_path)
|
||||
.create_if_missing(fresh)
|
||||
.disable_statement_logging();
|
||||
|
||||
@@ -51,15 +49,11 @@ impl StorageManager {
|
||||
}
|
||||
};
|
||||
|
||||
let connection_pool =
|
||||
SqlitePoolGuard::new(database_path.as_ref().to_path_buf(), connection_pool);
|
||||
|
||||
if let Err(err) = sqlx::migrate!("./fs_surbs_migrations")
|
||||
.run(&*connection_pool)
|
||||
.run(&connection_pool)
|
||||
.await
|
||||
{
|
||||
error!("Failed to initialize SQLx database: {err}");
|
||||
connection_pool.close().await;
|
||||
return Err(err.into());
|
||||
}
|
||||
|
||||
@@ -67,43 +61,38 @@ impl StorageManager {
|
||||
Ok(StorageManager { connection_pool })
|
||||
}
|
||||
|
||||
/// Close connection pool waiting for all connections to be closed.
|
||||
pub async fn close_pool(&self) {
|
||||
self.connection_pool.close().await;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn status_table_exists(&self) -> Result<bool, sqlx::Error> {
|
||||
sqlx::query!("SELECT name FROM sqlite_master WHERE type='table' AND name='status'")
|
||||
.fetch_optional(&*self.connection_pool)
|
||||
.fetch_optional(&self.connection_pool)
|
||||
.await
|
||||
.map(|r| r.is_some())
|
||||
}
|
||||
|
||||
pub async fn create_status_table(&self) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!("INSERT INTO status(flush_in_progress, previous_flush_timestamp, client_in_use) VALUES (0, 0, 1)")
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_flush_status(&self) -> Result<bool, sqlx::Error> {
|
||||
sqlx::query!("SELECT flush_in_progress FROM status;")
|
||||
.fetch_one(&*self.connection_pool)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|r| r.flush_in_progress > 0)
|
||||
}
|
||||
|
||||
pub async fn set_previous_flush_timestamp(&self, timestamp: i64) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!("UPDATE status SET previous_flush_timestamp = ?", timestamp)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_previous_flush_timestamp(&self) -> Result<i64, sqlx::Error> {
|
||||
sqlx::query!("SELECT previous_flush_timestamp FROM status;")
|
||||
.fetch_one(&*self.connection_pool)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|r| r.previous_flush_timestamp)
|
||||
}
|
||||
@@ -111,14 +100,14 @@ impl StorageManager {
|
||||
pub async fn set_flush_status(&self, in_progress: bool) -> Result<(), sqlx::Error> {
|
||||
let in_progress_int = i64::from(in_progress);
|
||||
sqlx::query!("UPDATE status SET flush_in_progress = ?", in_progress_int)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_client_in_use_status(&self) -> Result<bool, sqlx::Error> {
|
||||
sqlx::query!("SELECT client_in_use FROM status;")
|
||||
.fetch_one(&*self.connection_pool)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|r| r.client_in_use > 0)
|
||||
}
|
||||
@@ -126,21 +115,21 @@ impl StorageManager {
|
||||
pub async fn set_client_in_use_status(&self, in_use: bool) -> Result<(), sqlx::Error> {
|
||||
let in_use_int = i64::from(in_use);
|
||||
sqlx::query!("UPDATE status SET client_in_use = ?", in_use_int)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_all_tags(&self) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!("DELETE FROM sender_tag;")
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tags(&self) -> Result<Vec<StoredSenderTag>, sqlx::Error> {
|
||||
sqlx::query_as!(StoredSenderTag, "SELECT * FROM sender_tag;",)
|
||||
.fetch_all(&*self.connection_pool)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -152,21 +141,21 @@ impl StorageManager {
|
||||
stored_tag.recipient,
|
||||
stored_tag.tag
|
||||
)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_all_reply_keys(&self) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!("DELETE FROM reply_key;")
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_reply_keys(&self) -> Result<Vec<StoredReplyKey>, sqlx::Error> {
|
||||
sqlx::query_as!(StoredReplyKey, "SELECT * FROM reply_key;",)
|
||||
.fetch_all(&*self.connection_pool)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -182,14 +171,14 @@ impl StorageManager {
|
||||
stored_reply_key.reply_key,
|
||||
stored_reply_key.sent_at_timestamp
|
||||
)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_surb_senders(&self) -> Result<Vec<StoredSurbSender>, sqlx::Error> {
|
||||
sqlx::query_as!(StoredSurbSender, "SELECT * FROM reply_surb_sender;",)
|
||||
.fetch_all(&*self.connection_pool)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -204,7 +193,7 @@ impl StorageManager {
|
||||
stored_surb_sender.tag,
|
||||
stored_surb_sender.last_sent_timestamp
|
||||
)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?
|
||||
.last_insert_rowid();
|
||||
Ok(id)
|
||||
@@ -222,17 +211,17 @@ impl StorageManager {
|
||||
"#,
|
||||
sender_id
|
||||
)
|
||||
.fetch_all(&*self.connection_pool)
|
||||
.fetch_all(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_all_reply_surb_data(&self) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!("DELETE FROM reply_surb;")
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
sqlx::query!("DELETE FROM reply_surb_sender;")
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
@@ -250,7 +239,7 @@ impl StorageManager {
|
||||
stored_reply_surb.reply_surb,
|
||||
stored_reply_surb.encoded_key_rotation
|
||||
)
|
||||
.execute(&*self.connection_pool)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -264,7 +253,7 @@ impl StorageManager {
|
||||
SELECT min_reply_surb_threshold as "min_reply_surb_threshold: u32", max_reply_surb_threshold as "max_reply_surb_threshold: u32" FROM reply_surb_storage_metadata;
|
||||
"#,
|
||||
)
|
||||
.fetch_one(&*self.connection_pool)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -278,7 +267,7 @@ impl StorageManager {
|
||||
"#,
|
||||
metadata.min_reply_surb_threshold,
|
||||
metadata.max_reply_surb_threshold,
|
||||
).execute(&*self.connection_pool).await?;
|
||||
).execute(&self.connection_pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::backend::fs_backend::manager::StorageManager;
|
||||
use crate::backend::fs_backend::models::{
|
||||
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender,
|
||||
};
|
||||
use crate::surb_storage::ReceivedReplySurbs;
|
||||
use crate::{
|
||||
backend::fs_backend::{
|
||||
manager::StorageManager,
|
||||
models::{
|
||||
ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag,
|
||||
StoredSurbSender,
|
||||
},
|
||||
},
|
||||
surb_storage::ReceivedReplySurbs,
|
||||
CombinedReplyStorage, ReceivedReplySurbsMap, ReplyStorageBackend, SentReplyKeys,
|
||||
UsedSenderTags,
|
||||
CombinedReplyStorage, ReceivedReplySurbsMap, ReplyStorageBackend, SentReplyKeys, UsedSenderTags,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error, info, warn};
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@@ -44,17 +41,15 @@ impl Backend {
|
||||
}
|
||||
|
||||
let manager = StorageManager::init(database_path, true).await?;
|
||||
match manager.create_status_table().await {
|
||||
Ok(()) => Ok(Backend {
|
||||
temporary_old_path: None,
|
||||
database_path: owned_path,
|
||||
manager,
|
||||
}),
|
||||
Err(err) => {
|
||||
manager.close_pool().await;
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
manager.create_status_table().await?;
|
||||
|
||||
let backend = Backend {
|
||||
temporary_old_path: None,
|
||||
database_path: owned_path,
|
||||
manager,
|
||||
};
|
||||
|
||||
Ok(backend)
|
||||
}
|
||||
|
||||
pub async fn try_load<P: AsRef<Path>>(
|
||||
@@ -69,28 +64,7 @@ impl Backend {
|
||||
}
|
||||
|
||||
let manager = StorageManager::init(database_path, false).await?;
|
||||
match Self::try_load_inner(&manager, fresh_sender_tags).await {
|
||||
Ok(()) => Ok(Backend {
|
||||
temporary_old_path: None,
|
||||
database_path: owned_path,
|
||||
manager,
|
||||
}),
|
||||
Err(e) => {
|
||||
manager.close_pool().await;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gracefully close sqlite connection pool and drop backend.
|
||||
pub async fn shutdown(self) {
|
||||
self.manager.close_pool().await
|
||||
}
|
||||
|
||||
async fn try_load_inner(
|
||||
manager: &StorageManager,
|
||||
fresh_sender_tags: bool,
|
||||
) -> Result<(), StorageError> {
|
||||
// the database flush wasn't fully finished and thus the data is in inconsistent state
|
||||
// (we don't really know what's properly saved or what's not)
|
||||
if manager.get_flush_status().await? {
|
||||
@@ -152,11 +126,20 @@ impl Backend {
|
||||
manager.delete_all_tags().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(Backend {
|
||||
temporary_old_path: None,
|
||||
database_path: owned_path,
|
||||
// manager: StorageManagerState::Storage(manager),
|
||||
manager,
|
||||
})
|
||||
}
|
||||
|
||||
async fn close_pool(&mut self) {
|
||||
self.manager.connection_pool.close().await;
|
||||
}
|
||||
|
||||
async fn rotate(&mut self) -> Result<(), StorageError> {
|
||||
self.manager.close_pool().await;
|
||||
self.close_pool().await;
|
||||
|
||||
let new_extension = if let Some(existing_extension) =
|
||||
self.database_path.extension().and_then(|ext| ext.to_str())
|
||||
@@ -169,8 +152,7 @@ impl Backend {
|
||||
let mut temp_old = self.database_path.clone();
|
||||
temp_old.set_extension(new_extension);
|
||||
|
||||
tokio::fs::rename(&self.database_path, &temp_old)
|
||||
.await
|
||||
fs::rename(&self.database_path, &temp_old)
|
||||
.map_err(|err| StorageError::DatabaseRenameError { source: err })?;
|
||||
self.manager = StorageManager::init(&self.database_path, true).await?;
|
||||
self.manager.create_status_table().await?;
|
||||
@@ -179,10 +161,9 @@ impl Backend {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_old(&mut self) -> Result<(), StorageError> {
|
||||
fn remove_old(&mut self) -> Result<(), StorageError> {
|
||||
if let Some(old_path) = self.temporary_old_path.take() {
|
||||
tokio::fs::remove_file(old_path)
|
||||
.await
|
||||
fs::remove_file(old_path)
|
||||
.map_err(|err| StorageError::DatabaseOldFileRemoveError { source: err })
|
||||
} else {
|
||||
warn!("the old database file doesn't seem to exist!");
|
||||
@@ -354,7 +335,7 @@ impl ReplyStorageBackend for Backend {
|
||||
self.dump_reply_surb_storage_metadata(surbs_ref).await?;
|
||||
self.dump_reply_surbs(surbs_ref).await?;
|
||||
|
||||
self.remove_old().await?;
|
||||
self.remove_old()?;
|
||||
self.end_storage_flush().await
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ where
|
||||
self.backend.load_surb_storage().await
|
||||
}
|
||||
|
||||
// this will have to get enabled after merging develop
|
||||
pub async fn flush_on_shutdown(
|
||||
mut self,
|
||||
mem_state: CombinedReplyStorage,
|
||||
@@ -49,6 +50,7 @@ where
|
||||
shutdown.recv().await;
|
||||
|
||||
info!("PersistentReplyStorage is flushing all reply-related data to underlying storage");
|
||||
info!("you MUST NOT forcefully shutdown now or you risk data corruption!");
|
||||
if let Err(err) = self.backend.flush_surb_storage(&mem_state).await {
|
||||
error!("failed to flush our reply-related data to the persistent storage: {err}")
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,6 @@ nym-vesting-contract-common = { path = "../../cosmwasm-smart-contracts/vesting-c
|
||||
nym-ecash-contract-common = { path = "../../cosmwasm-smart-contracts/ecash-contract" }
|
||||
nym-multisig-contract-common = { path = "../../cosmwasm-smart-contracts/multisig-contract" }
|
||||
nym-group-contract-common = { path = "../../cosmwasm-smart-contracts/group-contract" }
|
||||
nym-performance-contract-common = { path = "../../cosmwasm-smart-contracts/nym-performance-contract" }
|
||||
nym-serde-helpers = { path = "../../serde-helpers", features = ["hex", "base64"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -16,8 +16,8 @@ async fn main() {
|
||||
let prefix = "n";
|
||||
let denom: Denom = "unym".parse().unwrap();
|
||||
let signer_mnemonic: bip39::Mnemonic = "<MNEMONIC WITH FUNDS HERE>".parse().unwrap();
|
||||
let validator = "https://rpc.sandbox.nymtech.net";
|
||||
let to_address: AccountId = "n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa".parse().unwrap();
|
||||
let validator = "https://qwerty-validator.qa.nymte.ch";
|
||||
let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap();
|
||||
|
||||
let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic);
|
||||
let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone();
|
||||
|
||||
@@ -13,7 +13,6 @@ pub mod ecash_query_client;
|
||||
pub mod group_query_client;
|
||||
pub mod mixnet_query_client;
|
||||
pub mod multisig_query_client;
|
||||
pub mod performance_query_client;
|
||||
pub mod vesting_query_client;
|
||||
|
||||
// signing clients
|
||||
@@ -22,7 +21,6 @@ pub mod ecash_signing_client;
|
||||
pub mod group_signing_client;
|
||||
pub mod mixnet_signing_client;
|
||||
pub mod multisig_signing_client;
|
||||
pub mod performance_signing_client;
|
||||
pub mod vesting_signing_client;
|
||||
|
||||
// re-export query traits
|
||||
@@ -31,7 +29,6 @@ pub use ecash_query_client::{EcashQueryClient, PagedEcashQueryClient};
|
||||
pub use group_query_client::{GroupQueryClient, PagedGroupQueryClient};
|
||||
pub use mixnet_query_client::{MixnetQueryClient, PagedMixnetQueryClient};
|
||||
pub use multisig_query_client::{MultisigQueryClient, PagedMultisigQueryClient};
|
||||
pub use performance_query_client::{PagedPerformanceQueryClient, PerformanceQueryClient};
|
||||
pub use vesting_query_client::{PagedVestingQueryClient, VestingQueryClient};
|
||||
|
||||
// re-export signing traits
|
||||
@@ -40,7 +37,6 @@ pub use ecash_signing_client::EcashSigningClient;
|
||||
pub use group_signing_client::GroupSigningClient;
|
||||
pub use mixnet_signing_client::MixnetSigningClient;
|
||||
pub use multisig_signing_client::MultisigSigningClient;
|
||||
pub use performance_signing_client::PerformanceSigningClient;
|
||||
pub use vesting_signing_client::VestingSigningClient;
|
||||
|
||||
// helper for providing blanket implementation for query clients
|
||||
@@ -48,7 +44,6 @@ pub trait NymContractsProvider {
|
||||
// main
|
||||
fn mixnet_contract_address(&self) -> Option<&AccountId>;
|
||||
fn vesting_contract_address(&self) -> Option<&AccountId>;
|
||||
fn performance_contract_address(&self) -> Option<&AccountId>;
|
||||
|
||||
// coconut-related
|
||||
fn ecash_contract_address(&self) -> Option<&AccountId>;
|
||||
@@ -61,7 +56,6 @@ pub trait NymContractsProvider {
|
||||
pub struct TypedNymContracts {
|
||||
pub mixnet_contract_address: Option<AccountId>,
|
||||
pub vesting_contract_address: Option<AccountId>,
|
||||
pub performance_contract_address: Option<AccountId>,
|
||||
|
||||
pub ecash_contract_address: Option<AccountId>,
|
||||
pub group_contract_address: Option<AccountId>,
|
||||
@@ -82,10 +76,6 @@ impl TryFrom<NymContracts> for TypedNymContracts {
|
||||
.vesting_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
performance_contract_address: value
|
||||
.performance_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
.transpose()?,
|
||||
ecash_contract_address: value
|
||||
.ecash_contract_address
|
||||
.map(|addr| addr.parse())
|
||||
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::collect_paged;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::CosmWasmClient;
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::AccountId;
|
||||
use serde::Deserialize;
|
||||
|
||||
pub use nym_performance_contract_common::{
|
||||
msg::QueryMsg as PerformanceQueryMsg, types::NetworkMonitorResponse, EpochId,
|
||||
EpochMeasurementsPagedResponse, EpochNodePerformance, EpochPerformancePagedResponse,
|
||||
FullHistoricalPerformancePagedResponse, HistoricalPerformance, LastSubmission,
|
||||
NetworkMonitorInformation, NetworkMonitorsPagedResponse, NodeId, NodeMeasurement,
|
||||
NodeMeasurementsResponse, NodePerformance, NodePerformancePagedResponse,
|
||||
NodePerformanceResponse, RetiredNetworkMonitor, RetiredNetworkMonitorsPagedResponse,
|
||||
};
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PerformanceQueryClient {
|
||||
async fn query_performance_contract<T>(
|
||||
&self,
|
||||
query: PerformanceQueryMsg,
|
||||
) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>;
|
||||
|
||||
async fn admin(&self) -> Result<cw_controllers::AdminResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::Admin {})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_node_performance(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
node_id: NodeId,
|
||||
) -> Result<NodePerformanceResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::NodePerformance { epoch_id, node_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_node_performance_paged(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
start_after: Option<EpochId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<NodePerformancePagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::NodePerformancePaged {
|
||||
node_id,
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_node_measurements(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
node_id: NodeId,
|
||||
) -> Result<NodeMeasurementsResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::NodeMeasurements { epoch_id, node_id })
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_epoch_measurements_paged(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<NodeId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<EpochMeasurementsPagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::EpochMeasurementsPaged {
|
||||
epoch_id,
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_epoch_performance_paged(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
start_after: Option<NodeId>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<EpochPerformancePagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::EpochPerformancePaged {
|
||||
epoch_id,
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_full_historical_performance_paged(
|
||||
&self,
|
||||
start_after: Option<(EpochId, NodeId)>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<FullHistoricalPerformancePagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::FullHistoricalPerformancePaged {
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_network_monitor(
|
||||
&self,
|
||||
address: &AccountId,
|
||||
) -> Result<NetworkMonitorResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::NetworkMonitor {
|
||||
address: address.to_string(),
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_network_monitors_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<NetworkMonitorsPagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::NetworkMonitorsPaged {
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_retired_network_monitors_paged(
|
||||
&self,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
) -> Result<RetiredNetworkMonitorsPagedResponse, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::RetiredNetworkMonitorsPaged {
|
||||
start_after,
|
||||
limit,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_last_submission(&self) -> Result<LastSubmission, NyxdError> {
|
||||
self.query_performance_contract(PerformanceQueryMsg::LastSubmittedMeasurement {})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
// extension trait to the query client to deal with the paged queries
|
||||
// (it didn't feel appropriate to combine it with the existing trait
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PagedPerformanceQueryClient: PerformanceQueryClient {
|
||||
async fn get_all_node_performance(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
) -> Result<Vec<EpochNodePerformance>, NyxdError> {
|
||||
collect_paged!(self, get_node_performance_paged, performance, node_id)
|
||||
}
|
||||
|
||||
async fn get_all_epoch_measurements(
|
||||
&self,
|
||||
node_id: NodeId,
|
||||
) -> Result<Vec<NodeMeasurement>, NyxdError> {
|
||||
collect_paged!(self, get_epoch_measurements_paged, measurements, node_id)
|
||||
}
|
||||
|
||||
async fn get_all_epoch_performance(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<Vec<NodePerformance>, NyxdError> {
|
||||
collect_paged!(self, get_epoch_performance_paged, performance, epoch_id)
|
||||
}
|
||||
|
||||
async fn get_all_full_historical_performance(
|
||||
&self,
|
||||
) -> Result<Vec<HistoricalPerformance>, NyxdError> {
|
||||
collect_paged!(self, get_full_historical_performance_paged, performance)
|
||||
}
|
||||
|
||||
async fn get_all_network_monitors(&self) -> Result<Vec<NetworkMonitorInformation>, NyxdError> {
|
||||
collect_paged!(self, get_network_monitors_paged, info)
|
||||
}
|
||||
|
||||
async fn get_all_retired_network_monitors(
|
||||
&self,
|
||||
) -> Result<Vec<RetiredNetworkMonitor>, NyxdError> {
|
||||
collect_paged!(self, get_retired_network_monitors_paged, info)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PagedPerformanceQueryClient for T where T: PerformanceQueryClient {}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> PerformanceQueryClient for C
|
||||
where
|
||||
C: CosmWasmClient + NymContractsProvider + Send + Sync,
|
||||
{
|
||||
async fn query_performance_contract<T>(
|
||||
&self,
|
||||
query: PerformanceQueryMsg,
|
||||
) -> Result<T, NyxdError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
{
|
||||
let performance_contract_address = &self
|
||||
.performance_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("performance contract"))?;
|
||||
self.query_contract_smart(performance_contract_address, &query)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
use nym_performance_contract_common::QueryMsg;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_query_variants_are_covered<C: PerformanceQueryClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: PerformanceQueryMsg,
|
||||
) {
|
||||
match msg {
|
||||
PerformanceQueryMsg::Admin {} => client.admin().ignore(),
|
||||
PerformanceQueryMsg::NodePerformance { epoch_id, node_id } => {
|
||||
client.get_node_performance(epoch_id, node_id).ignore()
|
||||
}
|
||||
PerformanceQueryMsg::NodePerformancePaged {
|
||||
node_id,
|
||||
start_after,
|
||||
limit,
|
||||
} => client
|
||||
.get_node_performance_paged(node_id, start_after, limit)
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::NodeMeasurements { epoch_id, node_id } => {
|
||||
client.get_node_measurements(epoch_id, node_id).ignore()
|
||||
}
|
||||
PerformanceQueryMsg::EpochMeasurementsPaged {
|
||||
epoch_id,
|
||||
start_after,
|
||||
limit,
|
||||
} => client
|
||||
.get_epoch_measurements_paged(epoch_id, start_after, limit)
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::EpochPerformancePaged {
|
||||
epoch_id,
|
||||
start_after,
|
||||
limit,
|
||||
} => client
|
||||
.get_epoch_performance_paged(epoch_id, start_after, limit)
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::FullHistoricalPerformancePaged { start_after, limit } => client
|
||||
.get_full_historical_performance_paged(start_after, limit)
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::NetworkMonitor { address } => client
|
||||
.get_network_monitor(&address.parse().unwrap())
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::NetworkMonitorsPaged { start_after, limit } => client
|
||||
.get_network_monitors_paged(start_after, limit)
|
||||
.ignore(),
|
||||
PerformanceQueryMsg::RetiredNetworkMonitorsPaged { start_after, limit } => client
|
||||
.get_retired_network_monitors_paged(start_after, limit)
|
||||
.ignore(),
|
||||
QueryMsg::LastSubmittedMeasurement {} => client.get_last_submission().ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nyxd::coin::Coin;
|
||||
use crate::nyxd::contract_traits::NymContractsProvider;
|
||||
use crate::nyxd::cosmwasm_client::types::ExecuteResult;
|
||||
use crate::nyxd::cosmwasm_client::ContractResponseData;
|
||||
use crate::nyxd::error::NyxdError;
|
||||
use crate::nyxd::{Fee, SigningCosmWasmClient};
|
||||
use crate::signing::signer::OfflineSigner;
|
||||
use async_trait::async_trait;
|
||||
use nym_performance_contract_common::{
|
||||
EpochId, ExecuteMsg as PerformanceExecuteMsg, NodeId, NodePerformance,
|
||||
RemoveEpochMeasurementsResponse,
|
||||
};
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait PerformanceSigningClient {
|
||||
async fn execute_performance_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: PerformanceExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError>;
|
||||
|
||||
async fn update_admin(
|
||||
&self,
|
||||
admin: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::UpdateAdmin { admin },
|
||||
"PerformanceContract::UpdateAdmin".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn submit_performance(
|
||||
&self,
|
||||
epoch: EpochId,
|
||||
data: NodePerformance,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::Submit { epoch, data },
|
||||
"PerformanceContract::Submit".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn batch_submit_performance(
|
||||
&self,
|
||||
epoch: EpochId,
|
||||
data: Vec<NodePerformance>,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::BatchSubmit { epoch, data },
|
||||
"PerformanceContract::BatchSubmit".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn authorise_network_monitor(
|
||||
&self,
|
||||
address: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::AuthoriseNetworkMonitor { address },
|
||||
"PerformanceContract::AuthoriseNetworkMonitor".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn retire_network_monitor(
|
||||
&self,
|
||||
address: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::RetireNetworkMonitor { address },
|
||||
"PerformanceContract::RetireNetworkMonitor".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn remove_node_measurements(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
node_id: NodeId,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::RemoveNodeMeasurements { epoch_id, node_id },
|
||||
"PerformanceContract::RemoveNodeMeasurements".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn partial_remove_epoch_measurements(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_performance_contract(
|
||||
fee,
|
||||
PerformanceExecuteMsg::RemoveEpochMeasurements { epoch_id },
|
||||
"PerformanceContract::RemoveEpochMeasurements".to_string(),
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn remove_epoch_measurements(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<(), NyxdError> {
|
||||
loop {
|
||||
let execute_res = self
|
||||
.partial_remove_epoch_measurements(epoch_id, fee.clone())
|
||||
.await?;
|
||||
let response = execute_res
|
||||
.parse_singleton_json_contract_response::<RemoveEpochMeasurementsResponse>()?;
|
||||
if !response.additional_entries_to_remove_remaining {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl<C> PerformanceSigningClient for C
|
||||
where
|
||||
C: SigningCosmWasmClient + NymContractsProvider + Sync,
|
||||
NyxdError: From<<Self as OfflineSigner>::Error>,
|
||||
{
|
||||
async fn execute_performance_contract(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
msg: PerformanceExecuteMsg,
|
||||
memo: String,
|
||||
funds: Vec<Coin>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
let performance_contract_address = &self
|
||||
.performance_contract_address()
|
||||
.ok_or_else(|| NyxdError::unavailable_contract_address("performance contract"))?;
|
||||
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier())));
|
||||
|
||||
let signer_address = &self.signer_addresses()?[0];
|
||||
self.execute(
|
||||
signer_address,
|
||||
performance_contract_address,
|
||||
&msg,
|
||||
fee,
|
||||
memo,
|
||||
funds,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::nyxd::contract_traits::tests::IgnoreValue;
|
||||
use nym_performance_contract_common::ExecuteMsg;
|
||||
|
||||
// it's enough that this compiles and clippy is happy about it
|
||||
#[allow(dead_code)]
|
||||
fn all_execute_variants_are_covered<C: PerformanceSigningClient + Send + Sync>(
|
||||
client: C,
|
||||
msg: PerformanceExecuteMsg,
|
||||
) {
|
||||
match msg {
|
||||
PerformanceExecuteMsg::UpdateAdmin { admin } => {
|
||||
client.update_admin(admin, None).ignore()
|
||||
}
|
||||
PerformanceExecuteMsg::Submit { epoch, data } => {
|
||||
client.submit_performance(epoch, data, None).ignore()
|
||||
}
|
||||
PerformanceExecuteMsg::BatchSubmit { epoch, data } => {
|
||||
client.batch_submit_performance(epoch, data, None).ignore()
|
||||
}
|
||||
PerformanceExecuteMsg::AuthoriseNetworkMonitor { address } => {
|
||||
client.authorise_network_monitor(address, None).ignore()
|
||||
}
|
||||
PerformanceExecuteMsg::RetireNetworkMonitor { address } => {
|
||||
client.retire_network_monitor(address, None).ignore()
|
||||
}
|
||||
ExecuteMsg::RemoveNodeMeasurements { epoch_id, node_id } => client
|
||||
.remove_node_measurements(epoch_id, node_id, None)
|
||||
.ignore(),
|
||||
ExecuteMsg::RemoveEpochMeasurements { epoch_id } => client
|
||||
.partial_remove_epoch_measurements(epoch_id, None)
|
||||
.ignore(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,6 @@ use tendermint_rpc::endpoint::broadcast;
|
||||
use tracing::error;
|
||||
|
||||
pub use cosmrs::abci::MsgResponse;
|
||||
use cosmwasm_std::from_json;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub fn parse_singleton_u32_from_contract_response(b: Vec<u8>) -> Result<u32, NyxdError> {
|
||||
if b.len() != 4 {
|
||||
@@ -75,11 +73,6 @@ pub fn parse_msg_responses(data: Bytes) -> Vec<MsgResponse> {
|
||||
|
||||
// requires there's a single response message
|
||||
pub trait ContractResponseData: Sized {
|
||||
fn parse_singleton_json_contract_response<T: DeserializeOwned>(&self) -> Result<T, NyxdError> {
|
||||
let b = self.to_singleton_contract_data()?;
|
||||
from_json(&b).map_err(|err| err.into())
|
||||
}
|
||||
|
||||
fn parse_singleton_u32_contract_data(&self) -> Result<u32, NyxdError> {
|
||||
let b = self.to_singleton_contract_data()?;
|
||||
parse_singleton_u32_from_contract_response(b)
|
||||
|
||||
@@ -276,10 +276,6 @@ impl<C, S> NymContractsProvider for NyxdClient<C, S> {
|
||||
self.config.contracts.vesting_contract_address.as_ref()
|
||||
}
|
||||
|
||||
fn performance_contract_address(&self) -> Option<&AccountId> {
|
||||
self.config.contracts.performance_contract_address.as_ref()
|
||||
}
|
||||
|
||||
fn ecash_contract_address(&self) -> Option<&AccountId> {
|
||||
self.config.contracts.ecash_contract_address.as_ref()
|
||||
}
|
||||
|
||||
@@ -49,14 +49,14 @@ pub fn show_error<E>(e: E)
|
||||
where
|
||||
E: Display,
|
||||
{
|
||||
error!("{e}");
|
||||
error!("{}", e);
|
||||
}
|
||||
|
||||
pub fn show_error_passthrough<E>(e: E) -> E
|
||||
where
|
||||
E: Error + Display,
|
||||
{
|
||||
error!("{e}");
|
||||
error!("{}", e);
|
||||
e
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ pub async fn query_balance(
|
||||
.address
|
||||
.unwrap_or_else(|| address_from_mnemonic.expect("please provide a mnemonic"));
|
||||
|
||||
info!("Getting balance for {address}...");
|
||||
info!("Getting balance for {}...", address);
|
||||
|
||||
match client.get_all_balances(&address).await {
|
||||
Ok(coins) => {
|
||||
|
||||
@@ -57,17 +57,17 @@ pub fn get_pubkey_from_mnemonic(address: AccountId, prefix: &str, mnemonic: bip3
|
||||
println!("{}", account.public_key().to_string());
|
||||
}
|
||||
None => {
|
||||
error!("Could not derive key that matches {address}")
|
||||
error!("Could not derive key that matches {}", address)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to derive accounts. {e}");
|
||||
error!("Failed to derive accounts. {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_pubkey_from_chain(address: AccountId, client: &QueryClient) {
|
||||
info!("Getting public key for address {address} from chain...");
|
||||
info!("Getting public key for address {} from chain...", address);
|
||||
match client.get_account(&address).await {
|
||||
Ok(Some(account)) => {
|
||||
if let Ok(base_account) = account.try_get_base_account() {
|
||||
|
||||
@@ -60,7 +60,7 @@ pub async fn send(args: Args, client: &SigningClient) {
|
||||
"Nodesguru: https://nym.explorers.guru/transaction/{}",
|
||||
&res.hash
|
||||
);
|
||||
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
|
||||
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
|
||||
println!("Transaction result code: {}", &res.tx_result.code.value());
|
||||
println!("Transaction hash: {}", &res.hash);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
|
||||
|
||||
let rows = InputFileReader::new(&args.input);
|
||||
if let Err(e) = rows {
|
||||
error!("Failed to read input file: {e}");
|
||||
error!("Failed to read input file: {}", e);
|
||||
return;
|
||||
}
|
||||
let rows = rows.unwrap();
|
||||
@@ -67,7 +67,7 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
|
||||
.prompt();
|
||||
|
||||
if let Err(e) = ans {
|
||||
info!("Aborting, {e}...");
|
||||
info!("Aborting, {}...", e);
|
||||
return;
|
||||
}
|
||||
if let Ok(false) = ans {
|
||||
@@ -95,15 +95,18 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
|
||||
"Nodesguru: https://nym.explorers.guru/transaction/{}",
|
||||
&res.hash
|
||||
);
|
||||
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
|
||||
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
|
||||
println!("Transaction result code: {}", &res.tx_result.code.value());
|
||||
println!("Transaction hash: {}", &res.hash);
|
||||
|
||||
if let Some(output_filename) = args.output {
|
||||
println!("\nWriting output log to {output_filename}");
|
||||
println!("\nWriting output log to {}", output_filename);
|
||||
|
||||
if let Err(e) = write_output_file(rows, res, &output_filename) {
|
||||
error!("Failed to write output file {output_filename} with error {e}");
|
||||
error!(
|
||||
"Failed to write output file {} with error {}",
|
||||
output_filename, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,7 +136,7 @@ fn write_output_file(
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
Ok(file.write_all(format!("{data}\n").as_bytes())?)
|
||||
Ok(file.write_all(format!("{}\n", data).as_bytes())?)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -168,7 +171,7 @@ impl InputFileReader {
|
||||
|
||||
// multiply when a whole token amount, e.g. 50nym (50.123456nym is not allowed, that must be input as 50123456unym)
|
||||
let (amount, denom) = if !denom.starts_with('u') {
|
||||
(amount * 1_000_000u128, format!("u{denom}"))
|
||||
(amount * 1_000_000u128, format!("u{}", denom))
|
||||
} else {
|
||||
(amount, denom)
|
||||
};
|
||||
|
||||
@@ -55,6 +55,6 @@ pub async fn execute(args: Args, client: SigningClient) {
|
||||
.await
|
||||
{
|
||||
Ok(res) => info!("SUCCESS ✅\n{}", json!(res)),
|
||||
Err(e) => error!("FAILURE ❌\n{e}"),
|
||||
Err(e) => error!("FAILURE ❌\n{}", e),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub struct Args {
|
||||
pub async fn generate(args: Args) {
|
||||
info!("Starting to generate vesting contract instantiate msg");
|
||||
|
||||
debug!("Received arguments: {args:?}");
|
||||
debug!("Received arguments: {:?}", args);
|
||||
|
||||
let multisig_addr = args.multisig_addr.unwrap_or_else(|| {
|
||||
let address = std::env::var(nym_network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
|
||||
@@ -97,7 +97,7 @@ pub async fn generate(args: Args) {
|
||||
key_size: DEFAULT_DEALINGS as u32,
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {instantiate_msg:?}");
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
let res =
|
||||
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
|
||||
|
||||
@@ -28,7 +28,7 @@ pub struct Args {
|
||||
pub async fn generate(args: Args) {
|
||||
info!("Starting to generate vesting contract instantiate msg");
|
||||
|
||||
debug!("Received arguments: {args:?}");
|
||||
debug!("Received arguments: {:?}", args);
|
||||
|
||||
let group_addr = args.group_addr.unwrap_or_else(|| {
|
||||
let address = std::env::var(nym_network_defaults::var_names::GROUP_CONTRACT_ADDRESS)
|
||||
@@ -51,7 +51,7 @@ pub async fn generate(args: Args) {
|
||||
deposit_amount: args.deposit_amount,
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {instantiate_msg:?}");
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
let res =
|
||||
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
|
||||
|
||||
@@ -88,7 +88,7 @@ pub struct Args {
|
||||
pub async fn generate(args: Args) {
|
||||
info!("Starting to generate mixnet contract instantiate msg");
|
||||
|
||||
debug!("Received arguments: {args:?}");
|
||||
debug!("Received arguments: {:?}", args);
|
||||
|
||||
let initial_rewarding_params = InitialRewardingParams {
|
||||
initial_reward_pool: Decimal::from_atomics(args.initial_reward_pool, 0)
|
||||
@@ -114,7 +114,7 @@ pub async fn generate(args: Args) {
|
||||
},
|
||||
};
|
||||
|
||||
debug!("initial_rewarding_params: {initial_rewarding_params:?}");
|
||||
debug!("initial_rewarding_params: {:?}", initial_rewarding_params);
|
||||
|
||||
let rewarding_validator_address = args.rewarding_validator_address.unwrap_or_else(|| {
|
||||
let address = std::env::var(nym_network_defaults::var_names::REWARDING_VALIDATOR_ADDRESS)
|
||||
@@ -160,7 +160,7 @@ pub async fn generate(args: Args) {
|
||||
key_validity_in_epochs: None,
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {instantiate_msg:?}");
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
let res =
|
||||
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
|
||||
|
||||
@@ -31,7 +31,7 @@ pub struct Args {
|
||||
pub async fn generate(args: Args) {
|
||||
info!("Starting to generate vesting contract instantiate msg");
|
||||
|
||||
debug!("Received arguments: {args:?}");
|
||||
debug!("Received arguments: {:?}", args);
|
||||
|
||||
let ecash_contract_address = args.ecash_contract_address.unwrap_or_else(|| {
|
||||
let address = std::env::var(nym_network_defaults::var_names::ECASH_CONTRACT_ADDRESS)
|
||||
@@ -60,7 +60,7 @@ pub async fn generate(args: Args) {
|
||||
coconut_dkg_contract_address: coconut_dkg_contract_address.to_string(),
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {instantiate_msg:?}");
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
let res =
|
||||
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct Args {
|
||||
pub async fn generate(args: Args) {
|
||||
info!("Starting to generate vesting contract instantiate msg");
|
||||
|
||||
debug!("Received arguments: {args:?}");
|
||||
debug!("Received arguments: {:?}", args);
|
||||
|
||||
let mixnet_contract_address = args.mixnet_contract_address.unwrap_or_else(|| {
|
||||
let address = std::env::var(nym_network_defaults::var_names::MIXNET_CONTRACT_ADDRESS)
|
||||
@@ -39,7 +39,7 @@ pub async fn generate(args: Args) {
|
||||
mix_denom,
|
||||
};
|
||||
|
||||
debug!("instantiate_msg: {instantiate_msg:?}");
|
||||
debug!("instantiate_msg: {:?}", instantiate_msg);
|
||||
|
||||
let res =
|
||||
serde_json::to_string(&instantiate_msg).expect("failed to convert instantiate msg to json");
|
||||
|
||||
@@ -72,7 +72,7 @@ pub async fn init(args: Args, client: SigningClient, network_details: &NymNetwor
|
||||
.await
|
||||
.expect("failed to instantiate the contract!");
|
||||
|
||||
info!("Init result: {res:?}");
|
||||
info!("Init result: {:?}", res);
|
||||
|
||||
println!("{}", res.contract_address)
|
||||
}
|
||||
|
||||
@@ -47,5 +47,5 @@ pub async fn migrate(args: Args, client: SigningClient) {
|
||||
.expect("failed to migrate the contract!")
|
||||
};
|
||||
|
||||
info!("Migrate result: {res:?}");
|
||||
info!("Migrate result: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn upload(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to upload the contract!");
|
||||
|
||||
info!("Upload result: {res:?}");
|
||||
info!("Upload result: {:?}", res);
|
||||
|
||||
println!("{}", res.code_id)
|
||||
}
|
||||
|
||||
@@ -47,5 +47,5 @@ pub async fn delegate_to_mixnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to delegate to mixnode!");
|
||||
|
||||
info!("delegating to mixnode: {res:?}");
|
||||
info!("delegating to mixnode: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
|
||||
let records = match InputFileReader::new(&args.input) {
|
||||
Ok(records) => records,
|
||||
Err(e) => {
|
||||
println!("Error reading input file: {e}");
|
||||
println!("Error reading input file: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -262,11 +262,11 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
|
||||
}
|
||||
|
||||
if !undelegation_msgs.is_empty() {
|
||||
println!("Undelegation records : \n{undelegation_table}\n\n");
|
||||
println!("Undelegation records : \n{}\n\n", undelegation_table);
|
||||
}
|
||||
|
||||
if !delegation_msgs.is_empty() {
|
||||
println!("Delegation records : \n{delegation_table}\n\n");
|
||||
println!("Delegation records : \n{}\n\n", delegation_table);
|
||||
}
|
||||
|
||||
let ans = inquire::Confirm::new("Do you want to continue with the shown operations?")
|
||||
@@ -275,7 +275,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
|
||||
.prompt();
|
||||
|
||||
if let Err(e) = ans {
|
||||
info!("Aborting, {e}...");
|
||||
info!("Aborting, {}...", e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ pub async fn delegate_to_multiple_mixnodes(args: Args, client: SigningClient) {
|
||||
|
||||
if args.output.is_some() {
|
||||
if let Err(e) = write_to_csv(output_details, args.output) {
|
||||
info!("Failed to write to CSV, {e}");
|
||||
info!("Failed to write to CSV, {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@ pub async fn migrate_vested_delegation(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to migrate delegation!");
|
||||
|
||||
info!("migration result: {res:?}")
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -40,5 +40,5 @@ pub async fn claim_delegator_reward(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to claim delegator-reward");
|
||||
|
||||
info!("Claiming delegator reward: {res:?}")
|
||||
info!("Claiming delegator reward: {:?}", res)
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,5 +40,5 @@ pub async fn vesting_claim_delegator_reward(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to claim vesting delegator-reward");
|
||||
|
||||
info!("Claiming vesting delegator reward: {res:?}")
|
||||
info!("Claiming vesting delegator reward: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -40,5 +40,5 @@ pub async fn undelegate_from_mixnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to remove stake from mixnode!");
|
||||
|
||||
info!("removing stake from mixnode: {res:?}")
|
||||
info!("removing stake from mixnode: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -53,5 +53,5 @@ pub async fn vesting_delegate_to_mixnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to delegate to mixnode!");
|
||||
|
||||
info!("vesting delegating to mixnode: {res:?}");
|
||||
info!("vesting delegating to mixnode: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -45,5 +45,5 @@ pub async fn vesting_undelegate_from_mixnode(args: Args, client: SigningClient)
|
||||
.await
|
||||
.expect("failed to remove stake from vesting account on mixnode!");
|
||||
|
||||
info!("removing stake from vesting mixnode: {res:?}")
|
||||
info!("removing stake from vesting mixnode: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -73,5 +73,5 @@ pub async fn bond_gateway(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to bond gateway!");
|
||||
|
||||
info!("Bonding result: {res:?}")
|
||||
info!("Bonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -52,5 +52,5 @@ pub async fn migrate_to_nymnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to migrate gateway!");
|
||||
|
||||
info!("migration result: {res:?}")
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -56,5 +56,5 @@ pub async fn update_config(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("updating gateway config");
|
||||
|
||||
info!("gateway config updated: {res:?}")
|
||||
info!("gateway config updated: {:?}", res)
|
||||
}
|
||||
|
||||
+1
-1
@@ -57,5 +57,5 @@ pub async fn vesting_update_config(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("updating vesting gateway config");
|
||||
|
||||
info!("gateway config updated: {res:?}")
|
||||
info!("gateway config updated: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ pub async fn unbond_gateway(client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to unbond gateway!");
|
||||
|
||||
info!("Unbonding result: {res:?}")
|
||||
info!("Unbonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -73,5 +73,5 @@ pub async fn vesting_bond_gateway(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to bond gateway!");
|
||||
|
||||
info!("Vesting bonding gateway result: {res:?}")
|
||||
info!("Vesting bonding gateway result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ pub async fn vesting_unbond_gateway(client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to unbond vesting gateway!");
|
||||
|
||||
info!("Unbonding vesting result: {res:?}")
|
||||
info!("Unbonding vesting result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -106,5 +106,5 @@ pub async fn bond_mixnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to bond mixnode!");
|
||||
|
||||
info!("Bonding result: {res:?}")
|
||||
info!("Bonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ pub async fn decrease_pledge(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to decrease pledge!");
|
||||
|
||||
info!("decreasing pledge: {res:?}");
|
||||
info!("decreasing pledge: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@ pub async fn migrate_vested_mixnode(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to migrate mixnode!");
|
||||
|
||||
info!("migration result: {res:?}")
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -15,5 +15,5 @@ pub async fn migrate_to_nymnode(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to migrate mixnode!");
|
||||
|
||||
info!("migration result: {res:?}")
|
||||
info!("migration result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ pub async fn pledge_more(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to pledge more!");
|
||||
|
||||
info!("pledging more: {res:?}");
|
||||
info!("pledging more: {:?}", res);
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,5 +17,5 @@ pub async fn claim_operator_reward(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to claim operator reward");
|
||||
|
||||
info!("Claiming operator reward: {res:?}")
|
||||
info!("Claiming operator reward: {:?}", res)
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,5 +20,5 @@ pub async fn vesting_claim_operator_reward(client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to claim vesting operator reward");
|
||||
|
||||
info!("Claiming vesting operator reward: {res:?}")
|
||||
info!("Claiming vesting operator reward: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -64,5 +64,5 @@ pub async fn update_config(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("updating mix-node config");
|
||||
|
||||
info!("mixnode config updated: {res:?}")
|
||||
info!("mixnode config updated: {:?}", res)
|
||||
}
|
||||
|
||||
+1
-1
@@ -65,5 +65,5 @@ pub async fn vesting_update_config(client: SigningClient, args: Args) {
|
||||
.await
|
||||
.expect("updating vesting mix-node config");
|
||||
|
||||
info!("mixnode config updated: {res:?}")
|
||||
info!("mixnode config updated: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ pub async fn unbond_mixnode(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to unbond mixnode!");
|
||||
|
||||
info!("Unbonding result: {res:?}")
|
||||
info!("Unbonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -106,5 +106,5 @@ pub async fn vesting_bond_mixnode(client: SigningClient, args: Args, denom: &str
|
||||
.await
|
||||
.expect("failed to bond vesting mixnode!");
|
||||
|
||||
info!("Bonding vesting result: {res:?}")
|
||||
info!("Bonding vesting result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ pub async fn vesting_decrease_pledge(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to vesting decrease pledge!");
|
||||
|
||||
info!("vesting decreasing pledge: {res:?}");
|
||||
info!("vesting decreasing pledge: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -26,5 +26,5 @@ pub async fn vesting_pledge_more(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to pledge more!");
|
||||
|
||||
info!("vesting pledge more: {res:?}");
|
||||
info!("vesting pledge more: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@ pub async fn vesting_unbond_mixnode(client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to unbond vesting mixnode!");
|
||||
|
||||
info!("Unbonding vesting result: {res:?}")
|
||||
info!("Unbonding vesting result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -85,5 +85,5 @@ pub async fn bond_nymnode(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to bond nymnode!");
|
||||
|
||||
info!("Bonding result: {res:?}")
|
||||
info!("Bonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ pub async fn decrease_pledge(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to decrease pledge!");
|
||||
|
||||
info!("decreasing pledge: {res:?}");
|
||||
info!("decreasing pledge: {:?}", res);
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ pub async fn increase_pledge(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to pledge more!");
|
||||
|
||||
info!("pledging more: {res:?}");
|
||||
info!("pledging more: {:?}", res);
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,5 +17,5 @@ pub async fn claim_operator_reward(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to claim operator reward");
|
||||
|
||||
info!("Claiming operator reward: {res:?}")
|
||||
info!("Claiming operator reward: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@ pub async fn update_config(args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("updating nym node config");
|
||||
|
||||
info!("nym node config updated: {res:?}")
|
||||
info!("nym node config updated: {:?}", res)
|
||||
}
|
||||
|
||||
+1
-1
@@ -68,6 +68,6 @@ pub async fn update_cost_params(args: Args, client: SigningClient) -> anyhow::Re
|
||||
.await
|
||||
.expect("failed to update cost params");
|
||||
|
||||
info!("Cost params result: {res:?}");
|
||||
info!("Cost params result: {:?}", res);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ pub async fn unbond_nymnode(_args: Args, client: SigningClient) {
|
||||
.await
|
||||
.expect("failed to unbond Nym Node!");
|
||||
|
||||
info!("Unbonding result: {res:?}")
|
||||
info!("Unbonding result: {:?}", res)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn sign(args: Args, prefix: &str, mnemonic: Option<bip39::Mnemonic>) {
|
||||
println!("{}", json!(output));
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to sign message. {e}");
|
||||
error!("Failed to sign message. {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ pub fn sign(args: Args, prefix: &str, mnemonic: Option<bip39::Mnemonic>) {
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to derive accounts. {e}");
|
||||
error!("Failed to derive accounts. {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub async fn verify(args: Args, client: &QueryClient) {
|
||||
|
||||
let public_key = match AccountId::from_str(&args.public_key_or_address) {
|
||||
Ok(address) => {
|
||||
info!("Found account address instead of public key, so looking up public key for {address} from chain");
|
||||
info!("Found account address instead of public key, so looking up public key for {} from chain", address);
|
||||
match client.get_account_public_key(&address).await.ok() {
|
||||
Some(public_key) => {
|
||||
if let Some(k) = public_key {
|
||||
@@ -48,7 +48,8 @@ pub async fn verify(args: Args, client: &QueryClient) {
|
||||
}
|
||||
None => {
|
||||
error!(
|
||||
"Address {address} does not have a public key recorded on the chain. This is probably because the account has never signed a transaction."
|
||||
"Address {} does not have a public key recorded on the chain. This is probably because the account has never signed a transaction.",
|
||||
address
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -57,7 +58,7 @@ pub async fn verify(args: Args, client: &QueryClient) {
|
||||
Err(_) => match PublicKey::from_json(&args.public_key_or_address) {
|
||||
Ok(parsed) => Some(parsed),
|
||||
Err(e) => {
|
||||
error!("Public key should be JSON. Unable to parse: {e}");
|
||||
error!("Public key should be JSON. Unable to parse: {}", e);
|
||||
None
|
||||
}
|
||||
},
|
||||
@@ -77,7 +78,7 @@ pub async fn verify(args: Args, client: &QueryClient) {
|
||||
) {
|
||||
Ok(()) => println!("SUCCESS ✅ signature verified"),
|
||||
Err(e) => {
|
||||
error!("FAILURE ❌ Signature verification failed: {e}");
|
||||
error!("FAILURE ❌ Signature verification failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,6 @@ pub async fn create(args: Args, client: SigningClient, network_details: &NymNetw
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
info!("Vesting result: {res:?}");
|
||||
info!("Coin send result: {send_coin_response:?}");
|
||||
info!("Vesting result: {:?}", res);
|
||||
info!("Coin send result: {:?}", send_coin_response);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub async fn query(args: Args, client: QueryClient, address_from_mnemonic: Optio
|
||||
.address
|
||||
.unwrap_or_else(|| address_from_mnemonic.expect("please provide a mnemonic"));
|
||||
|
||||
info!("Checking account {account_id} for a vesting schedule...");
|
||||
info!("Checking account {} for a vesting schedule...", account_id);
|
||||
|
||||
let vesting_address = account_id.to_string();
|
||||
let denom = client.current_chain_details().mix_denom.base.as_str();
|
||||
|
||||
@@ -76,7 +76,7 @@ pub async fn execute(args: Args, client: SigningClient) {
|
||||
&res.transaction_hash
|
||||
);
|
||||
println!(
|
||||
"Mintscan: https://ping.pub/nyx/tx/{}",
|
||||
"Mintscan: https://www.mintscan.io/nyx/txs/{}",
|
||||
&res.transaction_hash
|
||||
);
|
||||
println!("Transaction hash: {}", &res.transaction_hash);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
[package]
|
||||
name = "nym-contracts-common-testing"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
rust-version.workspace = true
|
||||
readme.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
|
||||
serde = { workspace = true }
|
||||
rand_chacha = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
cw-multi-test = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::testing::{message_info, MockApi, MockQuerier, MockStorage};
|
||||
use cosmwasm_std::{
|
||||
coins, Addr, BankMsg, CosmosMsg, Empty, Env, MemoryStorage, MessageInfo, Order, OwnedDeps,
|
||||
Response, StdResult, Storage,
|
||||
};
|
||||
use cw_storage_plus::{KeyDeserialize, Map, Prefix, PrimaryKey};
|
||||
use rand::{RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
pub const TEST_DENOM: &str = "unym";
|
||||
pub const TEST_PREFIX: &str = "n";
|
||||
|
||||
pub fn mock_api() -> MockApi {
|
||||
MockApi::default().with_prefix(TEST_PREFIX)
|
||||
}
|
||||
|
||||
pub fn mock_dependencies() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
||||
OwnedDeps {
|
||||
storage: MockStorage::default(),
|
||||
api: mock_api(),
|
||||
querier: MockQuerier::default(),
|
||||
custom_query_type: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_rng() -> ChaCha20Rng {
|
||||
let dummy_seed = [42u8; 32];
|
||||
rand_chacha::ChaCha20Rng::from_seed(dummy_seed)
|
||||
}
|
||||
|
||||
pub fn deps_with_balance(env: &Env) -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
||||
let mut deps = mock_dependencies();
|
||||
deps.querier = MockQuerier::<Empty>::new(&[(
|
||||
env.contract.address.as_str(),
|
||||
coins(100000000000, TEST_DENOM).as_slice(),
|
||||
)]);
|
||||
deps
|
||||
}
|
||||
|
||||
pub fn generate_sorted_addresses(n: usize) -> Vec<Addr> {
|
||||
let mut rng = test_rng();
|
||||
let mut addrs = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
addrs.push(mock_api().addr_make(&format!("addr{i}{}", rng.next_u64())));
|
||||
}
|
||||
addrs.sort();
|
||||
addrs
|
||||
}
|
||||
|
||||
pub fn addr<S: AsRef<str>>(raw: S) -> Addr {
|
||||
mock_api().addr_make(raw.as_ref())
|
||||
}
|
||||
|
||||
pub fn sender<S: AsRef<str>>(raw: S) -> MessageInfo {
|
||||
message_info(&addr(raw), &[])
|
||||
}
|
||||
|
||||
pub trait ExtractBankMsg {
|
||||
fn unwrap_bank_msg(self) -> Option<BankMsg>;
|
||||
}
|
||||
|
||||
impl ExtractBankMsg for Response {
|
||||
fn unwrap_bank_msg(self) -> Option<BankMsg> {
|
||||
for msg in self.messages {
|
||||
match msg.msg {
|
||||
CosmosMsg::Bank(bank_msg) => return Some(bank_msg),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FullReader<'a> {
|
||||
type Key;
|
||||
type Value: Serialize + DeserializeOwned;
|
||||
|
||||
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>>;
|
||||
|
||||
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>>;
|
||||
}
|
||||
|
||||
impl<'a, K, T> FullReader<'a> for Map<K, T>
|
||||
where
|
||||
T: Serialize + DeserializeOwned,
|
||||
K: PrimaryKey<'a> + KeyDeserialize,
|
||||
K::Output: 'static,
|
||||
{
|
||||
type Key = K::Output;
|
||||
type Value = T;
|
||||
|
||||
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>> {
|
||||
self.range(store, None, None, Order::Ascending)
|
||||
.map(|record| record.map(|r| r.1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>> {
|
||||
self.range(store, None, None, Order::Ascending).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, T, B> FullReader<'a> for Prefix<K, T, B>
|
||||
where
|
||||
K: KeyDeserialize + 'static,
|
||||
T: Serialize + DeserializeOwned,
|
||||
B: PrimaryKey<'a>,
|
||||
{
|
||||
type Key = K::Output;
|
||||
type Value = T;
|
||||
|
||||
fn all_values(&self, store: &dyn Storage) -> StdResult<Vec<Self::Value>> {
|
||||
self.range(store, None, None, Order::Ascending)
|
||||
.map(|record| record.map(|r| r.1))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn all_key_values(&self, store: &dyn Storage) -> StdResult<Vec<(Self::Key, Self::Value)>> {
|
||||
self.range(store, None, None, Order::Ascending).collect()
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// those are all used exclusively for testing thus unwraps, et al. are allowed
|
||||
#![allow(clippy::unwrap_used)]
|
||||
#![allow(clippy::expect_used)]
|
||||
#![allow(clippy::panic)]
|
||||
|
||||
pub mod helpers;
|
||||
pub mod tester;
|
||||
|
||||
pub use helpers::*;
|
||||
pub use tester::*;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user