Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e7200a7c8 |
+22
-17
@@ -11,25 +11,30 @@
|
|||||||
# In each subsection folders are ordered first by depth, then alphabetically.
|
# In each subsection folders are ordered first by depth, then alphabetically.
|
||||||
# This should make it easy to add new rules without breaking existing ones.
|
# This should make it easy to add new rules without breaking existing ones.
|
||||||
|
|
||||||
# contracts
|
# Something weird not covered by anything else
|
||||||
/contracts/mixnet @durch @jstuczyn
|
* @futurechimp @mmsinclair
|
||||||
/contracts/vesting @durch @jstuczyn
|
|
||||||
/contracts/service-provider-directory @octol
|
|
||||||
|
|
||||||
# crypto code
|
# Rust rules:
|
||||||
/common/crypto/ @jstuczyn
|
*.rs @durch @futurechimp @jstuczyn @neacsu @octol
|
||||||
/common/nymcoconut/ @jstuczyn
|
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||||
/common/dkg/ @jstuczyn
|
|
||||||
/common/nymsphinx/ @jstuczyn
|
|
||||||
|
|
||||||
# rust sdk
|
# JS rules:
|
||||||
/sdk/rust/ @octol
|
*.js @mmsinclair @fmtabbara
|
||||||
|
*.ts @mmsinclair @fmtabbara
|
||||||
|
*.tsx @mmsinclair @fmtabbara
|
||||||
|
*.jsx @mmsinclair @fmtabbara
|
||||||
|
|
||||||
# nym-connect (rust)
|
# Something looking like possible documentation rules:
|
||||||
/nym-connect/desktop/src-tauri/ @octol
|
*.md @mfahampshire
|
||||||
|
|
||||||
# nym-wallet (rust)
|
# our docker scripts
|
||||||
/nym-wallet/src-tauri/ @octol
|
/docker/ @neacsu
|
||||||
|
|
||||||
# documentation
|
# if there are any changes in the core crypto, I feel like Ania should take a look:
|
||||||
/documentation @mfahampshire
|
/common/crypto/ @aniampio
|
||||||
|
/common/nymsphinx/ @aniampio
|
||||||
|
|
||||||
|
# Explorer and wallet should probably get looked by the product team
|
||||||
|
/explorer/ @nymtech/product
|
||||||
|
/nym-wallet/ @nymtech/product
|
||||||
|
/wallet-web/ @nymtech/product
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"os":"windows10",
|
"os":"windows-latest",
|
||||||
"rust":"stable",
|
"rust":"stable",
|
||||||
"runOnEvent":"schedule"
|
"runOnEvent":"schedule"
|
||||||
},
|
},
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"runOnEvent":"schedule"
|
"runOnEvent":"schedule"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os":"windows10",
|
"os":"windows-latest",
|
||||||
"rust":"beta",
|
"rust":"beta",
|
||||||
"runOnEvent":"schedule"
|
"runOnEvent":"schedule"
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"runOnEvent":"schedule"
|
"runOnEvent":"schedule"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"os":"windows10",
|
"os":"windows-latest",
|
||||||
"rust":"nightly",
|
"rust":"nightly",
|
||||||
"runOnEvent":"schedule"
|
"runOnEvent":"schedule"
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-2
@@ -41,5 +41,4 @@ storybook-static
|
|||||||
envs/qwerty.env
|
envs/qwerty.env
|
||||||
.parcel-cache
|
.parcel-cache
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
cpu-cycles/libcpucycles/build
|
cpu-cycles/libcpucycles/build
|
||||||
foxyfox.env
|
|
||||||
+7
-22
@@ -4,29 +4,14 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## [v1.1.16] (2023-04-25)
|
- nym-network-statistics properly handles signals ([#3209])
|
||||||
|
- add socks5 support for Rust SDK ([#3226], [#3255])
|
||||||
|
- add coconut bandwidth credential support for Rust SDK ([#3273])
|
||||||
|
|
||||||
- Explorer - Fix sorting function on Stake Saturation. It is currently working per page and not globally ([#3320])
|
[#3209]: https://github.com/nymtech/nym/issues/3209
|
||||||
- Poisson process gets stuck at too slow rate. Rework to more aggressively up-regulate ([#3309])
|
[#3226]: https://github.com/nymtech/nym/pull/3226
|
||||||
- decrease the logging level of warnings associated with clients dropping packets due to gateway being overloaded (I'd say reduce it to debug/trace) - there are few sources of those, e.g. in real and cover traffic streams ([#3299])
|
[#3255]: https://github.com/nymtech/nym/pull/3255
|
||||||
- Make the buffer size in `AvailableReader` depend on packet sizes the client is using + introduce read timeouts ([#3213])
|
[#3273]: https://github.com/nymtech/nym/pull/3273
|
||||||
- Rust SDK - Support coconut, credential storage etc ([#2755])
|
|
||||||
- version bump for next release ([#3349])
|
|
||||||
- added coconut credential generation example ([#3339])
|
|
||||||
- update mix-node setup docs with node description ([#3325])
|
|
||||||
- exposed missing gateway commands in nym-cli ([#3324])
|
|
||||||
- make sure to clear inner 'ack_map' in 'GatewaysReader' ([#3300])
|
|
||||||
|
|
||||||
[#3320]: https://github.com/nymtech/nym/issues/3320
|
|
||||||
[#3309]: https://github.com/nymtech/nym/issues/3309
|
|
||||||
[#3299]: https://github.com/nymtech/nym/issues/3299
|
|
||||||
[#3213]: https://github.com/nymtech/nym/issues/3213
|
|
||||||
[#2755]: https://github.com/nymtech/nym/issues/2755
|
|
||||||
[#3349]: https://github.com/nymtech/nym/pull/3349
|
|
||||||
[#3339]: https://github.com/nymtech/nym/pull/3339
|
|
||||||
[#3325]: https://github.com/nymtech/nym/pull/3325
|
|
||||||
[#3324]: https://github.com/nymtech/nym/pull/3324
|
|
||||||
[#3300]: https://github.com/nymtech/nym/pull/3300
|
|
||||||
|
|
||||||
## [v1.1.15] (2023-04-18)
|
## [v1.1.15] (2023-04-18)
|
||||||
|
|
||||||
|
|||||||
Generated
+37
-37
@@ -1576,7 +1576,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
@@ -3011,7 +3011,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-api"
|
name = "nym-api"
|
||||||
version = "1.1.17"
|
version = "1.1.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3142,7 +3142,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-cli"
|
name = "nym-cli"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.13.1",
|
"base64 0.13.1",
|
||||||
@@ -3203,7 +3203,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
"dirs",
|
"dirs",
|
||||||
@@ -3471,7 +3471,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-gateway"
|
name = "nym-gateway"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3600,7 +3600,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnet-contract-common"
|
name = "nym-mixnet-contract-common"
|
||||||
version = "0.5.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
@@ -3619,7 +3619,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnode"
|
name = "nym-mixnode"
|
||||||
version = "1.1.17"
|
version = "1.1.16"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bs58",
|
"bs58",
|
||||||
@@ -3721,7 +3721,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-file-watcher",
|
"async-file-watcher",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3763,7 +3763,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-statistics"
|
name = "nym-network-statistics"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"log",
|
"log",
|
||||||
@@ -3778,25 +3778,6 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nym-node-tester-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"futures",
|
|
||||||
"log",
|
|
||||||
"nym-crypto",
|
|
||||||
"nym-sphinx",
|
|
||||||
"nym-sphinx-params",
|
|
||||||
"nym-task",
|
|
||||||
"nym-topology",
|
|
||||||
"rand 0.7.3",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"wasm-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-nonexhaustive-delayqueue"
|
name = "nym-nonexhaustive-delayqueue"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -3828,9 +3809,8 @@ dependencies = [
|
|||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"rand 0.7.3",
|
|
||||||
"rayon",
|
"rayon",
|
||||||
"sphinx-packet",
|
"sphinx-packet 0.1.0 (git+https://github.com/nymtech/sphinx.git)",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@@ -3899,7 +3879,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 4.1.11",
|
"clap 4.1.11",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@@ -4081,7 +4061,6 @@ dependencies = [
|
|||||||
"nym-sphinx-addressing",
|
"nym-sphinx-addressing",
|
||||||
"nym-sphinx-params",
|
"nym-sphinx-params",
|
||||||
"nym-sphinx-types",
|
"nym-sphinx-types",
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4109,9 +4088,7 @@ dependencies = [
|
|||||||
name = "nym-sphinx-types"
|
name = "nym-sphinx-types"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nym-outfox",
|
"sphinx-packet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sphinx-packet",
|
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4225,7 +4202,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract"
|
name = "nym-vesting-contract"
|
||||||
version = "1.4.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-derive",
|
"cosmwasm-derive",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
@@ -4243,7 +4220,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract-common"
|
name = "nym-vesting-contract-common"
|
||||||
version = "0.6.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"nym-contracts-common",
|
"nym-contracts-common",
|
||||||
@@ -5912,6 +5889,29 @@ dependencies = [
|
|||||||
"subtle 2.4.1",
|
"subtle 2.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sphinx-packet"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/nymtech/sphinx.git#ca107d94360cdf8bbfbdb12fe5320ed74f80e40c"
|
||||||
|
dependencies = [
|
||||||
|
"aes 0.7.5",
|
||||||
|
"arrayref",
|
||||||
|
"blake2",
|
||||||
|
"bs58",
|
||||||
|
"byteorder",
|
||||||
|
"chacha",
|
||||||
|
"curve25519-dalek",
|
||||||
|
"digest 0.9.0",
|
||||||
|
"hkdf 0.11.0",
|
||||||
|
"hmac 0.11.0",
|
||||||
|
"lioness",
|
||||||
|
"log",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"rand_distr",
|
||||||
|
"sha2 0.9.9",
|
||||||
|
"subtle 2.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ members = [
|
|||||||
"common/ledger",
|
"common/ledger",
|
||||||
"common/mixnode-common",
|
"common/mixnode-common",
|
||||||
"common/network-defaults",
|
"common/network-defaults",
|
||||||
"common/node-tester-utils",
|
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
"common/nymcoconut",
|
"common/nymcoconut",
|
||||||
"common/nymsphinx",
|
"common/nymsphinx",
|
||||||
|
|||||||
@@ -13,10 +13,6 @@ happy: fmt clippy-happy test
|
|||||||
# on all workspaces.
|
# on all workspaces.
|
||||||
build-release: build-release-main wasm
|
build-release: build-release-main wasm
|
||||||
|
|
||||||
# Deprecated
|
|
||||||
# For backwards compatibility
|
|
||||||
clippy-all: clippy
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Define targets for a given workspace
|
# Define targets for a given workspace
|
||||||
# $(1): name
|
# $(1): name
|
||||||
@@ -56,11 +52,11 @@ fmt-$(1):
|
|||||||
cargo fmt --manifest-path $(2)/Cargo.toml --all
|
cargo fmt --manifest-path $(2)/Cargo.toml --all
|
||||||
|
|
||||||
clippy-happy: clippy-happy-$(1)
|
clippy-happy: clippy-happy-$(1)
|
||||||
clippy: clippy-$(1) clippy-examples-$(1)
|
clippy-all: clippy-$(1) clippy-examples-$(1)
|
||||||
check: check-$(1)
|
check: check-$(1)
|
||||||
cargo-test: test-$(1)
|
cargo-test: test-$(1)
|
||||||
cargo-test-expensive: test-expensive-$(1)
|
cargo-test-expensive: test-expensive-$(1)
|
||||||
build: build-$(1) build-examples-$(1)
|
build: build-$(1) build-$(1)-examples
|
||||||
build-release-all: build-release-$(1)
|
build-release-all: build-release-$(1)
|
||||||
fmt: fmt-$(1)
|
fmt: fmt-$(1)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use nym_client_core::client::received_buffer::{
|
|||||||
};
|
};
|
||||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
use nym_task::TaskManager;
|
use nym_task::TaskManager;
|
||||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||||
@@ -120,7 +119,6 @@ impl SocketClient {
|
|||||||
self_address,
|
self_address,
|
||||||
shared_lane_queue_lengths,
|
shared_lane_queue_lengths,
|
||||||
reply_controller_sender,
|
reply_controller_sender,
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
||||||
@@ -180,10 +178,7 @@ impl SocketClient {
|
|||||||
Ok(started_client.task_manager)
|
Ok(started_client.task_manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_direct(
|
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
|
||||||
self,
|
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Result<DirectClient, ClientError> {
|
|
||||||
if self.config.get_socket_type().is_websocket() {
|
if self.config.get_socket_type().is_websocket() {
|
||||||
return Err(ClientError::InvalidSocketMode);
|
return Err(ClientError::InvalidSocketMode);
|
||||||
}
|
}
|
||||||
@@ -229,7 +224,6 @@ impl SocketClient {
|
|||||||
reconstructed_receiver,
|
reconstructed_receiver,
|
||||||
address,
|
address,
|
||||||
shutdown_notifier: started_client.task_manager,
|
shutdown_notifier: started_client.task_manager,
|
||||||
packet_type,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +237,6 @@ pub struct DirectClient {
|
|||||||
|
|
||||||
// we need to keep reference to this guy otherwise things will start dropping
|
// we need to keep reference to this guy otherwise things will start dropping
|
||||||
shutdown_notifier: TaskManager,
|
shutdown_notifier: TaskManager,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectClient {
|
impl DirectClient {
|
||||||
@@ -264,7 +257,7 @@ impl DirectClient {
|
|||||||
/// well enough in local tests)
|
/// well enough in local tests)
|
||||||
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
|
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||||
|
|
||||||
self.client_input
|
self.client_input
|
||||||
.input_sender
|
.input_sender
|
||||||
@@ -283,8 +276,7 @@ impl DirectClient {
|
|||||||
reply_surbs: u32,
|
reply_surbs: u32,
|
||||||
) {
|
) {
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
let input_msg =
|
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
|
||||||
|
|
||||||
self.client_input
|
self.client_input
|
||||||
.input_sender
|
.input_sender
|
||||||
@@ -298,7 +290,7 @@ impl DirectClient {
|
|||||||
/// well enough in local tests)
|
/// well enough in local tests)
|
||||||
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
|
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||||
|
|
||||||
self.client_input
|
self.client_input
|
||||||
.input_sender
|
.input_sender
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use nym_client_core::client::{
|
|||||||
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_sphinx::receiver::ReconstructedMessage;
|
use nym_sphinx::receiver::ReconstructedMessage;
|
||||||
use nym_task::connections::{
|
use nym_task::connections::{
|
||||||
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||||
@@ -42,7 +41,6 @@ pub(crate) struct HandlerBuilder {
|
|||||||
self_full_address: Recipient,
|
self_full_address: Recipient,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
reply_controller_sender: ReplyControllerSender,
|
reply_controller_sender: ReplyControllerSender,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HandlerBuilder {
|
impl HandlerBuilder {
|
||||||
@@ -53,7 +51,6 @@ impl HandlerBuilder {
|
|||||||
self_full_address: &Recipient,
|
self_full_address: &Recipient,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
reply_controller_sender: ReplyControllerSender,
|
reply_controller_sender: ReplyControllerSender,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
msg_input,
|
msg_input,
|
||||||
@@ -62,7 +59,6 @@ impl HandlerBuilder {
|
|||||||
self_full_address: *self_full_address,
|
self_full_address: *self_full_address,
|
||||||
lane_queue_lengths,
|
lane_queue_lengths,
|
||||||
reply_controller_sender,
|
reply_controller_sender,
|
||||||
packet_type,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +73,6 @@ impl HandlerBuilder {
|
|||||||
received_response_type: Default::default(),
|
received_response_type: Default::default(),
|
||||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||||
reply_controller_sender: self.reply_controller_sender.clone(),
|
reply_controller_sender: self.reply_controller_sender.clone(),
|
||||||
packet_type: self.packet_type,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,7 +86,6 @@ pub(crate) struct Handler {
|
|||||||
received_response_type: ReceivedResponseType,
|
received_response_type: ReceivedResponseType,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
reply_controller_sender: ReplyControllerSender,
|
reply_controller_sender: ReplyControllerSender,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Handler {
|
impl Drop for Handler {
|
||||||
@@ -166,7 +160,7 @@ impl Handler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// the ack control is now responsible for chunking, etc.
|
// the ack control is now responsible for chunking, etc.
|
||||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||||
self.msg_input
|
self.msg_input
|
||||||
.send(input_msg)
|
.send(input_msg)
|
||||||
.await
|
.await
|
||||||
@@ -197,8 +191,7 @@ impl Handler {
|
|||||||
TransmissionLane::ConnectionId(id)
|
TransmissionLane::ConnectionId(id)
|
||||||
});
|
});
|
||||||
|
|
||||||
let input_msg =
|
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
|
||||||
self.msg_input
|
self.msg_input
|
||||||
.send(input_msg)
|
.send(input_msg)
|
||||||
.await
|
.await
|
||||||
@@ -225,7 +218,7 @@ impl Handler {
|
|||||||
TransmissionLane::ConnectionId(id)
|
TransmissionLane::ConnectionId(id)
|
||||||
});
|
});
|
||||||
|
|
||||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||||
self.msg_input
|
self.msg_input
|
||||||
.send(input_msg)
|
.send(input_msg)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.16"
|
version = "1.1.15"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
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"
|
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ impl From<Init> for OverrideConfig {
|
|||||||
no_cover: init_config.no_cover,
|
no_cover: init_config.no_cover,
|
||||||
nyxd_urls: init_config.nyxd_urls,
|
nyxd_urls: init_config.nyxd_urls,
|
||||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||||
outfox: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use nym_bin_common::completions::{fig_generate, ArgShell};
|
|||||||
use nym_config::{NymConfig, OptionalSet};
|
use nym_config::{NymConfig, OptionalSet};
|
||||||
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
|
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||||
use nym_socks5_client_core::config::{BaseConfig, Config};
|
use nym_socks5_client_core::config::{BaseConfig, Config};
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
@@ -65,7 +64,6 @@ pub(crate) struct OverrideConfig {
|
|||||||
no_cover: bool,
|
no_cover: bool,
|
||||||
nyxd_urls: Option<Vec<url::Url>>,
|
nyxd_urls: Option<Vec<url::Url>>,
|
||||||
enabled_credentials_mode: Option<bool>,
|
enabled_credentials_mode: Option<bool>,
|
||||||
outfox: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||||
@@ -82,15 +80,9 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||||
let packet_type = if args.outfox {
|
|
||||||
PacketType::Outfox
|
|
||||||
} else {
|
|
||||||
PacketType::Mix
|
|
||||||
};
|
|
||||||
config
|
config
|
||||||
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
||||||
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
||||||
.with_base(BaseConfig::with_packet_type, packet_type)
|
|
||||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||||
.with_optional(Config::with_port, args.port)
|
.with_optional(Config::with_port, args.port)
|
||||||
.with_optional_custom_env_ext(
|
.with_optional_custom_env_ext(
|
||||||
|
|||||||
@@ -67,9 +67,6 @@ pub(crate) struct Run {
|
|||||||
/// with bandwidth credential requirement.
|
/// with bandwidth credential requirement.
|
||||||
#[clap(long, hide = true)]
|
#[clap(long, hide = true)]
|
||||||
enabled_credentials_mode: Option<bool>,
|
enabled_credentials_mode: Option<bool>,
|
||||||
|
|
||||||
#[clap(long, hide = true, action)]
|
|
||||||
outfox: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Run> for OverrideConfig {
|
impl From<Run> for OverrideConfig {
|
||||||
@@ -82,7 +79,6 @@ impl From<Run> for OverrideConfig {
|
|||||||
no_cover: run_config.no_cover,
|
no_cover: run_config.no_cover,
|
||||||
nyxd_urls: run_config.nyxd_urls,
|
nyxd_urls: run_config.nyxd_urls,
|
||||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||||
outfox: run_config.outfox,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
[build]
|
|
||||||
target = "wasm32-unknown-unknown"
|
|
||||||
@@ -17,7 +17,6 @@ default = ["console_error_panic_hook"]
|
|||||||
offline-test = []
|
offline-test = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bs58 = "0.4.0"
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||||
@@ -29,12 +28,8 @@ tokio = { version = "1.24.1", features = ["sync"] }
|
|||||||
url = "2.2"
|
url = "2.2"
|
||||||
wasm-bindgen = { version = "=0.2.83", features = ["serde-serialize"] }
|
wasm-bindgen = { version = "=0.2.83", features = ["serde-serialize"] }
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
thiserror = "1.0.40"
|
|
||||||
|
|
||||||
wasm-timer = { git = "https://github.com/mmsinclair/wasm-timer", rev = "b9d1a54ad514c2f230a026afe0dde341e98cd7b6"}
|
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
nym-node-tester-utils = { path = "../../common/node-tester-utils" }
|
|
||||||
nym-client-core = { path = "../../common/client-core", default-features = false, features = ["wasm"] }
|
nym-client-core = { path = "../../common/client-core", default-features = false, features = ["wasm"] }
|
||||||
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
nym-bandwidth-controller = { path = "../../common/bandwidth-controller" }
|
||||||
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
nym-coconut-interface = { path = "../../common/coconut-interface" }
|
||||||
@@ -42,8 +37,6 @@ nym-credentials = { path = "../../common/credentials" }
|
|||||||
nym-credential-storage = { path = "../../common/credential-storage" }
|
nym-credential-storage = { path = "../../common/credential-storage" }
|
||||||
nym-crypto = { path = "../../common/crypto" }
|
nym-crypto = { path = "../../common/crypto" }
|
||||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||||
nym-topology = { path = "../../common/topology" }
|
|
||||||
nym-gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm"] }
|
|
||||||
nym-validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
nym-validator-client = { path = "../../common/client-libs/validator-client", default-features = false }
|
||||||
wasm-utils = { path = "../../common/wasm-utils" }
|
wasm-utils = { path = "../../common/wasm-utils" }
|
||||||
nym-task = { path = "../../common/task" }
|
nym-task = { path = "../../common/task" }
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
// A dependency graph that contains any wasm must all be imported
|
|
||||||
// asynchronously. This `bootstrap.js` file does the single async import, so
|
|
||||||
// that no one else needs to worry about it again.
|
|
||||||
import('./index.js')
|
|
||||||
.catch(e => console.error('Error importing `index.js`:', e));
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Nym WebAssembly Demo</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<p>
|
|
||||||
<label>Sender: </label><input disabled="true" size="85" type="text" id="sender" value="">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<label>Recipient: </label><input size="85" type="text" id="recipient" value="">
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label>Message: </label><input type="text" id="message" value="Hello mixnet!">
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<button id="send-button">Send</button>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label>Mixnode Identity: </label>
|
|
||||||
<input type="text" size = "60" id="mixnode_identity" value="...">
|
|
||||||
<button id="magic-button">✨ Magic Test Button ✨</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<p>Send messages from your browser, through the mixnet, and to the recipient using the "send" button.</p>
|
|
||||||
<p><span style='color: blue;'>Sent</span> messages show in blue, <span style='color: green;'>received</span>
|
|
||||||
messages show in green.</p>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<p>
|
|
||||||
<span id="output"></span>
|
|
||||||
</p>
|
|
||||||
<script src="./bootstrap.js"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
// Copyright 2020-2023 Nym Technologies SA
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
class WebWorkerClient {
|
|
||||||
worker = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.worker = new Worker('./worker.js');
|
|
||||||
|
|
||||||
this.worker.onmessage = (ev) => {
|
|
||||||
if (ev.data && ev.data.kind) {
|
|
||||||
switch (ev.data.kind) {
|
|
||||||
case 'Ready':
|
|
||||||
const {selfAddress} = ev.data.args;
|
|
||||||
displaySenderAddress(selfAddress);
|
|
||||||
break;
|
|
||||||
case 'ReceiveMessage':
|
|
||||||
const {message, senderTag, isTestPacket } = ev.data.args;
|
|
||||||
displayReceived(message, senderTag, isTestPacket);
|
|
||||||
break;
|
|
||||||
case 'DisableMagicTestButton':
|
|
||||||
const magicButton = document.querySelector('#magic-button');
|
|
||||||
magicButton.setAttribute('disabled', "true")
|
|
||||||
break;
|
|
||||||
case 'DisplayTesterResults':
|
|
||||||
const {score, sentPackets, receivedPackets, receivedAcks, duplicatePackets, duplicateAcks} = ev.data.args;
|
|
||||||
const resultText = `Test score: ${score}. Sent ${sentPackets} packets. Received ${receivedPackets} packets and ${receivedAcks} acks back. We also got ${duplicatePackets} duplicate packets and ${duplicateAcks} duplicate acks.`
|
|
||||||
displayReceivedRawString(resultText)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage = (message, recipient) => {
|
|
||||||
if (!this.worker) {
|
|
||||||
console.error('Could not send message because worker does not exist');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.worker.postMessage({
|
|
||||||
kind: 'SendMessage',
|
|
||||||
args: {
|
|
||||||
message, recipient,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
sendTestPacket = (mixnodeIdentity) => {
|
|
||||||
if (!this.worker) {
|
|
||||||
console.error('Could not send message because worker does not exist');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.worker.postMessage({
|
|
||||||
kind: 'TestPacket',
|
|
||||||
args: {
|
|
||||||
mixnodeIdentity,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let client = null;
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
client = new WebWorkerClient();
|
|
||||||
|
|
||||||
const sendButton = document.querySelector('#send-button');
|
|
||||||
sendButton.onclick = function () {
|
|
||||||
sendMessageTo();
|
|
||||||
};
|
|
||||||
|
|
||||||
const magicButton = document.querySelector('#magic-button');
|
|
||||||
magicButton.onclick = function () {
|
|
||||||
sendTestPacket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a Sphinx packet and send it to the mixnet through the gateway node.
|
|
||||||
*
|
|
||||||
* Message and recipient are taken from the values in the user interface.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async function sendMessageTo() {
|
|
||||||
const message = document.getElementById('message').value;
|
|
||||||
const recipient = document.getElementById('recipient').value;
|
|
||||||
|
|
||||||
await client.sendMessage(message, recipient);
|
|
||||||
displaySend(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendTestPacket() {
|
|
||||||
const mixnodeIdentity = document.getElementById('mixnode_identity').value;
|
|
||||||
|
|
||||||
await client.sendTestPacket(mixnodeIdentity)
|
|
||||||
displaySend(`sending test packets to: ${mixnodeIdentity}...`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display messages that have been sent up the websocket. Colours them blue.
|
|
||||||
*
|
|
||||||
* @param {string} message
|
|
||||||
*/
|
|
||||||
function displaySend(message) {
|
|
||||||
let timestamp = new Date().toISOString().substr(11, 12);
|
|
||||||
|
|
||||||
let sendDiv = document.createElement('div');
|
|
||||||
let paragraph = document.createElement('p');
|
|
||||||
paragraph.setAttribute('style', 'color: blue');
|
|
||||||
let paragraphContent = document.createTextNode(timestamp + ' sent >>> ' + message);
|
|
||||||
paragraph.appendChild(paragraphContent);
|
|
||||||
|
|
||||||
sendDiv.appendChild(paragraph);
|
|
||||||
document.getElementById('output').appendChild(sendDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display received text messages in the browser. Colour them green.
|
|
||||||
*
|
|
||||||
* @param {Uint8Array} raw
|
|
||||||
*/
|
|
||||||
function displayReceived(raw, sender_tag, isTestPacket) {
|
|
||||||
let content = new TextDecoder().decode(raw);
|
|
||||||
if (sender_tag !== undefined) {
|
|
||||||
console.log("this message also contained some surbs from", sender_tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTestPacket) {
|
|
||||||
const decoded = JSON.parse(content)
|
|
||||||
content = `Received packet ${decoded.msg_id} / ${decoded.total_msgs} for node ${decoded.encoded_node_identity} (test: ${decoded.test_id})`
|
|
||||||
}
|
|
||||||
|
|
||||||
displayReceivedRawString(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function displayReceivedRawString(raw) {
|
|
||||||
let timestamp = new Date().toISOString().substr(11, 12);
|
|
||||||
let receivedDiv = document.createElement('div');
|
|
||||||
let paragraph = document.createElement('p');
|
|
||||||
paragraph.setAttribute('style', 'color: green');
|
|
||||||
let paragraphContent = document.createTextNode(timestamp + ' received >>> ' + raw);
|
|
||||||
paragraph.appendChild(paragraphContent);
|
|
||||||
receivedDiv.appendChild(paragraph);
|
|
||||||
document.getElementById('output').appendChild(receivedDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the nymClient's sender address in the user interface
|
|
||||||
*
|
|
||||||
* @param {String} address
|
|
||||||
*/
|
|
||||||
function displaySenderAddress(address) {
|
|
||||||
document.getElementById('sender').value = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "create-wasm-app",
|
|
||||||
"version": "0.1.0",
|
|
||||||
"description": "create an app to consume rust-generated wasm packages",
|
|
||||||
"main": "index.js",
|
|
||||||
"bin": {
|
|
||||||
"create-wasm-app": ".bin/create-wasm-app.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "webpack --config webpack.config.js",
|
|
||||||
"start": "webpack-dev-server --port 8001"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"webassembly",
|
|
||||||
"wasm",
|
|
||||||
"rust",
|
|
||||||
"webpack"
|
|
||||||
],
|
|
||||||
"author": "Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/nymtech/nym/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://nymtech.net/docs",
|
|
||||||
"devDependencies": {
|
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
|
||||||
"hello-wasm-pack": "^0.1.0",
|
|
||||||
"webpack": "^5.70.0",
|
|
||||||
"webpack-cli": "^4.9.2",
|
|
||||||
"webpack-dev-server": "^4.7.4"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@nymproject/nym-client-wasm": "file:../pkg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
performance: {
|
|
||||||
hints: false,
|
|
||||||
maxEntrypointSize: 512000,
|
|
||||||
maxAssetSize: 512000
|
|
||||||
},
|
|
||||||
entry: {
|
|
||||||
bootstrap: './bootstrap.js',
|
|
||||||
worker: './worker.js',
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, 'dist'),
|
|
||||||
filename: '[name].js',
|
|
||||||
},
|
|
||||||
// mode: 'development',
|
|
||||||
mode: 'production',
|
|
||||||
plugins: [
|
|
||||||
new CopyWebpackPlugin({
|
|
||||||
patterns: [
|
|
||||||
'index.html',
|
|
||||||
{
|
|
||||||
from: 'node_modules/@nymproject/nym-client-wasm/*.(js|wasm)',
|
|
||||||
to: '[name][ext]',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
],
|
|
||||||
experiments: { syncWebAssembly: true },
|
|
||||||
};
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
// Copyright 2020-2023 Nym Technologies SA
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
importScripts('nym_client_wasm.js');
|
|
||||||
|
|
||||||
console.log('Initializing worker');
|
|
||||||
|
|
||||||
// wasm_bindgen creates a global variable (with the exports attached) that is in scope after `importScripts`
|
|
||||||
const {
|
|
||||||
NymNodeTester,
|
|
||||||
WasmGateway,
|
|
||||||
WasmMixNode,
|
|
||||||
WasmNymTopology,
|
|
||||||
default_debug,
|
|
||||||
NymClientBuilder,
|
|
||||||
NymClient,
|
|
||||||
set_panic_hook,
|
|
||||||
Config,
|
|
||||||
GatewayEndpointConfig,
|
|
||||||
current_network_topology,
|
|
||||||
} = wasm_bindgen;
|
|
||||||
|
|
||||||
let client = null;
|
|
||||||
let tester = null;
|
|
||||||
|
|
||||||
function dummyTopology() {
|
|
||||||
const l1Mixnode = new WasmMixNode(
|
|
||||||
1,
|
|
||||||
'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47',
|
|
||||||
'178.79.143.65',
|
|
||||||
1789,
|
|
||||||
'4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz',
|
|
||||||
'8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG',
|
|
||||||
1,
|
|
||||||
'1.10.0',
|
|
||||||
);
|
|
||||||
const l2Mixnode = new WasmMixNode(
|
|
||||||
2,
|
|
||||||
'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70',
|
|
||||||
'109.74.197.180',
|
|
||||||
1789,
|
|
||||||
'7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK',
|
|
||||||
'GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN',
|
|
||||||
2,
|
|
||||||
'1.10.0',
|
|
||||||
);
|
|
||||||
const l3Mixnode = new WasmMixNode(
|
|
||||||
3,
|
|
||||||
'n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77',
|
|
||||||
'176.58.101.80',
|
|
||||||
1789,
|
|
||||||
'FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R',
|
|
||||||
'DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD',
|
|
||||||
3,
|
|
||||||
'1.10.0',
|
|
||||||
);
|
|
||||||
|
|
||||||
const gateway = new WasmGateway(
|
|
||||||
'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts',
|
|
||||||
'85.159.212.96',
|
|
||||||
1789,
|
|
||||||
9000,
|
|
||||||
'336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
|
|
||||||
'BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL',
|
|
||||||
'1.10.1',
|
|
||||||
);
|
|
||||||
|
|
||||||
const mixnodes = new Map();
|
|
||||||
mixnodes.set(1, [l1Mixnode]);
|
|
||||||
mixnodes.set(2, [l2Mixnode]);
|
|
||||||
mixnodes.set(3, [l3Mixnode]);
|
|
||||||
|
|
||||||
|
|
||||||
const gateways = [gateway];
|
|
||||||
|
|
||||||
return new WasmNymTopology(mixnodes, gateways)
|
|
||||||
}
|
|
||||||
|
|
||||||
function printAndDisplayTestResult(result) {
|
|
||||||
result.log_details();
|
|
||||||
|
|
||||||
self.postMessage({
|
|
||||||
kind: 'DisplayTesterResults',
|
|
||||||
args: {
|
|
||||||
score: result.score(),
|
|
||||||
sentPackets: result.sent_packets,
|
|
||||||
receivedPackets: result.received_packets,
|
|
||||||
receivedAcks: result.received_acks,
|
|
||||||
duplicatePackets: result.duplicate_packets,
|
|
||||||
duplicateAcks: result.duplicate_acks,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function dummyGatewayConfig() {
|
|
||||||
return new GatewayEndpointConfig(
|
|
||||||
'336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
|
|
||||||
'n1rqqw8km7a0rvf8lr6k8dsdqvvkyn2mglj7xxfm',
|
|
||||||
'ws://85.159.212.96:9000',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function testWithTester() {
|
|
||||||
const gatewayConfig = dummyGatewayConfig();
|
|
||||||
|
|
||||||
// A) construct with hardcoded topology
|
|
||||||
const topology = dummyTopology()
|
|
||||||
const nodeTester = await new NymNodeTester(gatewayConfig, topology);
|
|
||||||
|
|
||||||
// B) first get topology directly from nym-api
|
|
||||||
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
|
||||||
// const topology = await current_network_topology(validator)
|
|
||||||
// const nodeTester = await new NymNodeTester(gatewayConfig, topology);
|
|
||||||
//
|
|
||||||
// C) use nym-api in the constructor (note: it does no filtering for 'good' nodes on other layers)
|
|
||||||
// const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
|
||||||
// const nodeTester = await NymNodeTester.new_with_api(gatewayConfig, validator)
|
|
||||||
|
|
||||||
self.onmessage = async event => {
|
|
||||||
if (event.data && event.data.kind) {
|
|
||||||
switch (event.data.kind) {
|
|
||||||
case 'TestPacket': {
|
|
||||||
const {mixnodeIdentity} = event.data.args;
|
|
||||||
console.log("starting node test...");
|
|
||||||
|
|
||||||
let result = await nodeTester.test_node(mixnodeIdentity);
|
|
||||||
printAndDisplayTestResult(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function testWithNymClient() {
|
|
||||||
const gatewayConfig = dummyGatewayConfig();
|
|
||||||
const topology = dummyTopology()
|
|
||||||
|
|
||||||
let received = 0
|
|
||||||
|
|
||||||
const onMessageHandler = (message) => {
|
|
||||||
received += 1;
|
|
||||||
self.postMessage({
|
|
||||||
kind: 'ReceiveMessage',
|
|
||||||
args: {
|
|
||||||
message,
|
|
||||||
senderTag: undefined,
|
|
||||||
isTestPacket: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// it's really up to the user to create proper callback here...
|
|
||||||
console.log(`received ${received} packets so far`)
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Instantiating WASM client...');
|
|
||||||
|
|
||||||
let clientBuilder = NymClientBuilder.new_tester(gatewayConfig, topology, onMessageHandler)
|
|
||||||
console.log('Web worker creating WASM client...');
|
|
||||||
let local_client = await clientBuilder.start_client();
|
|
||||||
console.log('WASM client running!');
|
|
||||||
|
|
||||||
const selfAddress = local_client.self_address();
|
|
||||||
|
|
||||||
// set the global (I guess we don't have to anymore?)
|
|
||||||
client = local_client;
|
|
||||||
|
|
||||||
console.log(`Client address is ${selfAddress}`);
|
|
||||||
self.postMessage({
|
|
||||||
kind: 'Ready',
|
|
||||||
args: {
|
|
||||||
selfAddress,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set callback to handle messages passed to the worker.
|
|
||||||
self.onmessage = async event => {
|
|
||||||
console.log(event)
|
|
||||||
if (event.data && event.data.kind) {
|
|
||||||
switch (event.data.kind) {
|
|
||||||
case 'SendMessage': {
|
|
||||||
const {message, recipient} = event.data.args;
|
|
||||||
let uint8Array = new TextEncoder().encode(message);
|
|
||||||
await client.send_regular_message(uint8Array, recipient);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'TestPacket': {
|
|
||||||
const {mixnodeIdentity} = event.data.args;
|
|
||||||
const req = await client.try_construct_test_packet_request(mixnodeIdentity);
|
|
||||||
await client.change_hardcoded_topology(req.injectable_topology());
|
|
||||||
await client.try_send_test_packets(req);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function normalNymClientUsage() {
|
|
||||||
self.postMessage({kind: 'DisableMagicTestButton'});
|
|
||||||
|
|
||||||
// only really useful if you want to adjust some settings like traffic rate
|
|
||||||
// (if not needed you can just pass a null)
|
|
||||||
const debug = default_debug();
|
|
||||||
|
|
||||||
debug.disable_main_poisson_packet_distribution = true;
|
|
||||||
debug.disable_loop_cover_traffic_stream = true;
|
|
||||||
debug.use_extended_packet_size = false;
|
|
||||||
// debug.average_packet_delay_ms = BigInt(10);
|
|
||||||
// debug.average_ack_delay_ms = BigInt(10);
|
|
||||||
// debug.ack_wait_addition_ms = BigInt(3000);
|
|
||||||
// debug.ack_wait_multiplier = 10;
|
|
||||||
|
|
||||||
debug.topology_refresh_rate_ms = BigInt(60000)
|
|
||||||
|
|
||||||
const gatewayConfig = dummyGatewayConfig();
|
|
||||||
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
|
||||||
|
|
||||||
const config = new Config('my-awesome-wasm-client', validator, gatewayConfig, debug);
|
|
||||||
|
|
||||||
const onMessageHandler = (message) => {
|
|
||||||
console.log(message);
|
|
||||||
self.postMessage({
|
|
||||||
kind: 'ReceiveMessage',
|
|
||||||
args: {
|
|
||||||
message,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Instantiating WASM client...');
|
|
||||||
|
|
||||||
let localClient = await new NymClient(config, onMessageHandler)
|
|
||||||
console.log('WASM client running!');
|
|
||||||
|
|
||||||
const selfAddress = localClient.self_address();
|
|
||||||
|
|
||||||
// set the global (I guess we don't have to anymore?)
|
|
||||||
client = localClient;
|
|
||||||
|
|
||||||
console.log(`Client address is ${selfAddress}`);
|
|
||||||
self.postMessage({
|
|
||||||
kind: 'Ready',
|
|
||||||
args: {
|
|
||||||
selfAddress,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set callback to handle messages passed to the worker.
|
|
||||||
self.onmessage = async event => {
|
|
||||||
console.log(event)
|
|
||||||
if (event.data && event.data.kind) {
|
|
||||||
switch (event.data.kind) {
|
|
||||||
case 'SendMessage': {
|
|
||||||
const {message, recipient} = event.data.args;
|
|
||||||
let uint8Array = new TextEncoder().encode(message);
|
|
||||||
await client.send_regular_message(uint8Array, recipient);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
// load WASM package
|
|
||||||
await wasm_bindgen('nym_client_wasm_bg.wasm');
|
|
||||||
console.log('Loaded WASM');
|
|
||||||
|
|
||||||
// sets up better stack traces in case of in-rust panics
|
|
||||||
set_panic_hook();
|
|
||||||
|
|
||||||
// run test on simplified and dedicated tester:
|
|
||||||
await testWithTester()
|
|
||||||
|
|
||||||
// hook-up the whole client for testing
|
|
||||||
// await testWithNymClient()
|
|
||||||
|
|
||||||
// 'Normal' client setup (to send 'normal' messages)
|
|
||||||
// await normalNymClientUsage()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's get started!
|
|
||||||
main();
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ pub struct Config {
|
|||||||
/// ID specifies the human readable ID of this particular client.
|
/// ID specifies the human readable ID of this particular client.
|
||||||
pub(crate) id: String,
|
pub(crate) id: String,
|
||||||
|
|
||||||
pub(crate) nym_api_url: Option<Url>,
|
pub(crate) nym_api_url: Url,
|
||||||
|
|
||||||
pub(crate) disabled_credentials_mode: bool,
|
pub(crate) disabled_credentials_mode: bool,
|
||||||
|
|
||||||
@@ -46,11 +46,9 @@ impl Config {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Config {
|
Config {
|
||||||
id,
|
id,
|
||||||
nym_api_url: Some(
|
nym_api_url: validator_server
|
||||||
validator_server
|
.parse()
|
||||||
.parse()
|
.expect("provided url was malformed"),
|
||||||
.expect("provided url was malformed"),
|
|
||||||
),
|
|
||||||
disabled_credentials_mode: true,
|
disabled_credentials_mode: true,
|
||||||
gateway_endpoint,
|
gateway_endpoint,
|
||||||
debug: debug.map(Into::into).unwrap_or_default(),
|
debug: debug.map(Into::into).unwrap_or_default(),
|
||||||
@@ -231,11 +229,6 @@ pub struct Topology {
|
|||||||
/// path. This timeout determines waiting period until it is decided that the packet
|
/// path. This timeout determines waiting period until it is decided that the packet
|
||||||
/// did not reach its destination.
|
/// did not reach its destination.
|
||||||
pub topology_resolution_timeout_ms: u64,
|
pub topology_resolution_timeout_ms: u64,
|
||||||
|
|
||||||
/// Specifies whether the client should not refresh the network topology after obtaining
|
|
||||||
/// the first valid instance.
|
|
||||||
/// Supersedes `topology_refresh_rate_ms`.
|
|
||||||
pub disable_refreshing: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Topology> for ConfigTopology {
|
impl From<Topology> for ConfigTopology {
|
||||||
@@ -245,7 +238,6 @@ impl From<Topology> for ConfigTopology {
|
|||||||
topology_resolution_timeout: Duration::from_millis(
|
topology_resolution_timeout: Duration::from_millis(
|
||||||
topology.topology_resolution_timeout_ms,
|
topology.topology_resolution_timeout_ms,
|
||||||
),
|
),
|
||||||
disable_refreshing: topology.disable_refreshing,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +247,6 @@ impl From<ConfigTopology> for Topology {
|
|||||||
Topology {
|
Topology {
|
||||||
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
|
topology_refresh_rate_ms: topology.topology_refresh_rate.as_millis() as u64,
|
||||||
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
|
topology_resolution_timeout_ms: topology.topology_resolution_timeout.as_millis() as u64,
|
||||||
disable_refreshing: topology.disable_refreshing,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,16 @@
|
|||||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::error::WasmClientError;
|
|
||||||
use crate::tester::helpers::WasmTestMessageExt;
|
|
||||||
use crate::tester::{NodeTestMessage, DEFAULT_TEST_PACKETS};
|
|
||||||
use crate::topology::WasmNymTopology;
|
|
||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
use nym_client_core::client::base_client::{ClientInput, ClientState};
|
use nym_client_core::client::base_client::ClientInput;
|
||||||
use nym_client_core::client::inbound_messages::InputMessage;
|
use nym_client_core::client::inbound_messages::InputMessage;
|
||||||
use nym_topology::{MixLayer, NymTopology};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use wasm_bindgen_futures::future_to_promise;
|
use wasm_bindgen_futures::future_to_promise;
|
||||||
use wasm_utils::{console_log, js_error, simple_js_error};
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct NymClientTestRequest {
|
|
||||||
// serialized NodeTestMessage
|
|
||||||
pub(crate) test_msgs: Vec<Vec<u8>>,
|
|
||||||
|
|
||||||
// specially constructed network topology that only contains the target
|
|
||||||
// node on the tested layer
|
|
||||||
pub(crate) testable_topology: NymTopology,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl NymClientTestRequest {
|
|
||||||
pub fn injectable_topology(&self) -> WasmNymTopology {
|
|
||||||
self.testable_topology.clone().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// defining helper trait as we could directly call the method on the wrapper
|
// defining helper trait as we could directly call the method on the wrapper
|
||||||
pub(crate) trait InputSender {
|
pub(crate) trait InputSender {
|
||||||
fn send_message(&self, message: InputMessage) -> Promise;
|
fn send_message(&self, message: InputMessage) -> Promise;
|
||||||
|
|
||||||
fn send_messages(&self, messages: Vec<InputMessage>) -> Promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputSender for Arc<ClientInput> {
|
impl InputSender for Arc<ClientInput> {
|
||||||
@@ -45,125 +19,12 @@ impl InputSender for Arc<ClientInput> {
|
|||||||
future_to_promise(async move {
|
future_to_promise(async move {
|
||||||
match this.input_sender.send(message).await {
|
match this.input_sender.send(message).await {
|
||||||
Ok(_) => Ok(JsValue::null()),
|
Ok(_) => Ok(JsValue::null()),
|
||||||
Err(_) => Err(simple_js_error(
|
Err(_) => {
|
||||||
"InputMessageReceiver has stopped receiving!",
|
let js_error =
|
||||||
)),
|
js_sys::Error::new("InputMessageReceiver has stopped receiving!");
|
||||||
}
|
Err(JsValue::from(js_error))
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_messages(&self, messages: Vec<InputMessage>) -> Promise {
|
|
||||||
let this = Arc::clone(self);
|
|
||||||
future_to_promise(async move {
|
|
||||||
for message in messages {
|
|
||||||
if this.input_sender.send(message).await.is_err() {
|
|
||||||
return Err(simple_js_error(
|
|
||||||
"InputMessageReceiver has stopped receiving!",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(JsValue::null())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait WasmTopologyExt {
|
|
||||||
/// Changes the current network topology to the provided value.
|
|
||||||
fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise;
|
|
||||||
|
|
||||||
/// Returns the current network topology.
|
|
||||||
fn current_topology(&self) -> Promise;
|
|
||||||
|
|
||||||
/// Checks whether the provided node exists in the known network topology and if so, returns its layer.
|
|
||||||
fn check_for_mixnode_existence(&self, mixnode_identity: String) -> Promise;
|
|
||||||
|
|
||||||
/// Creates a `NymClientTestRequest` with a variant of `this` topology where the target node is the only one on its layer.
|
|
||||||
fn mix_test_request(
|
|
||||||
&self,
|
|
||||||
test_id: u32,
|
|
||||||
mixnode_identity: String,
|
|
||||||
num_test_packets: Option<u32>,
|
|
||||||
) -> Promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmTopologyExt for Arc<ClientState> {
|
|
||||||
fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise {
|
|
||||||
let this = Arc::clone(self);
|
|
||||||
future_to_promise(async move {
|
|
||||||
let nym_topology: NymTopology = topology.into();
|
|
||||||
console_log!("changing topology to {nym_topology:?}");
|
|
||||||
this.topology_accessor
|
|
||||||
.manually_change_topology(nym_topology)
|
|
||||||
.await;
|
|
||||||
Ok(JsValue::null())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_topology(&self) -> Promise {
|
|
||||||
let this = Arc::clone(self);
|
|
||||||
future_to_promise(async move {
|
|
||||||
match this.topology_accessor.current_topology().await {
|
|
||||||
Some(topology) => Ok(JsValue::from(WasmNymTopology::from(topology))),
|
|
||||||
None => Err(WasmClientError::UnavailableNetworkTopology.into()),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether the target mixnode exists in the known network topology and returns its layer.
|
|
||||||
fn check_for_mixnode_existence(&self, mixnode_identity: String) -> Promise {
|
|
||||||
let this = Arc::clone(self);
|
|
||||||
future_to_promise(async move {
|
|
||||||
let Some(current_topology) = this.topology_accessor.current_topology().await else {
|
|
||||||
return Err(WasmClientError::UnavailableNetworkTopology.into())
|
|
||||||
};
|
|
||||||
|
|
||||||
match current_topology.find_mix_by_identity(&mixnode_identity) {
|
|
||||||
None => Err(WasmClientError::NonExistentMixnode { mixnode_identity }.into()),
|
|
||||||
Some(node) => Ok(JsValue::from(MixLayer::from(node.layer))),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mix_test_request(
|
|
||||||
&self,
|
|
||||||
test_id: u32,
|
|
||||||
mixnode_identity: String,
|
|
||||||
num_test_packets: Option<u32>,
|
|
||||||
) -> Promise {
|
|
||||||
let num_test_packets = num_test_packets.unwrap_or(DEFAULT_TEST_PACKETS);
|
|
||||||
|
|
||||||
let this = Arc::clone(self);
|
|
||||||
future_to_promise(async move {
|
|
||||||
let Some(current_topology) = this.topology_accessor.current_topology().await else {
|
|
||||||
return Err(WasmClientError::UnavailableNetworkTopology.into())
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(mix) = current_topology.find_mix_by_identity(&mixnode_identity) else {
|
|
||||||
return Err(WasmClientError::NonExistentMixnode { mixnode_identity }.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut test_msgs = Vec::with_capacity(num_test_packets as usize);
|
|
||||||
for i in 1..=num_test_packets {
|
|
||||||
let msg = NodeTestMessage::new_mix(
|
|
||||||
mix,
|
|
||||||
i,
|
|
||||||
num_test_packets,
|
|
||||||
WasmTestMessageExt::new(test_id),
|
|
||||||
);
|
|
||||||
let serialized = match msg.as_bytes() {
|
|
||||||
Ok(bytes) => bytes,
|
|
||||||
Err(err) => return Err(js_error!("failed to serialize test message: {err}")),
|
|
||||||
};
|
|
||||||
test_msgs.push(serialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut updated = current_topology.clone();
|
|
||||||
updated.set_mixes_in_layer(mix.layer.into(), vec![mix.to_owned()]);
|
|
||||||
|
|
||||||
Ok(JsValue::from(NymClientTestRequest {
|
|
||||||
test_msgs,
|
|
||||||
testable_topology: updated,
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,27 @@
|
|||||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use self::config::Config;
|
use self::config::Config;
|
||||||
use crate::client::helpers::{InputSender, NymClientTestRequest, WasmTopologyExt};
|
use crate::client::helpers::InputSender;
|
||||||
use crate::client::response_pusher::ResponsePusher;
|
use crate::client::response_pusher::ResponsePusher;
|
||||||
use crate::error::WasmClientError;
|
|
||||||
use crate::helpers::{
|
|
||||||
parse_recipient, parse_sender_tag, setup_new_key_manager, setup_reply_surb_storage_backend,
|
|
||||||
};
|
|
||||||
use crate::topology::WasmNymTopology;
|
|
||||||
use js_sys::Promise;
|
use js_sys::Promise;
|
||||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
||||||
use nym_bandwidth_controller::BandwidthController;
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
use nym_client_core::client::base_client::{
|
use nym_client_core::client::base_client::{
|
||||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState, CredentialsToggle,
|
BaseClientBuilder, ClientInput, ClientOutput, CredentialsToggle,
|
||||||
};
|
};
|
||||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||||
use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
|
use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyManager};
|
||||||
use nym_client_core::config::{
|
|
||||||
CoverTraffic, DebugConfig, GatewayEndpointConfig, Topology, Traffic,
|
|
||||||
};
|
|
||||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||||
use nym_sphinx::params::PacketType;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
use nym_task::TaskManager;
|
use nym_task::TaskManager;
|
||||||
use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
|
|
||||||
use nym_topology::NymTopology;
|
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::RngCore;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_futures::future_to_promise;
|
use wasm_bindgen_futures::future_to_promise;
|
||||||
use wasm_utils::{check_promise_result, console_log, PromisableResult};
|
use wasm_utils::{console_error, console_log};
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
@@ -41,22 +31,15 @@ mod response_pusher;
|
|||||||
pub struct NymClient {
|
pub struct NymClient {
|
||||||
self_address: String,
|
self_address: String,
|
||||||
client_input: Arc<ClientInput>,
|
client_input: Arc<ClientInput>,
|
||||||
client_state: Arc<ClientState>,
|
|
||||||
|
|
||||||
// keep track of the "old" topology for the purposes of node tester
|
|
||||||
// so that it could be restored after the check is done
|
|
||||||
_full_topology: Option<NymTopology>,
|
|
||||||
|
|
||||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
||||||
// and if it's dropped, everything will start going offline
|
// and if it's dropped, everything will start going offline
|
||||||
_task_manager: TaskManager,
|
_task_manager: TaskManager,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct NymClientBuilder {
|
pub struct NymClientBuilder {
|
||||||
config: Config,
|
config: Config,
|
||||||
custom_topology: Option<NymTopology>,
|
|
||||||
|
|
||||||
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
||||||
key_manager: KeyManager,
|
key_manager: KeyManager,
|
||||||
@@ -69,7 +52,6 @@ pub struct NymClientBuilder {
|
|||||||
bandwidth_controller:
|
bandwidth_controller:
|
||||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||||
disabled_credentials: bool,
|
disabled_credentials: bool,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@@ -78,193 +60,118 @@ impl NymClientBuilder {
|
|||||||
pub fn new(config: Config, on_message: js_sys::Function) -> Self {
|
pub fn new(config: Config, on_message: js_sys::Function) -> Self {
|
||||||
//, key_manager: Option<KeyManager>) {
|
//, key_manager: Option<KeyManager>) {
|
||||||
NymClientBuilder {
|
NymClientBuilder {
|
||||||
reply_surb_storage_backend: setup_reply_surb_storage_backend(config.debug.reply_surbs),
|
reply_surb_storage_backend: Self::setup_reply_surb_storage_backend(&config),
|
||||||
config,
|
config,
|
||||||
custom_topology: None,
|
key_manager: Self::setup_key_manager(),
|
||||||
key_manager: setup_new_key_manager(),
|
|
||||||
on_message,
|
on_message,
|
||||||
bandwidth_controller: None,
|
bandwidth_controller: None,
|
||||||
disabled_credentials: true,
|
disabled_credentials: true,
|
||||||
packet_type: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no cover traffic
|
// TODO: once we make keys persistent, we'll require some kind of `init` method to generate
|
||||||
// no poisson delay
|
// a prior shared keypair between the client and the gateway
|
||||||
// hardcoded topology
|
|
||||||
// NOTE: you most likely want to use `[NymNodeTester]` instead.
|
|
||||||
pub fn new_tester(
|
|
||||||
gateway_config: GatewayEndpointConfig,
|
|
||||||
topology: WasmNymTopology,
|
|
||||||
on_message: js_sys::Function,
|
|
||||||
) -> Self {
|
|
||||||
if !topology.ensure_contains(&gateway_config) {
|
|
||||||
panic!("the specified topology does not contain the gateway used by the client")
|
|
||||||
}
|
|
||||||
|
|
||||||
let full_config = Config {
|
// perhaps this should be public?
|
||||||
id: "ephemeral-id".to_string(),
|
fn setup_key_manager() -> KeyManager {
|
||||||
nym_api_url: None,
|
let mut rng = OsRng;
|
||||||
disabled_credentials_mode: true,
|
// for time being generate new keys each time...
|
||||||
gateway_endpoint: gateway_config,
|
console_log!("generated new set of keys");
|
||||||
debug: DebugConfig {
|
KeyManager::new(&mut rng)
|
||||||
traffic: Traffic {
|
}
|
||||||
disable_main_poisson_packet_distribution: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
cover_traffic: CoverTraffic {
|
|
||||||
disable_loop_cover_traffic_stream: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
topology: Topology {
|
|
||||||
disable_refreshing: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
NymClientBuilder {
|
// don't get too excited about the name, under the hood it's just a big fat placeholder
|
||||||
reply_surb_storage_backend: setup_reply_surb_storage_backend(
|
// with no persistence
|
||||||
full_config.debug.reply_surbs,
|
fn setup_reply_surb_storage_backend(config: &Config) -> browser_backend::Backend {
|
||||||
),
|
browser_backend::Backend::new(
|
||||||
config: full_config,
|
config
|
||||||
custom_topology: Some(topology.into()),
|
.debug
|
||||||
// TODO: once we make keys persistent, we'll require some kind of `init` method to generate
|
.reply_surbs
|
||||||
// a prior shared keypair between the client and the gateway
|
.minimum_reply_surb_storage_threshold,
|
||||||
key_manager: setup_new_key_manager(),
|
config
|
||||||
on_message,
|
.debug
|
||||||
bandwidth_controller: None,
|
.reply_surbs
|
||||||
disabled_credentials: true,
|
.maximum_reply_surb_storage_threshold,
|
||||||
packet_type: None,
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_reconstructed_pusher(client_output: ClientOutput, on_message: js_sys::Function) {
|
fn start_reconstructed_pusher(client_output: ClientOutput, on_message: js_sys::Function) {
|
||||||
ResponsePusher::new(client_output, on_message).start()
|
ResponsePusher::new(client_output, on_message).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn topology_provider(&mut self) -> Option<Box<dyn TopologyProvider>> {
|
pub async fn start_client(self) -> Promise {
|
||||||
if let Some(hardcoded_topology) = self.custom_topology.take() {
|
future_to_promise(async move {
|
||||||
Some(Box::new(HardcodedTopologyProvider::new(hardcoded_topology)))
|
console_log!("Starting the wasm client");
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_client_async(mut self) -> Result<NymClient, WasmClientError> {
|
let disabled_credentials = if self.disabled_credentials {
|
||||||
console_log!("Starting the wasm client");
|
CredentialsToggle::Disabled
|
||||||
|
} else {
|
||||||
|
CredentialsToggle::Enabled
|
||||||
|
};
|
||||||
|
|
||||||
let maybe_topology_provider = self.topology_provider();
|
let base_builder = BaseClientBuilder::new(
|
||||||
|
&self.config.gateway_endpoint,
|
||||||
|
&self.config.debug,
|
||||||
|
self.key_manager,
|
||||||
|
self.bandwidth_controller,
|
||||||
|
self.reply_surb_storage_backend,
|
||||||
|
disabled_credentials,
|
||||||
|
vec![self.config.nym_api_url.clone()],
|
||||||
|
);
|
||||||
|
|
||||||
let disabled_credentials = if self.disabled_credentials {
|
let self_address = base_builder.as_mix_recipient().to_string();
|
||||||
CredentialsToggle::Disabled
|
let mut started_client = match base_builder.start_base().await {
|
||||||
} else {
|
Ok(base_client) => base_client,
|
||||||
CredentialsToggle::Enabled
|
Err(err) => {
|
||||||
};
|
let error_msg = format!("failed to start the base client components - {err}");
|
||||||
|
console_error!("{}", error_msg);
|
||||||
|
let js_error = js_sys::Error::new(&error_msg);
|
||||||
|
return Err(JsValue::from(js_error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let nym_api_endpoints = match self.config.nym_api_url {
|
let client_input = started_client.client_input.register_producer();
|
||||||
Some(endpoint) => vec![endpoint],
|
let client_output = started_client.client_output.register_consumer();
|
||||||
None => Vec::new(),
|
|
||||||
};
|
|
||||||
let mut base_builder = BaseClientBuilder::new(
|
|
||||||
&self.config.gateway_endpoint,
|
|
||||||
&self.config.debug,
|
|
||||||
self.key_manager,
|
|
||||||
self.bandwidth_controller,
|
|
||||||
self.reply_surb_storage_backend,
|
|
||||||
disabled_credentials,
|
|
||||||
nym_api_endpoints,
|
|
||||||
);
|
|
||||||
if let Some(topology_provider) = maybe_topology_provider {
|
|
||||||
base_builder = base_builder.with_topology_provider(topology_provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
let self_address = base_builder.as_mix_recipient().to_string();
|
Self::start_reconstructed_pusher(client_output, self.on_message);
|
||||||
let mut started_client = base_builder.start_base().await?;
|
|
||||||
|
|
||||||
let client_input = started_client.client_input.register_producer();
|
Ok(JsValue::from(NymClient {
|
||||||
let client_output = started_client.client_output.register_consumer();
|
self_address,
|
||||||
|
client_input: Arc::new(client_input),
|
||||||
Self::start_reconstructed_pusher(client_output, self.on_message);
|
_task_manager: started_client.task_manager,
|
||||||
|
}))
|
||||||
Ok(NymClient {
|
|
||||||
self_address,
|
|
||||||
client_input: Arc::new(client_input),
|
|
||||||
client_state: Arc::new(started_client.client_state),
|
|
||||||
_full_topology: None,
|
|
||||||
_task_manager: started_client.task_manager,
|
|
||||||
packet_type: self.packet_type,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_client(self) -> Promise {
|
|
||||||
future_to_promise(async move { self.start_client_async().await.into_promise_result() })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl NymClient {
|
impl NymClient {
|
||||||
async fn _new(
|
|
||||||
config: Config,
|
|
||||||
on_message: js_sys::Function,
|
|
||||||
) -> Result<NymClient, WasmClientError> {
|
|
||||||
NymClientBuilder::new(config, on_message)
|
|
||||||
.start_client_async()
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
#[allow(clippy::new_ret_no_self)]
|
|
||||||
pub fn new(config: Config, on_message: js_sys::Function) -> Promise {
|
|
||||||
future_to_promise(async move { Self::_new(config, on_message).await.into_promise_result() })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn self_address(&self) -> String {
|
pub fn self_address(&self) -> String {
|
||||||
self.self_address.clone()
|
self.self_address.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_construct_test_packet_request(
|
fn parse_recipient(recipient: &str) -> Result<Recipient, JsValue> {
|
||||||
&self,
|
match Recipient::try_from_base58_string(recipient) {
|
||||||
mixnode_identity: String,
|
Ok(recipient) => Ok(recipient),
|
||||||
num_test_packets: Option<u32>,
|
Err(err) => {
|
||||||
) -> Promise {
|
let error_msg = format!("{recipient} is not a valid Nym network recipient - {err}");
|
||||||
// TODO: improve the source of rng (i.e. don't make it ephemeral...)
|
console_error!("{}", error_msg);
|
||||||
let mut ephemeral_rng = OsRng;
|
let js_error = js_sys::Error::new(&error_msg);
|
||||||
let test_id = ephemeral_rng.next_u32();
|
Err(JsValue::from(js_error))
|
||||||
self.client_state
|
}
|
||||||
.mix_test_request(test_id, mixnode_identity, num_test_packets)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_hardcoded_topology(&self, topology: WasmNymTopology) -> Promise {
|
fn parse_sender_tag(tag: &str) -> Result<AnonymousSenderTag, JsValue> {
|
||||||
self.client_state.change_hardcoded_topology(topology)
|
match AnonymousSenderTag::try_from_base58_string(tag) {
|
||||||
}
|
Ok(tag) => Ok(tag),
|
||||||
|
Err(err) => {
|
||||||
pub fn current_network_topology(&self) -> Promise {
|
let error_msg = format!("{tag} is not a valid Nym AnonymousSenderTag - {err}");
|
||||||
self.client_state.current_topology()
|
console_error!("{}", error_msg);
|
||||||
}
|
let js_error = js_sys::Error::new(&error_msg);
|
||||||
|
Err(JsValue::from(js_error))
|
||||||
/// Sends a test packet through the current network topology.
|
}
|
||||||
/// It's the responsibility of the caller to ensure the correct topology has been injected and
|
}
|
||||||
/// correct onmessage handlers have been setup.
|
|
||||||
pub fn try_send_test_packets(&mut self, request: NymClientTestRequest) -> Promise {
|
|
||||||
// TOOD: use the premade packets instead
|
|
||||||
console_log!(
|
|
||||||
"Attempting to send {} test packets",
|
|
||||||
request.test_msgs.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
// our address MUST BE valid
|
|
||||||
let recipient = parse_recipient(&self.self_address()).unwrap();
|
|
||||||
|
|
||||||
let lane = TransmissionLane::General;
|
|
||||||
let input_msgs = request
|
|
||||||
.test_msgs
|
|
||||||
.into_iter()
|
|
||||||
.map(|p| InputMessage::new_regular(recipient, p, lane, None))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
self.client_input.send_messages(input_msgs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The simplest message variant where no additional information is attached.
|
/// The simplest message variant where no additional information is attached.
|
||||||
@@ -277,11 +184,13 @@ impl NymClient {
|
|||||||
message.len() as f64 / 1024.0
|
message.len() as f64 / 1024.0
|
||||||
);
|
);
|
||||||
|
|
||||||
let recipient = check_promise_result!(parse_recipient(&recipient));
|
let recipient = match Self::parse_recipient(&recipient) {
|
||||||
|
Ok(recipient) => recipient,
|
||||||
|
Err(err) => return Promise::reject(&err),
|
||||||
|
};
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
|
|
||||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||||
self.client_input.send_message(input_msg)
|
self.client_input.send_message(input_msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,12 +213,13 @@ impl NymClient {
|
|||||||
message.len() as f64 / 1024.0
|
message.len() as f64 / 1024.0
|
||||||
);
|
);
|
||||||
|
|
||||||
let recipient = check_promise_result!(parse_recipient(&recipient));
|
let recipient = match Self::parse_recipient(&recipient) {
|
||||||
|
Ok(recipient) => recipient,
|
||||||
|
Err(err) => return Promise::reject(&err),
|
||||||
|
};
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
|
|
||||||
let input_msg =
|
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
|
||||||
self.client_input.send_message(input_msg)
|
self.client_input.send_message(input_msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,11 +233,13 @@ impl NymClient {
|
|||||||
message.len() as f64 / 1024.0
|
message.len() as f64 / 1024.0
|
||||||
);
|
);
|
||||||
|
|
||||||
let sender_tag = check_promise_result!(parse_sender_tag(&recipient_tag));
|
let sender_tag = match Self::parse_sender_tag(&recipient_tag) {
|
||||||
|
Ok(recipient) => recipient,
|
||||||
|
Err(err) => return Promise::reject(&err),
|
||||||
|
};
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
|
|
||||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane, self.packet_type);
|
let input_msg = InputMessage::new_reply(sender_tag, message, lane);
|
||||||
self.client_input.send_message(input_msg)
|
self.client_input.send_message(input_msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::topology::WasmTopologyError;
|
|
||||||
use js_sys::Promise;
|
|
||||||
use nym_client_core::error::ClientCoreError;
|
|
||||||
use nym_crypto::asymmetric::identity::Ed25519RecoveryError;
|
|
||||||
use nym_gateway_client::error::GatewayClientError;
|
|
||||||
use nym_node_tester_utils::error::NetworkTestingError;
|
|
||||||
use nym_sphinx::addressing::clients::RecipientFormattingError;
|
|
||||||
use nym_sphinx::anonymous_replies::requests::InvalidAnonymousSenderTagRepresentation;
|
|
||||||
use nym_validator_client::ValidatorClientError;
|
|
||||||
use thiserror::Error;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use wasm_utils::simple_js_error;
|
|
||||||
|
|
||||||
// might as well start using well-defined error enum...
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum WasmClientError {
|
|
||||||
#[error(
|
|
||||||
"A node test is already in progress. Wait for it to finish before starting another one."
|
|
||||||
)]
|
|
||||||
TestInProgress,
|
|
||||||
|
|
||||||
#[error("experienced an issue with internal client components: {source}")]
|
|
||||||
BaseClientError {
|
|
||||||
#[from]
|
|
||||||
source: ClientCoreError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("The provided gateway identity is invalid: {source}")]
|
|
||||||
InvalidGatewayIdentity { source: Ed25519RecoveryError },
|
|
||||||
|
|
||||||
#[error("Gateway communication failure: {source}")]
|
|
||||||
GatewayClientError {
|
|
||||||
#[from]
|
|
||||||
source: GatewayClientError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("failed to query nym api: {source}")]
|
|
||||||
NymApiError {
|
|
||||||
#[from]
|
|
||||||
source: ValidatorClientError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("The provided topology was invalid: {source}")]
|
|
||||||
WasmTopologyError {
|
|
||||||
#[from]
|
|
||||||
source: WasmTopologyError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("failed to test the node: {source}")]
|
|
||||||
NodeTestingFailure {
|
|
||||||
#[from]
|
|
||||||
source: NetworkTestingError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("{raw} is not a valid url: {source}")]
|
|
||||||
MalformedUrl {
|
|
||||||
raw: String,
|
|
||||||
source: url::ParseError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("Network topology is currently unavailable")]
|
|
||||||
UnavailableNetworkTopology,
|
|
||||||
|
|
||||||
#[error("Mixnode {mixnode_identity} is not present in the current network topology")]
|
|
||||||
NonExistentMixnode { mixnode_identity: String },
|
|
||||||
|
|
||||||
#[error("{raw} is not a valid Nym network recipient: {source}")]
|
|
||||||
MalformedRecipient {
|
|
||||||
raw: String,
|
|
||||||
source: RecipientFormattingError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("{raw} is not a valid Nym AnonymousSenderTag: {source}")]
|
|
||||||
MalformedSenderTag {
|
|
||||||
raw: String,
|
|
||||||
source: InvalidAnonymousSenderTagRepresentation,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmClientError {
|
|
||||||
pub fn into_rejected_promise(self) -> Promise {
|
|
||||||
self.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WasmClientError> for JsValue {
|
|
||||||
fn from(value: WasmClientError) -> Self {
|
|
||||||
simple_js_error(value.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WasmClientError> for Promise {
|
|
||||||
fn from(value: WasmClientError) -> Self {
|
|
||||||
Promise::reject(&value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::WasmClientError;
|
|
||||||
use crate::topology::WasmNymTopology;
|
|
||||||
use js_sys::Promise;
|
|
||||||
use nym_client_core::client::key_manager::KeyManager;
|
|
||||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
|
||||||
use nym_client_core::config;
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
|
||||||
use nym_topology::NymTopology;
|
|
||||||
use nym_validator_client::NymApiClient;
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use url::Url;
|
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
|
||||||
use wasm_bindgen_futures::future_to_promise;
|
|
||||||
use wasm_utils::{console_log, PromisableResult};
|
|
||||||
|
|
||||||
pub(crate) fn setup_new_key_manager() -> KeyManager {
|
|
||||||
let mut rng = OsRng;
|
|
||||||
console_log!("generated new set of keys");
|
|
||||||
KeyManager::new(&mut rng)
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't get too excited about the name, under the hood it's just a big fat placeholder
|
|
||||||
// with no persistence
|
|
||||||
pub(crate) fn setup_reply_surb_storage_backend(
|
|
||||||
config: config::ReplySurbs,
|
|
||||||
) -> browser_backend::Backend {
|
|
||||||
browser_backend::Backend::new(
|
|
||||||
config.minimum_reply_surb_storage_threshold,
|
|
||||||
config.maximum_reply_surb_storage_threshold,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn parse_recipient(recipient: &str) -> Result<Recipient, WasmClientError> {
|
|
||||||
Recipient::try_from_base58_string(recipient).map_err(|source| {
|
|
||||||
WasmClientError::MalformedRecipient {
|
|
||||||
raw: recipient.to_string(),
|
|
||||||
source,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn parse_sender_tag(tag: &str) -> Result<AnonymousSenderTag, WasmClientError> {
|
|
||||||
AnonymousSenderTag::try_from_base58_string(tag).map_err(|source| {
|
|
||||||
WasmClientError::MalformedSenderTag {
|
|
||||||
raw: tag.to_string(),
|
|
||||||
source,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn current_network_topology_async(
|
|
||||||
nym_api_url: String,
|
|
||||||
) -> Result<WasmNymTopology, WasmClientError> {
|
|
||||||
let url: Url = match nym_api_url.parse() {
|
|
||||||
Ok(url) => url,
|
|
||||||
Err(source) => {
|
|
||||||
return Err(WasmClientError::MalformedUrl {
|
|
||||||
raw: nym_api_url,
|
|
||||||
source,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let api_client = NymApiClient::new(url);
|
|
||||||
let mixnodes = api_client.get_cached_active_mixnodes().await?;
|
|
||||||
let gateways = api_client.get_cached_gateways().await?;
|
|
||||||
|
|
||||||
Ok(NymTopology::from_detailed(mixnodes, gateways).into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn current_network_topology(nym_api_url: String) -> Promise {
|
|
||||||
future_to_promise(async move {
|
|
||||||
current_network_topology_async(nym_api_url)
|
|
||||||
.await
|
|
||||||
.into_promise_result()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -7,19 +7,11 @@ use wasm_bindgen::prelude::*;
|
|||||||
mod client;
|
mod client;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub mod encoded_payload_helper;
|
pub mod encoded_payload_helper;
|
||||||
pub mod error;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub mod gateway_selector;
|
pub mod gateway_selector;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub mod tester;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub mod topology;
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
pub mod validation;
|
pub mod validation;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
mod helpers;
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_panic_hook() {
|
pub fn set_panic_hook() {
|
||||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::tester::helpers::NodeTestResult;
|
|
||||||
use crate::tester::NodeTestMessage;
|
|
||||||
use futures::StreamExt;
|
|
||||||
use nym_node_tester_utils::receiver::{Received, ReceivedReceiver};
|
|
||||||
use nym_sphinx::chunking::fragment::FragmentIdentifier;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::sync::MutexGuard as AsyncMutexGuard;
|
|
||||||
use wasm_utils::{console_error, console_log, console_warn};
|
|
||||||
|
|
||||||
pub(crate) struct EphemeralTestReceiver<'a> {
|
|
||||||
sent_packets: u32,
|
|
||||||
expected_acks: HashSet<FragmentIdentifier>,
|
|
||||||
|
|
||||||
received_valid_messages: HashSet<u32>,
|
|
||||||
received_valid_acks: HashSet<FragmentIdentifier>,
|
|
||||||
duplicate_packets: u32,
|
|
||||||
duplicate_acks: u32,
|
|
||||||
|
|
||||||
timeout_duration: Duration,
|
|
||||||
receiver_permit: AsyncMutexGuard<'a, ReceivedReceiver>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> EphemeralTestReceiver<'a> {
|
|
||||||
pub(crate) fn finish(self) -> NodeTestResult {
|
|
||||||
NodeTestResult {
|
|
||||||
sent_packets: self.sent_packets,
|
|
||||||
received_packets: self.received_valid_messages.len() as u32,
|
|
||||||
received_acks: self.received_valid_acks.len() as u32,
|
|
||||||
duplicate_packets: self.duplicate_packets,
|
|
||||||
duplicate_acks: self.duplicate_acks,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn new(
|
|
||||||
sent_packets: u32,
|
|
||||||
expected_acks: HashSet<FragmentIdentifier>,
|
|
||||||
receiver_permit: AsyncMutexGuard<'a, ReceivedReceiver>,
|
|
||||||
timeout: Duration,
|
|
||||||
) -> Self {
|
|
||||||
EphemeralTestReceiver {
|
|
||||||
sent_packets,
|
|
||||||
expected_acks,
|
|
||||||
received_valid_messages: Default::default(),
|
|
||||||
received_valid_acks: Default::default(),
|
|
||||||
duplicate_packets: 0,
|
|
||||||
duplicate_acks: 0,
|
|
||||||
timeout_duration: timeout,
|
|
||||||
receiver_permit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_next_received_packet(&mut self, packet: Option<Received>) -> bool {
|
|
||||||
let Some(received_packet) = packet else {
|
|
||||||
// can't do anything more...
|
|
||||||
console_error!("packet receiver has stopped processing results!");
|
|
||||||
return true
|
|
||||||
};
|
|
||||||
match received_packet {
|
|
||||||
Received::Message(msg) => match NodeTestMessage::try_recover(msg) {
|
|
||||||
Ok(test_msg) => {
|
|
||||||
if !self.received_valid_messages.insert(test_msg.msg_id) {
|
|
||||||
self.duplicate_packets += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
console_warn!("failed to recover test message from received packet: {err}")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Received::Ack(frag_id) => {
|
|
||||||
if self.expected_acks.contains(&frag_id) {
|
|
||||||
if !self.received_valid_acks.insert(frag_id) {
|
|
||||||
self.duplicate_acks += 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console_warn!("received an ack that was not part of the test! (id: {frag_id})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.received_all() {
|
|
||||||
console_log!("already received all the packets! finishing the test...");
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn received_all(&self) -> bool {
|
|
||||||
self.received_valid_acks.len() == self.received_valid_messages.len()
|
|
||||||
&& self.received_valid_acks.len() == self.sent_packets as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn perform_test(mut self) -> NodeTestResult {
|
|
||||||
let mut timeout_fut = wasm_timer::Delay::new(self.timeout_duration);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
_ = &mut timeout_fut => {
|
|
||||||
console_warn!("reached test timeout before receiving all packets.");
|
|
||||||
break
|
|
||||||
}
|
|
||||||
received_packet = self.receiver_permit.next() => {
|
|
||||||
let is_done = self.on_next_received_packet(received_packet);
|
|
||||||
if is_done {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// due to expansion of #[wasm_bindgen] macro on NodeTestResult
|
|
||||||
#![allow(clippy::drop_non_drop)]
|
|
||||||
|
|
||||||
use nym_node_tester_utils::receiver::{Received, ReceivedReceiver};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard};
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use wasm_utils::{console_log, console_warn};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(super) struct ReceivedReceiverWrapper(Arc<AsyncMutex<ReceivedReceiver>>);
|
|
||||||
|
|
||||||
impl ReceivedReceiverWrapper {
|
|
||||||
pub(super) fn new(inner: ReceivedReceiver) -> Self {
|
|
||||||
ReceivedReceiverWrapper(Arc::new(AsyncMutex::new(inner)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn clear_received_channel(&self) {
|
|
||||||
let mut lost_msgs = 0;
|
|
||||||
let mut lost_acks = 0;
|
|
||||||
let mut permit = self.0.lock().await;
|
|
||||||
while let Ok(Some(received)) = permit.try_next() {
|
|
||||||
match received {
|
|
||||||
Received::Message(_) => lost_msgs += 1,
|
|
||||||
Received::Ack(_) => lost_acks += 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if lost_msgs > 0 || lost_acks > 0 {
|
|
||||||
console_warn!("while preparing for the test run, we cleared {lost_msgs} messages and {lost_acks} acks that were received in the meantime.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn lock(&self) -> AsyncMutexGuard<'_, ReceivedReceiver> {
|
|
||||||
self.0.lock().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Copy, Clone)]
|
|
||||||
pub struct WasmTestMessageExt {
|
|
||||||
pub test_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmTestMessageExt {
|
|
||||||
pub fn new(test_id: u32) -> Self {
|
|
||||||
WasmTestMessageExt { test_id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: maybe put it in the tester utils
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct NodeTestResult {
|
|
||||||
pub sent_packets: u32,
|
|
||||||
pub received_packets: u32,
|
|
||||||
pub received_acks: u32,
|
|
||||||
|
|
||||||
pub duplicate_packets: u32,
|
|
||||||
pub duplicate_acks: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for NodeTestResult {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
writeln!(f, "Test results: ")?;
|
|
||||||
writeln!(f, "Total score: {:.2}%", self.score())?;
|
|
||||||
writeln!(f, "Sent packets: {}", self.sent_packets)?;
|
|
||||||
writeln!(f, "Received (valid) packets: {}", self.received_packets)?;
|
|
||||||
writeln!(f, "Received (valid) acks: {}", self.received_acks)?;
|
|
||||||
writeln!(f, "Received duplicate packets: {}", self.duplicate_packets)?;
|
|
||||||
write!(f, "Received duplicate acks: {}", self.duplicate_acks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl NodeTestResult {
|
|
||||||
pub fn log_details(&self) {
|
|
||||||
console_log!("{}", self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn score(&self) -> f32 {
|
|
||||||
let expected = self.sent_packets * 2;
|
|
||||||
let actual = (self.received_packets + self.received_acks)
|
|
||||||
.saturating_sub(self.duplicate_packets + self.duplicate_acks);
|
|
||||||
|
|
||||||
actual as f32 / expected as f32 * 100.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct TestMarker {
|
|
||||||
value: Arc<AtomicBool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestMarker {
|
|
||||||
pub fn new(value: Arc<AtomicBool>) -> Self {
|
|
||||||
Self { value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for TestMarker {
|
|
||||||
// make sure to clear the test flag when the marker is dropped
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.value.store(false, Ordering::SeqCst)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::WasmClientError;
|
|
||||||
use crate::helpers::{current_network_topology_async, setup_new_key_manager};
|
|
||||||
use crate::tester::ephemeral_receiver::EphemeralTestReceiver;
|
|
||||||
use crate::tester::helpers::{
|
|
||||||
NodeTestResult, ReceivedReceiverWrapper, TestMarker, WasmTestMessageExt,
|
|
||||||
};
|
|
||||||
use crate::topology::WasmNymTopology;
|
|
||||||
use futures::channel::mpsc;
|
|
||||||
use js_sys::Promise;
|
|
||||||
use nym_bandwidth_controller::wasm_mockups::{Client as FakeClient, DirectSigningNyxdClient};
|
|
||||||
use nym_bandwidth_controller::BandwidthController;
|
|
||||||
use nym_client_core::client::key_manager::KeyManager;
|
|
||||||
use nym_client_core::config::GatewayEndpointConfig;
|
|
||||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
|
||||||
use nym_crypto::asymmetric::identity;
|
|
||||||
use nym_gateway_client::GatewayClient;
|
|
||||||
use nym_node_tester_utils::receiver::SimpleMessageReceiver;
|
|
||||||
use nym_node_tester_utils::{NodeTester, TestMessage};
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
|
||||||
use nym_sphinx::params::PacketSize;
|
|
||||||
use nym_sphinx::preparer::PreparedFragment;
|
|
||||||
use nym_task::TaskManager;
|
|
||||||
use nym_topology::NymTopology;
|
|
||||||
use rand::rngs::OsRng;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
|
||||||
use std::sync::{Arc, Mutex as SyncMutex};
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::sync::Mutex as AsyncMutex;
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
use wasm_bindgen_futures::future_to_promise;
|
|
||||||
use wasm_utils::{check_promise_result, console_log, console_warn, PromisableResult};
|
|
||||||
|
|
||||||
mod ephemeral_receiver;
|
|
||||||
pub(crate) mod helpers;
|
|
||||||
|
|
||||||
pub type NodeTestMessage = TestMessage<WasmTestMessageExt>;
|
|
||||||
type LockedGatewayClient =
|
|
||||||
Arc<AsyncMutex<GatewayClient<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>>;
|
|
||||||
|
|
||||||
pub(crate) const DEFAULT_TEST_TIMEOUT: Duration = Duration::from_secs(10);
|
|
||||||
pub(crate) const DEFAULT_TEST_PACKETS: u32 = 20;
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct NymNodeTester {
|
|
||||||
test_in_progress: Arc<AtomicBool>,
|
|
||||||
|
|
||||||
// we need to increment the nonce between tests to distinguish the packets
|
|
||||||
// but we can't make the tester mutable because of wasm...
|
|
||||||
// so we're using the atomics
|
|
||||||
current_test_nonce: AtomicU32,
|
|
||||||
|
|
||||||
// blame all those mutexes on being unable to have an async method with internal mutability...
|
|
||||||
tester: Arc<SyncMutex<NodeTester<OsRng>>>,
|
|
||||||
gateway_client: LockedGatewayClient,
|
|
||||||
|
|
||||||
// we have to put it behind the lock due to wasm limitations and borrowing...
|
|
||||||
// the mutex acquisition should be instant as there aren't going to be any threads attempting
|
|
||||||
// to get simultaneous access
|
|
||||||
processed_receiver: ReceivedReceiverWrapper,
|
|
||||||
|
|
||||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
|
||||||
// and if it's dropped, everything will start going offline
|
|
||||||
_task_manager: TaskManager,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct NymNodeTesterBuilder {
|
|
||||||
gateway_config: GatewayEndpointConfig,
|
|
||||||
|
|
||||||
base_topology: NymTopology,
|
|
||||||
|
|
||||||
/// KeyManager object containing smart pointers to all relevant keys used by the client.
|
|
||||||
key_manager: KeyManager,
|
|
||||||
|
|
||||||
// unimplemented
|
|
||||||
bandwidth_controller:
|
|
||||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn address(keys: &KeyManager, gateway_identity: NodeIdentity) -> Recipient {
|
|
||||||
Recipient::new(
|
|
||||||
*keys.identity_keypair().public_key(),
|
|
||||||
*keys.encryption_keypair().public_key(),
|
|
||||||
gateway_identity,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl NymNodeTesterBuilder {
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new(
|
|
||||||
gateway_config: GatewayEndpointConfig,
|
|
||||||
base_topology: WasmNymTopology,
|
|
||||||
) -> NymNodeTesterBuilder {
|
|
||||||
NymNodeTesterBuilder {
|
|
||||||
gateway_config,
|
|
||||||
base_topology: base_topology.into(),
|
|
||||||
key_manager: setup_new_key_manager(),
|
|
||||||
bandwidth_controller: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn _new_with_api(
|
|
||||||
gateway_config: GatewayEndpointConfig,
|
|
||||||
api_url: String,
|
|
||||||
) -> Result<Self, WasmClientError> {
|
|
||||||
let topology = current_network_topology_async(api_url).await?;
|
|
||||||
Ok(NymNodeTesterBuilder::new(gateway_config, topology))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_api(gateway_config: GatewayEndpointConfig, api_url: String) -> Promise {
|
|
||||||
future_to_promise(async move {
|
|
||||||
Self::_new_with_api(gateway_config, api_url)
|
|
||||||
.await
|
|
||||||
.into_promise_result()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn _setup_client(mut self) -> Result<NymNodeTester, WasmClientError> {
|
|
||||||
let rng = OsRng;
|
|
||||||
let task_manager = TaskManager::default();
|
|
||||||
|
|
||||||
let gateway_identity =
|
|
||||||
identity::PublicKey::from_base58_string(self.gateway_config.gateway_id)
|
|
||||||
.map_err(|source| WasmClientError::InvalidGatewayIdentity { source })?;
|
|
||||||
|
|
||||||
// we **REALLY** need persistence...
|
|
||||||
let shared_key = if self.key_manager.is_gateway_key_set() {
|
|
||||||
Some(self.key_manager.gateway_shared_key())
|
|
||||||
} else {
|
|
||||||
console_warn!("Gateway key not set - will derive a fresh one.");
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded();
|
|
||||||
let (ack_sender, ack_receiver) = mpsc::unbounded();
|
|
||||||
|
|
||||||
let mut gateway_client = GatewayClient::new(
|
|
||||||
self.gateway_config.gateway_listener,
|
|
||||||
self.key_manager.identity_keypair(),
|
|
||||||
gateway_identity,
|
|
||||||
shared_key,
|
|
||||||
mixnet_message_sender,
|
|
||||||
ack_sender,
|
|
||||||
Duration::from_secs(10),
|
|
||||||
self.bandwidth_controller.take(),
|
|
||||||
task_manager.subscribe(),
|
|
||||||
);
|
|
||||||
|
|
||||||
gateway_client.set_disabled_credentials_mode(true);
|
|
||||||
let shared_keys = gateway_client.authenticate_and_start().await?;
|
|
||||||
|
|
||||||
// currently pointless but might as well do it for the future ¯\_(ツ)_/¯
|
|
||||||
self.key_manager.insert_gateway_shared_key(shared_keys);
|
|
||||||
|
|
||||||
// TODO: make those values configurable later
|
|
||||||
let tester = NodeTester::new(
|
|
||||||
rng,
|
|
||||||
self.base_topology,
|
|
||||||
address(&self.key_manager, gateway_identity),
|
|
||||||
PacketSize::default(),
|
|
||||||
Duration::from_millis(5),
|
|
||||||
Duration::from_millis(5),
|
|
||||||
self.key_manager.ack_key(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let (processed_sender, processed_receiver) = mpsc::unbounded();
|
|
||||||
|
|
||||||
let mut receiver = SimpleMessageReceiver::new_sphinx_receiver(
|
|
||||||
self.key_manager.encryption_keypair(),
|
|
||||||
self.key_manager.ack_key(),
|
|
||||||
mixnet_message_receiver,
|
|
||||||
ack_receiver,
|
|
||||||
processed_sender,
|
|
||||||
task_manager.subscribe(),
|
|
||||||
);
|
|
||||||
|
|
||||||
nym_task::spawn(async move { receiver.run().await });
|
|
||||||
|
|
||||||
Ok(NymNodeTester {
|
|
||||||
test_in_progress: Arc::new(AtomicBool::new(false)),
|
|
||||||
current_test_nonce: Default::default(),
|
|
||||||
tester: Arc::new(SyncMutex::new(tester)),
|
|
||||||
gateway_client: Arc::new(AsyncMutex::new(gateway_client)),
|
|
||||||
processed_receiver: ReceivedReceiverWrapper::new(processed_receiver),
|
|
||||||
_task_manager: task_manager,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup_client(self) -> Promise {
|
|
||||||
future_to_promise(async move { self._setup_client().await.into_promise_result() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn test_mixnode(
|
|
||||||
test_packets: Vec<PreparedFragment>,
|
|
||||||
gateway_client: LockedGatewayClient,
|
|
||||||
processed_receiver: ReceivedReceiverWrapper,
|
|
||||||
_test_marker: TestMarker,
|
|
||||||
timeout: Duration,
|
|
||||||
) -> Result<NodeTestResult, WasmClientError> {
|
|
||||||
let num_test_packets = test_packets.len() as u32;
|
|
||||||
|
|
||||||
let expected_ack_ids = test_packets
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.fragment_identifier)
|
|
||||||
.collect::<HashSet<_>>();
|
|
||||||
|
|
||||||
let mix_packets = test_packets.into_iter().map(|p| p.mix_packet).collect();
|
|
||||||
|
|
||||||
// start by clearing any messages that might have been received between tests
|
|
||||||
processed_receiver.clear_received_channel().await;
|
|
||||||
|
|
||||||
// locking the gateway client so that we could get mutable access to data without having to declare
|
|
||||||
// self mutable
|
|
||||||
let mut gateway_permit = gateway_client.lock().await;
|
|
||||||
gateway_permit.batch_send_mix_packets(mix_packets).await?;
|
|
||||||
|
|
||||||
let receiver_permit = processed_receiver.lock().await;
|
|
||||||
let result =
|
|
||||||
EphemeralTestReceiver::new(num_test_packets, expected_ack_ids, receiver_permit, timeout)
|
|
||||||
.perform_test()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl NymNodeTester {
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
#[allow(clippy::new_ret_no_self)]
|
|
||||||
pub fn new(gateway_config: GatewayEndpointConfig, topology: WasmNymTopology) -> Promise {
|
|
||||||
console_log!("constructing node tester!");
|
|
||||||
NymNodeTesterBuilder::new(gateway_config, topology).setup_client()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn _new_with_api(
|
|
||||||
gateway_config: GatewayEndpointConfig,
|
|
||||||
api_url: String,
|
|
||||||
) -> Result<Self, WasmClientError> {
|
|
||||||
NymNodeTesterBuilder::_new_with_api(gateway_config, api_url)
|
|
||||||
.await?
|
|
||||||
._setup_client()
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_api(gateway_config: GatewayEndpointConfig, api_url: String) -> Promise {
|
|
||||||
future_to_promise(async move {
|
|
||||||
Self::_new_with_api(gateway_config, api_url)
|
|
||||||
.await
|
|
||||||
.into_promise_result()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_test_packets(
|
|
||||||
&self,
|
|
||||||
mixnode_identity: String,
|
|
||||||
test_nonce: u32,
|
|
||||||
num_test_packets: u32,
|
|
||||||
) -> Result<Vec<PreparedFragment>, WasmClientError> {
|
|
||||||
let test_ext = WasmTestMessageExt::new(test_nonce);
|
|
||||||
let mut tester_permit = self.tester.lock().expect("mutex got poisoned");
|
|
||||||
tester_permit
|
|
||||||
.existing_identity_mixnode_test_packets(mixnode_identity, test_ext, num_test_packets)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_node(
|
|
||||||
&self,
|
|
||||||
mixnode_identity: String,
|
|
||||||
timeout_millis: Option<u64>,
|
|
||||||
num_test_packets: Option<u32>,
|
|
||||||
) -> Promise {
|
|
||||||
// establish test parameters
|
|
||||||
let timeout = timeout_millis
|
|
||||||
.map(Duration::from_millis)
|
|
||||||
.unwrap_or(DEFAULT_TEST_TIMEOUT);
|
|
||||||
let num_test_packets = num_test_packets.unwrap_or(DEFAULT_TEST_PACKETS);
|
|
||||||
|
|
||||||
// mark start of the test
|
|
||||||
if self.test_in_progress.swap(true, Ordering::SeqCst) {
|
|
||||||
return WasmClientError::TestInProgress.into_rejected_promise();
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare test packets
|
|
||||||
// (I simultaneously feel both disgusted and amazed by this workaround)
|
|
||||||
let test_nonce = self.current_test_nonce.fetch_add(1, Ordering::Relaxed);
|
|
||||||
let test_packets = check_promise_result!(self.prepare_test_packets(
|
|
||||||
mixnode_identity,
|
|
||||||
test_nonce,
|
|
||||||
num_test_packets
|
|
||||||
));
|
|
||||||
|
|
||||||
let processed_receiver_clone = self.processed_receiver.clone();
|
|
||||||
let gateway_client_clone = Arc::clone(&self.gateway_client);
|
|
||||||
let tester_marker = TestMarker::new(Arc::clone(&self.test_in_progress));
|
|
||||||
|
|
||||||
// start doing async things (send packets and watch for anything coming back)
|
|
||||||
future_to_promise(async move {
|
|
||||||
test_mixnode(
|
|
||||||
test_packets,
|
|
||||||
gateway_client_clone,
|
|
||||||
processed_receiver_clone,
|
|
||||||
tester_marker,
|
|
||||||
timeout,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.into_promise_result()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use nym_client_core::config::GatewayEndpointConfig;
|
|
||||||
use nym_crypto::asymmetric::{encryption, identity};
|
|
||||||
use nym_topology::gateway::GatewayConversionError;
|
|
||||||
use nym_topology::mix::{Layer, MixnodeConversionError};
|
|
||||||
use nym_topology::{gateway, mix, MixLayer, NymTopology};
|
|
||||||
use nym_validator_client::client::MixId;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use thiserror::Error;
|
|
||||||
use wasm_bindgen::prelude::wasm_bindgen;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
use wasm_utils::{console_log, simple_js_error};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum WasmTopologyError {
|
|
||||||
#[error("got invalid mix layer {value}. Expected 1, 2 or 3.")]
|
|
||||||
InvalidMixLayer { value: u8 },
|
|
||||||
|
|
||||||
#[error(transparent)]
|
|
||||||
GatewayConversion(#[from] GatewayConversionError),
|
|
||||||
|
|
||||||
#[error(transparent)]
|
|
||||||
MixnodeConversion(#[from] MixnodeConversionError),
|
|
||||||
|
|
||||||
#[error("The provided mixnode map was malformed: {source}")]
|
|
||||||
MalformedMixnodeMap { source: serde_wasm_bindgen::Error },
|
|
||||||
|
|
||||||
#[error("The provided gateway list was malformed: {source}")]
|
|
||||||
MalformedGatewayList { source: serde_wasm_bindgen::Error },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WasmTopologyError> for JsValue {
|
|
||||||
fn from(value: WasmTopologyError) -> Self {
|
|
||||||
simple_js_error(value.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WasmNymTopology {
|
|
||||||
inner: NymTopology,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl WasmNymTopology {
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new(
|
|
||||||
// expected: BTreeMap<MixLayer, Vec<WasmMixNode>>,
|
|
||||||
// HashMap<MixLayer, Vec<WasmMixNode>> will also work because it has the same json representation
|
|
||||||
mixnodes: JsValue,
|
|
||||||
// expected: Vec<WasmGateway>
|
|
||||||
gateways: JsValue,
|
|
||||||
) -> Result<WasmNymTopology, WasmTopologyError> {
|
|
||||||
let mixnodes: BTreeMap<MixLayer, Vec<WasmMixNode>> =
|
|
||||||
serde_wasm_bindgen::from_value(mixnodes)
|
|
||||||
.map_err(|source| WasmTopologyError::MalformedMixnodeMap { source })?;
|
|
||||||
|
|
||||||
let gateways: Vec<WasmGateway> = serde_wasm_bindgen::from_value(gateways)
|
|
||||||
.map_err(|source| WasmTopologyError::MalformedGatewayList { source })?;
|
|
||||||
|
|
||||||
let mut converted_mixes = BTreeMap::new();
|
|
||||||
|
|
||||||
for (layer, nodes) in mixnodes {
|
|
||||||
let layer_nodes = nodes
|
|
||||||
.into_iter()
|
|
||||||
.map(TryInto::try_into)
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
converted_mixes.insert(layer, layer_nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
let gateways = gateways
|
|
||||||
.into_iter()
|
|
||||||
.map(TryInto::try_into)
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
Ok(WasmNymTopology {
|
|
||||||
inner: NymTopology::new(converted_mixes, gateways),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool {
|
|
||||||
self.inner
|
|
||||||
.gateways()
|
|
||||||
.iter()
|
|
||||||
.any(|g| g.identity_key.to_base58_string() == gateway_config.gateway_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(&self) {
|
|
||||||
if !self.inner.mixes().is_empty() {
|
|
||||||
console_log!("mixnodes:");
|
|
||||||
for (layer, nodes) in self.inner.mixes() {
|
|
||||||
console_log!("\tlayer {layer}:");
|
|
||||||
for node in nodes {
|
|
||||||
console_log!("\t\t{} - {}", node.mix_id, node.identity_key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console_log!("NO MIXNODES")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.inner.gateways().is_empty() {
|
|
||||||
console_log!("gateways:");
|
|
||||||
for gateway in self.inner.gateways() {
|
|
||||||
console_log!("\t{}", gateway.identity_key)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console_log!("NO GATEWAYS")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WasmNymTopology> for NymTopology {
|
|
||||||
fn from(value: WasmNymTopology) -> Self {
|
|
||||||
value.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NymTopology> for WasmNymTopology {
|
|
||||||
fn from(value: NymTopology) -> Self {
|
|
||||||
WasmNymTopology { inner: value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct WasmMixNode {
|
|
||||||
pub mix_id: MixId,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub owner: String,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub host: String,
|
|
||||||
pub mix_port: u16,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub identity_key: String,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub sphinx_key: String,
|
|
||||||
pub layer: MixLayer,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl WasmMixNode {
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn new(
|
|
||||||
mix_id: MixId,
|
|
||||||
owner: String,
|
|
||||||
host: String,
|
|
||||||
mix_port: u16,
|
|
||||||
identity_key: String,
|
|
||||||
sphinx_key: String,
|
|
||||||
layer: MixLayer,
|
|
||||||
version: String,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
mix_id,
|
|
||||||
owner,
|
|
||||||
host,
|
|
||||||
mix_port,
|
|
||||||
identity_key,
|
|
||||||
sphinx_key,
|
|
||||||
layer,
|
|
||||||
version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<WasmMixNode> for mix::Node {
|
|
||||||
type Error = WasmTopologyError;
|
|
||||||
|
|
||||||
fn try_from(value: WasmMixNode) -> Result<Self, Self::Error> {
|
|
||||||
let host = mix::Node::parse_host(&value.host)?;
|
|
||||||
|
|
||||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
|
||||||
// single time we want to construct a path
|
|
||||||
let mix_host = mix::Node::extract_mix_host(&host, value.mix_port)?;
|
|
||||||
|
|
||||||
Ok(mix::Node {
|
|
||||||
mix_id: value.mix_id,
|
|
||||||
owner: value.owner,
|
|
||||||
host,
|
|
||||||
mix_host,
|
|
||||||
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
|
|
||||||
.map_err(MixnodeConversionError::from)?,
|
|
||||||
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
|
|
||||||
.map_err(MixnodeConversionError::from)?,
|
|
||||||
layer: Layer::try_from(value.layer)
|
|
||||||
.map_err(|_| WasmTopologyError::InvalidMixLayer { value: value.layer })?,
|
|
||||||
version: value.version,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct WasmGateway {
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub owner: String,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub host: String,
|
|
||||||
pub mix_port: u16,
|
|
||||||
pub clients_port: u16,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub identity_key: String,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub sphinx_key: String,
|
|
||||||
#[wasm_bindgen(getter_with_clone)]
|
|
||||||
pub version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
impl WasmGateway {
|
|
||||||
#[wasm_bindgen(constructor)]
|
|
||||||
pub fn new(
|
|
||||||
owner: String,
|
|
||||||
host: String,
|
|
||||||
mix_port: u16,
|
|
||||||
clients_port: u16,
|
|
||||||
identity_key: String,
|
|
||||||
sphinx_key: String,
|
|
||||||
version: String,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
owner,
|
|
||||||
host,
|
|
||||||
mix_port,
|
|
||||||
clients_port,
|
|
||||||
identity_key,
|
|
||||||
sphinx_key,
|
|
||||||
version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<WasmGateway> for gateway::Node {
|
|
||||||
type Error = WasmTopologyError;
|
|
||||||
|
|
||||||
fn try_from(value: WasmGateway) -> Result<Self, Self::Error> {
|
|
||||||
let host = gateway::Node::parse_host(&value.host)?;
|
|
||||||
|
|
||||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
|
||||||
// single time we want to construct a path
|
|
||||||
let mix_host = gateway::Node::extract_mix_host(&host, value.mix_port)?;
|
|
||||||
|
|
||||||
Ok(gateway::Node {
|
|
||||||
owner: value.owner,
|
|
||||||
host,
|
|
||||||
mix_host,
|
|
||||||
clients_port: value.clients_port,
|
|
||||||
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
|
|
||||||
.map_err(GatewayConversionError::from)?,
|
|
||||||
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
|
|
||||||
.map_err(GatewayConversionError::from)?,
|
|
||||||
version: value.version,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,7 +22,7 @@ use crate::client::topology_control::{
|
|||||||
};
|
};
|
||||||
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
use crate::config::{Config, DebugConfig, GatewayEndpointConfig};
|
||||||
use crate::error::ClientCoreError;
|
use crate::error::ClientCoreError;
|
||||||
use crate::{config, spawn_future};
|
use crate::spawn_future;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use nym_bandwidth_controller::BandwidthController;
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
@@ -39,6 +39,7 @@ use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender,
|
|||||||
use nym_task::{TaskClient, TaskManager};
|
use nym_task::{TaskClient, TaskManager};
|
||||||
use nym_topology::provider_trait::TopologyProvider;
|
use nym_topology::provider_trait::TopologyProvider;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
use tap::TapFallible;
|
use tap::TapFallible;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -370,12 +371,11 @@ where
|
|||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
async fn start_topology_refresher(
|
async fn start_topology_refresher(
|
||||||
topology_provider: Box<dyn TopologyProvider>,
|
topology_provider: Box<dyn TopologyProvider>,
|
||||||
topology_config: config::Topology,
|
refresh_rate: Duration,
|
||||||
topology_accessor: TopologyAccessor,
|
topology_accessor: TopologyAccessor,
|
||||||
mut shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> Result<(), ClientCoreError> {
|
) -> Result<(), ClientCoreError> {
|
||||||
let topology_refresher_config =
|
let topology_refresher_config = TopologyRefresherConfig::new(refresh_rate);
|
||||||
TopologyRefresherConfig::new(topology_config.topology_refresh_rate);
|
|
||||||
|
|
||||||
let mut topology_refresher = TopologyRefresher::new(
|
let mut topology_refresher = TopologyRefresher::new(
|
||||||
topology_refresher_config,
|
topology_refresher_config,
|
||||||
@@ -395,21 +395,12 @@ where
|
|||||||
return Err(ClientCoreError::InsufficientNetworkTopology(err));
|
return Err(ClientCoreError::InsufficientNetworkTopology(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
if topology_config.disable_refreshing {
|
info!("Starting topology refresher...");
|
||||||
// if we're not spawning the refresher, don't cause shutdown immediately
|
topology_refresher.start_with_shutdown(shutdown);
|
||||||
info!("The topology refesher is not going to be started");
|
|
||||||
shutdown.mark_as_success();
|
|
||||||
} else {
|
|
||||||
// don't spawn the refresher if we don't want to be refreshing the topology.
|
|
||||||
// only use the initial values obtained
|
|
||||||
info!("Starting topology refresher...");
|
|
||||||
topology_refresher.start_with_shutdown(shutdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// controller for sending packets to mixnet (either real traffic or cover traffic)
|
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
||||||
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
|
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
|
||||||
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
||||||
// requests?
|
// requests?
|
||||||
@@ -509,7 +500,7 @@ where
|
|||||||
);
|
);
|
||||||
Self::start_topology_refresher(
|
Self::start_topology_refresher(
|
||||||
topology_provider,
|
topology_provider,
|
||||||
self.debug_config.topology,
|
self.debug_config.topology.topology_refresh_rate,
|
||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
task_manager.subscribe(),
|
task_manager.subscribe(),
|
||||||
)
|
)
|
||||||
@@ -524,11 +515,11 @@ where
|
|||||||
task_manager.subscribe(),
|
task_manager.subscribe(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// The message_sender is the transmitter for any component generating sphinx packets
|
// The sphinx_message_sender is the transmitter for any component generating sphinx packets
|
||||||
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
||||||
// traffic stream.
|
// traffic stream.
|
||||||
// The MixTrafficController then sends the actual traffic
|
// The MixTrafficController then sends the actual traffic
|
||||||
let message_sender =
|
let sphinx_message_sender =
|
||||||
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
|
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
|
||||||
|
|
||||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||||
@@ -550,7 +541,7 @@ where
|
|||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
ack_receiver,
|
ack_receiver,
|
||||||
input_receiver,
|
input_receiver,
|
||||||
message_sender.clone(),
|
sphinx_message_sender.clone(),
|
||||||
reply_storage,
|
reply_storage,
|
||||||
reply_controller_sender.clone(),
|
reply_controller_sender.clone(),
|
||||||
reply_controller_receiver,
|
reply_controller_receiver,
|
||||||
@@ -569,7 +560,7 @@ where
|
|||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self_address,
|
self_address,
|
||||||
shared_topology_accessor.clone(),
|
shared_topology_accessor.clone(),
|
||||||
message_sender,
|
sphinx_message_sender,
|
||||||
task_manager.subscribe(),
|
task_manager.subscribe(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ where
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
next_delay: Pin<Box<wasm_timer::Delay>>,
|
next_delay: Pin<Box<wasm_timer::Delay>>,
|
||||||
|
|
||||||
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them
|
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||||
/// out to the network without any further delays.
|
/// out to the network without any further delays.
|
||||||
mix_tx: BatchMixMessageSender,
|
mix_tx: BatchMixMessageSender,
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_sphinx::forwarding::packet::MixPacket;
|
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
|
|
||||||
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
||||||
@@ -12,14 +7,6 @@ pub type InputMessageReceiver = tokio::sync::mpsc::Receiver<InputMessage>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InputMessage {
|
pub enum InputMessage {
|
||||||
/// Fire an already prepared mix packets into the network.
|
|
||||||
/// No guarantees are made about it. For example no retransmssion
|
|
||||||
/// will be attempted if it gets dropped.
|
|
||||||
Premade {
|
|
||||||
msgs: Vec<MixPacket>,
|
|
||||||
lane: TransmissionLane,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// The simplest message variant where no additional information is attached.
|
/// The simplest message variant where no additional information is attached.
|
||||||
/// You're simply sending your `data` to specified `recipient` without any tagging.
|
/// You're simply sending your `data` to specified `recipient` without any tagging.
|
||||||
///
|
///
|
||||||
@@ -54,49 +41,14 @@ pub enum InputMessage {
|
|||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
},
|
},
|
||||||
|
|
||||||
MessageWrapper {
|
|
||||||
message: Box<InputMessage>,
|
|
||||||
packet_type: PacketType,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputMessage {
|
impl InputMessage {
|
||||||
pub fn new_premade(
|
pub fn new_regular(recipient: Recipient, data: Vec<u8>, lane: TransmissionLane) -> Self {
|
||||||
msgs: Vec<MixPacket>,
|
InputMessage::Regular {
|
||||||
lane: TransmissionLane,
|
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Self {
|
|
||||||
let message = InputMessage::Premade { msgs, lane };
|
|
||||||
if packet_type == PacketType::Mix {
|
|
||||||
message
|
|
||||||
} else {
|
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_wrapper(message: InputMessage, packet_type: PacketType) -> Self {
|
|
||||||
InputMessage::MessageWrapper {
|
|
||||||
message: Box::new(message),
|
|
||||||
packet_type,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_regular(
|
|
||||||
recipient: Recipient,
|
|
||||||
data: Vec<u8>,
|
|
||||||
lane: TransmissionLane,
|
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Self {
|
|
||||||
let message = InputMessage::Regular {
|
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
};
|
|
||||||
if let Some(packet_type) = packet_type {
|
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
|
||||||
} else {
|
|
||||||
message
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,18 +57,12 @@ impl InputMessage {
|
|||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
reply_surbs: u32,
|
reply_surbs: u32,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let message = InputMessage::Anonymous {
|
InputMessage::Anonymous {
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
reply_surbs,
|
reply_surbs,
|
||||||
lane,
|
lane,
|
||||||
};
|
|
||||||
if let Some(packet_type) = packet_type {
|
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
|
||||||
} else {
|
|
||||||
message
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,17 +70,11 @@ impl InputMessage {
|
|||||||
recipient_tag: AnonymousSenderTag,
|
recipient_tag: AnonymousSenderTag,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let message = InputMessage::Reply {
|
InputMessage::Reply {
|
||||||
recipient_tag,
|
recipient_tag,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
};
|
|
||||||
if let Some(packet_type) = packet_type {
|
|
||||||
InputMessage::new_wrapper(message, packet_type)
|
|
||||||
} else {
|
|
||||||
message
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,9 +82,7 @@ impl InputMessage {
|
|||||||
match self {
|
match self {
|
||||||
InputMessage::Regular { lane, .. }
|
InputMessage::Regular { lane, .. }
|
||||||
| InputMessage::Anonymous { lane, .. }
|
| InputMessage::Anonymous { lane, .. }
|
||||||
| InputMessage::Reply { lane, .. }
|
| InputMessage::Reply { lane, .. } => lane,
|
||||||
| InputMessage::Premade { lane, .. } => lane,
|
|
||||||
InputMessage::MessageWrapper { message, .. } => message.lane(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,15 +39,15 @@ where
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gateway_client: GatewayClient<C, St>,
|
gateway_client: GatewayClient<C, St>,
|
||||||
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
|
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
|
||||||
let (message_sender, message_receiver) =
|
let (sphinx_message_sender, sphinx_message_receiver) =
|
||||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||||
(
|
(
|
||||||
MixTrafficController {
|
MixTrafficController {
|
||||||
gateway_client,
|
gateway_client,
|
||||||
mix_rx: message_receiver,
|
mix_rx: sphinx_message_receiver,
|
||||||
consecutive_gateway_failure_count: 0,
|
consecutive_gateway_failure_count: 0,
|
||||||
},
|
},
|
||||||
message_sender,
|
sphinx_message_sender,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-59
@@ -3,13 +3,10 @@
|
|||||||
|
|
||||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
||||||
use crate::client::real_messages_control::message_handler::MessageHandler;
|
use crate::client::real_messages_control::message_handler::MessageHandler;
|
||||||
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
|
||||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_sphinx::forwarding::packet::MixPacket;
|
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
|
|
||||||
@@ -44,18 +41,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_premade_packets(&mut self, packets: Vec<MixPacket>, lane: TransmissionLane) {
|
|
||||||
self.message_handler
|
|
||||||
.send_premade_mix_packets(
|
|
||||||
packets
|
|
||||||
.into_iter()
|
|
||||||
.map(|p| RealMessage::new(p, None))
|
|
||||||
.collect(),
|
|
||||||
lane,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_reply(
|
async fn handle_reply(
|
||||||
&mut self,
|
&mut self,
|
||||||
recipient_tag: AnonymousSenderTag,
|
recipient_tag: AnonymousSenderTag,
|
||||||
@@ -72,11 +57,10 @@ where
|
|||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
content: Vec<u8>,
|
content: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
|
||||||
) {
|
) {
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.message_handler
|
.message_handler
|
||||||
.try_send_plain_message(recipient, content, lane, packet_type)
|
.try_send_plain_message(recipient, content, lane)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("failed to send a plain message - {err}")
|
warn!("failed to send a plain message - {err}")
|
||||||
@@ -89,11 +73,10 @@ where
|
|||||||
content: Vec<u8>,
|
content: Vec<u8>,
|
||||||
reply_surbs: u32,
|
reply_surbs: u32,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
|
||||||
) {
|
) {
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.message_handler
|
.message_handler
|
||||||
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type)
|
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("failed to send a repliable message - {err}")
|
warn!("failed to send a repliable message - {err}")
|
||||||
@@ -106,17 +89,14 @@ where
|
|||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
lane,
|
lane,
|
||||||
} => {
|
} => self.handle_plain_message(recipient, data, lane).await,
|
||||||
self.handle_plain_message(recipient, data, lane, PacketType::Mix)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
InputMessage::Anonymous {
|
InputMessage::Anonymous {
|
||||||
recipient,
|
recipient,
|
||||||
data,
|
data,
|
||||||
reply_surbs,
|
reply_surbs,
|
||||||
lane,
|
lane,
|
||||||
} => {
|
} => {
|
||||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix)
|
self.handle_repliable_message(recipient, data, reply_surbs, lane)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
InputMessage::Reply {
|
InputMessage::Reply {
|
||||||
@@ -126,41 +106,6 @@ where
|
|||||||
} => {
|
} => {
|
||||||
self.handle_reply(recipient_tag, data, lane).await;
|
self.handle_reply(recipient_tag, data, lane).await;
|
||||||
}
|
}
|
||||||
InputMessage::Premade { msgs, lane } => self.handle_premade_packets(msgs, lane).await,
|
|
||||||
InputMessage::MessageWrapper {
|
|
||||||
message,
|
|
||||||
packet_type,
|
|
||||||
} => match *message {
|
|
||||||
InputMessage::Regular {
|
|
||||||
recipient,
|
|
||||||
data,
|
|
||||||
lane,
|
|
||||||
} => {
|
|
||||||
self.handle_plain_message(recipient, data, lane, packet_type)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
InputMessage::Anonymous {
|
|
||||||
recipient,
|
|
||||||
data,
|
|
||||||
reply_surbs,
|
|
||||||
lane,
|
|
||||||
} => {
|
|
||||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
InputMessage::Reply {
|
|
||||||
recipient_tag,
|
|
||||||
data,
|
|
||||||
lane,
|
|
||||||
} => {
|
|
||||||
self.handle_reply(recipient_tag, data, lane).await;
|
|
||||||
}
|
|
||||||
InputMessage::Premade { msgs, lane } => {
|
|
||||||
self.handle_premade_packets(msgs, lane).await
|
|
||||||
}
|
|
||||||
// MessageWrappers can't be nested
|
|
||||||
InputMessage::MessageWrapper { .. } => unimplemented!(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-8
@@ -11,9 +11,9 @@ use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
|||||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::chunking::fragment::Fragment;
|
use nym_sphinx::chunking::fragment::Fragment;
|
||||||
use nym_sphinx::preparer::PreparedFragment;
|
use nym_sphinx::preparer::PreparedFragment;
|
||||||
use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
|
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
@@ -51,10 +51,8 @@ where
|
|||||||
) -> Result<PreparedFragment, PreparationError> {
|
) -> Result<PreparedFragment, PreparationError> {
|
||||||
debug!("retransmitting normal packet...");
|
debug!("retransmitting normal packet...");
|
||||||
|
|
||||||
// TODO: Figure out retransmission packet type signaling
|
|
||||||
|
|
||||||
self.message_handler
|
self.message_handler
|
||||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, PacketType::Mix)
|
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +131,7 @@ where
|
|||||||
// send to `OutQueueControl` to eventually send to the mix network
|
// send to `OutQueueControl` to eventually send to the mix network
|
||||||
self.message_handler
|
self.message_handler
|
||||||
.forward_messages(
|
.forward_messages(
|
||||||
vec![RealMessage::new(
|
vec![RealMessage::new(prepared_fragment.mix_packet, frag_id)],
|
||||||
prepared_fragment.mix_packet,
|
|
||||||
Some(frag_id),
|
|
||||||
)],
|
|
||||||
TransmissionLane::Retransmission,
|
TransmissionLane::Retransmission,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessa
|
|||||||
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||||
use nym_sphinx::message::NymMessage;
|
use nym_sphinx::message::NymMessage;
|
||||||
use nym_sphinx::params::{PacketSize, PacketType, DEFAULT_NUM_MIX_HOPS};
|
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||||
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||||
use nym_sphinx::Delay;
|
use nym_sphinx::Delay;
|
||||||
use nym_task::connections::TransmissionLane;
|
use nym_task::connections::TransmissionLane;
|
||||||
@@ -291,10 +291,8 @@ where
|
|||||||
.try_prepare_single_reply_chunk_for_sending(reply_surb, chunk_clone)
|
.try_prepare_single_reply_chunk_for_sending(reply_surb, chunk_clone)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let real_messages = RealMessage::new(
|
let real_messages =
|
||||||
prepared_fragment.mix_packet,
|
RealMessage::new(prepared_fragment.mix_packet, chunk.fragment_identifier());
|
||||||
Some(chunk.fragment_identifier()),
|
|
||||||
);
|
|
||||||
let delay = prepared_fragment.total_delay;
|
let delay = prepared_fragment.total_delay;
|
||||||
let pending_ack =
|
let pending_ack =
|
||||||
PendingAcknowledgement::new_anonymous(chunk, delay, target, is_extra_surb_request);
|
PendingAcknowledgement::new_anonymous(chunk, delay, target, is_extra_surb_request);
|
||||||
@@ -386,8 +384,7 @@ where
|
|||||||
let lane = raw.0;
|
let lane = raw.0;
|
||||||
let fragment = raw.1;
|
let fragment = raw.1;
|
||||||
|
|
||||||
let real_message =
|
let real_message = RealMessage::new(prepared.mix_packet, prepared.fragment_identifier);
|
||||||
RealMessage::new(prepared.mix_packet, Some(prepared.fragment_identifier));
|
|
||||||
let delay = prepared.total_delay;
|
let delay = prepared.total_delay;
|
||||||
let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false);
|
let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false);
|
||||||
|
|
||||||
@@ -404,23 +401,14 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn send_premade_mix_packets(
|
|
||||||
&mut self,
|
|
||||||
msgs: Vec<RealMessage>,
|
|
||||||
lane: TransmissionLane,
|
|
||||||
) {
|
|
||||||
self.forward_messages(msgs, lane).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn try_send_plain_message(
|
pub(crate) async fn try_send_plain_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
message: Vec<u8>,
|
message: Vec<u8>,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<(), PreparationError> {
|
) -> Result<(), PreparationError> {
|
||||||
let message = NymMessage::new_plain(message);
|
let message = NymMessage::new_plain(message);
|
||||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +417,6 @@ where
|
|||||||
message: NymMessage,
|
message: NymMessage,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<(), PreparationError> {
|
) -> Result<(), PreparationError> {
|
||||||
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
||||||
debug_assert!(!matches!(message, NymMessage::Reply(_)));
|
debug_assert!(!matches!(message, NymMessage::Reply(_)));
|
||||||
@@ -455,13 +442,10 @@ where
|
|||||||
topology,
|
topology,
|
||||||
&self.config.ack_key,
|
&self.config.ack_key,
|
||||||
&recipient,
|
&recipient,
|
||||||
&packet_type,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let real_message = RealMessage::new(
|
let real_message =
|
||||||
prepared_fragment.mix_packet,
|
RealMessage::new(prepared_fragment.mix_packet, fragment.fragment_identifier());
|
||||||
Some(fragment.fragment_identifier()),
|
|
||||||
);
|
|
||||||
let delay = prepared_fragment.total_delay;
|
let delay = prepared_fragment.total_delay;
|
||||||
let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient);
|
let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient);
|
||||||
|
|
||||||
@@ -479,7 +463,6 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<(), PreparationError> {
|
) -> Result<(), PreparationError> {
|
||||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||||
let (reply_surbs, reply_keys) =
|
let (reply_surbs, reply_keys) =
|
||||||
@@ -494,7 +477,6 @@ where
|
|||||||
message,
|
message,
|
||||||
recipient,
|
recipient,
|
||||||
TransmissionLane::AdditionalReplySurbs,
|
TransmissionLane::AdditionalReplySurbs,
|
||||||
packet_type,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -510,7 +492,6 @@ where
|
|||||||
message: Vec<u8>,
|
message: Vec<u8>,
|
||||||
num_reply_surbs: u32,
|
num_reply_surbs: u32,
|
||||||
lane: TransmissionLane,
|
lane: TransmissionLane,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<(), SurbWrappedPreparationError> {
|
) -> Result<(), SurbWrappedPreparationError> {
|
||||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||||
let (reply_surbs, reply_keys) = self
|
let (reply_surbs, reply_keys) = self
|
||||||
@@ -520,7 +501,7 @@ where
|
|||||||
let message =
|
let message =
|
||||||
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
|
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
|
||||||
|
|
||||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
log::trace!("storing {} reply keys", reply_keys.len());
|
log::trace!("storing {} reply keys", reply_keys.len());
|
||||||
@@ -533,20 +514,13 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
chunk: Fragment,
|
chunk: Fragment,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<PreparedFragment, PreparationError> {
|
) -> Result<PreparedFragment, PreparationError> {
|
||||||
let topology_permit = self.topology_access.get_read_permit().await;
|
let topology_permit = self.topology_access.get_read_permit().await;
|
||||||
let topology = self.get_topology(&topology_permit)?;
|
let topology = self.get_topology(&topology_permit)?;
|
||||||
|
|
||||||
let prepared_fragment = self
|
let prepared_fragment = self
|
||||||
.message_preparer
|
.message_preparer
|
||||||
.prepare_chunk_for_sending(
|
.prepare_chunk_for_sending(chunk, topology, &self.config.ack_key, &recipient)
|
||||||
chunk,
|
|
||||||
topology,
|
|
||||||
&self.config.ack_key,
|
|
||||||
&recipient,
|
|
||||||
&packet_type,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Ok(prepared_fragment)
|
Ok(prepared_fragment)
|
||||||
@@ -582,7 +556,6 @@ where
|
|||||||
topology,
|
topology,
|
||||||
&self.config.ack_key,
|
&self.config.ack_key,
|
||||||
reply_surb,
|
reply_surb,
|
||||||
PacketType::Mix,
|
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
})
|
})
|
||||||
@@ -602,13 +575,7 @@ where
|
|||||||
|
|
||||||
let prepared_fragment = self
|
let prepared_fragment = self
|
||||||
.message_preparer
|
.message_preparer
|
||||||
.prepare_reply_chunk_for_sending(
|
.prepare_reply_chunk_for_sending(chunk, topology, &self.config.ack_key, reply_surb)
|
||||||
chunk,
|
|
||||||
topology,
|
|
||||||
&self.config.ack_key,
|
|
||||||
reply_surb,
|
|
||||||
PacketType::Mix,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Ok(prepared_fragment)
|
Ok(prepared_fragment)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ where
|
|||||||
// messages.
|
// messages.
|
||||||
sending_delay_controller: SendingDelayController,
|
sending_delay_controller: SendingDelayController,
|
||||||
|
|
||||||
/// Channel used for sending prepared packets to `MixTrafficController` that sends them
|
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||||
/// out to the network without any further delays.
|
/// out to the network without any further delays.
|
||||||
mix_tx: BatchMixMessageSender,
|
mix_tx: BatchMixMessageSender,
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ where
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct RealMessage {
|
pub(crate) struct RealMessage {
|
||||||
mix_packet: MixPacket,
|
mix_packet: MixPacket,
|
||||||
fragment_id: Option<FragmentIdentifier>,
|
fragment_id: FragmentIdentifier,
|
||||||
// TODO: add info about it being constructed with reply-surb
|
// TODO: add info about it being constructed with reply-surb
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +129,17 @@ impl From<PreparedFragment> for RealMessage {
|
|||||||
fn from(fragment: PreparedFragment) -> Self {
|
fn from(fragment: PreparedFragment) -> Self {
|
||||||
RealMessage {
|
RealMessage {
|
||||||
mix_packet: fragment.mix_packet,
|
mix_packet: fragment.mix_packet,
|
||||||
fragment_id: Some(fragment.fragment_identifier),
|
fragment_id: fragment.fragment_identifier,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealMessage {
|
impl RealMessage {
|
||||||
pub(crate) fn packet_size(&self) -> usize {
|
pub(crate) fn packet_size(&self) -> usize {
|
||||||
self.mix_packet.packet().len()
|
self.mix_packet.sphinx_packet().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(mix_packet: MixPacket, fragment_id: Option<FragmentIdentifier>) -> Self {
|
pub(crate) fn new(mix_packet: MixPacket, fragment_id: FragmentIdentifier) -> Self {
|
||||||
RealMessage {
|
RealMessage {
|
||||||
mix_packet,
|
mix_packet,
|
||||||
fragment_id,
|
fragment_id,
|
||||||
@@ -255,7 +255,7 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
StreamMessage::Real(real_message) => {
|
StreamMessage::Real(real_message) => {
|
||||||
(real_message.mix_packet, real_message.fragment_id)
|
(real_message.mix_packet, Some(real_message.fragment_id))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ where
|
|||||||
|
|
||||||
// On every iteration we get new messages from upstream. Given that these come bunched
|
// On every iteration we get new messages from upstream. Given that these come bunched
|
||||||
// in `Vec`, this ensures that on average we will fetch messages faster than we can
|
// in `Vec`, this ensures that on average we will fetch messages faster than we can
|
||||||
// send, which is a condition for being able to multiplex packets from multiple
|
// send, which is a condition for being able to multiplex sphinx packets from multiple
|
||||||
// data streams.
|
// data streams.
|
||||||
match Pin::new(&mut self.real_receiver).poll_recv(cx) {
|
match Pin::new(&mut self.real_receiver).poll_recv(cx) {
|
||||||
// in the case our real message channel stream was closed, we should also indicate we are closed
|
// in the case our real message channel stream was closed, we should also indicate we are closed
|
||||||
|
|||||||
@@ -512,11 +512,7 @@ where
|
|||||||
let to_send = min(remaining, 100);
|
let to_send = min(remaining, 100);
|
||||||
if let Err(err) = self
|
if let Err(err) = self
|
||||||
.message_handler
|
.message_handler
|
||||||
.try_send_additional_reply_surbs(
|
.try_send_additional_reply_surbs(recipient, to_send)
|
||||||
recipient,
|
|
||||||
to_send,
|
|
||||||
nym_sphinx::params::PacketType::Mix,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("failed to send additional surbs to {recipient} - {err}");
|
warn!("failed to send additional surbs to {recipient} - {err}");
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ impl SizedData for RealMessage {
|
|||||||
|
|
||||||
impl SizedData for Fragment {
|
impl SizedData for Fragment {
|
||||||
fn data_size(&self) -> usize {
|
fn data_size(&self) -> usize {
|
||||||
// note that raw `Fragment` is smaller than packet payload
|
// note that raw `Fragment` is smaller than sphinx packet payload
|
||||||
// as it doesn't include surb-ack or the [shared] key materials
|
// as it doesn't include surb-ack or the [shared] key materials
|
||||||
self.payload_size()
|
self.payload_size()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use nym_config::defaults::NymNetworkDetails;
|
use nym_config::defaults::NymNetworkDetails;
|
||||||
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
||||||
use nym_sphinx::params::{PacketSize, PacketType};
|
use nym_sphinx::params::PacketSize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -217,11 +217,6 @@ impl<T> Config<T> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
|
|
||||||
self.client.packet_type = Some(packet_type);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_high_default_traffic_volume(&mut self) {
|
pub fn set_high_default_traffic_volume(&mut self) {
|
||||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||||
// basically don't really send cover messages
|
// basically don't really send cover messages
|
||||||
@@ -409,10 +404,6 @@ impl<T> Config<T> {
|
|||||||
pub fn get_maximum_reply_key_age(&self) -> Duration {
|
pub fn get_maximum_reply_key_age(&self) -> Duration {
|
||||||
self.debug.reply_surbs.maximum_reply_key_age
|
self.debug.reply_surbs.maximum_reply_key_age
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_packet_type(&self) -> PacketType {
|
|
||||||
self.client.packet_type.unwrap_or(PacketType::Mix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: NymConfig> Default for Config<T> {
|
impl<T: NymConfig> Default for Config<T> {
|
||||||
@@ -527,8 +518,6 @@ pub struct Client<T> {
|
|||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub super_struct: PhantomData<T>,
|
pub super_struct: PhantomData<T>,
|
||||||
|
|
||||||
pub packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: NymConfig> Default for Client<T> {
|
impl<T: NymConfig> Default for Client<T> {
|
||||||
@@ -567,7 +556,6 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
reply_surb_database_path: Default::default(),
|
reply_surb_database_path: Default::default(),
|
||||||
nym_root_directory: T::default_root_directory(),
|
nym_root_directory: T::default_root_directory(),
|
||||||
super_struct: Default::default(),
|
super_struct: Default::default(),
|
||||||
packet_type: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -755,11 +743,6 @@ pub struct Topology {
|
|||||||
/// did not reach its destination.
|
/// did not reach its destination.
|
||||||
#[serde(with = "humantime_serde")]
|
#[serde(with = "humantime_serde")]
|
||||||
pub topology_resolution_timeout: Duration,
|
pub topology_resolution_timeout: Duration,
|
||||||
|
|
||||||
/// Specifies whether the client should not refresh the network topology after obtaining
|
|
||||||
/// the first valid instance.
|
|
||||||
/// Supersedes `topology_refresh_rate_ms`.
|
|
||||||
pub disable_refreshing: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Topology {
|
impl Default for Topology {
|
||||||
@@ -767,7 +750,6 @@ impl Default for Topology {
|
|||||||
Topology {
|
Topology {
|
||||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||||
disable_refreshing: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ impl From<OldDebugConfigV1_1_13> for DebugConfig {
|
|||||||
topology: Topology {
|
topology: Topology {
|
||||||
topology_refresh_rate: value.topology_refresh_rate,
|
topology_refresh_rate: value.topology_refresh_rate,
|
||||||
topology_resolution_timeout: value.topology_resolution_timeout,
|
topology_resolution_timeout: value.topology_resolution_timeout,
|
||||||
disable_refreshing: false,
|
|
||||||
},
|
},
|
||||||
reply_surbs: ReplySurbs {
|
reply_surbs: ReplySurbs {
|
||||||
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
minimum_reply_surb_storage_threshold: value.minimum_reply_surb_storage_threshold,
|
||||||
@@ -210,8 +209,8 @@ impl<T, U> From<OldConfigV1_1_13<T>> for Config<U> {
|
|||||||
database_path: value.client.database_path,
|
database_path: value.client.database_path,
|
||||||
reply_surb_database_path: value.client.reply_surb_database_path,
|
reply_surb_database_path: value.client.reply_surb_database_path,
|
||||||
nym_root_directory: value.client.nym_root_directory,
|
nym_root_directory: value.client.nym_root_directory,
|
||||||
|
|
||||||
super_struct: PhantomData,
|
super_struct: PhantomData,
|
||||||
packet_type: Some(nym_sphinx::params::PacketType::Mix),
|
|
||||||
},
|
},
|
||||||
logging: value.logging,
|
logging: value.logging,
|
||||||
debug: value.debug.into(),
|
debug: value.debug.into(),
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ where
|
|||||||
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
||||||
packets
|
packets
|
||||||
.iter()
|
.iter()
|
||||||
.map(|packet| packet.packet().len())
|
.map(|packet| packet.sphinx_packet().len())
|
||||||
.sum::<usize>() as i64
|
.sum::<usize>() as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,9 +686,9 @@ where
|
|||||||
if !self.authenticated {
|
if !self.authenticated {
|
||||||
return Err(GatewayClientError::NotAuthenticated);
|
return Err(GatewayClientError::NotAuthenticated);
|
||||||
}
|
}
|
||||||
if (mix_packet.packet().len() as i64) > self.bandwidth_remaining {
|
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||||
mix_packet.packet().len() as i64,
|
mix_packet.sphinx_packet().len() as i64,
|
||||||
self.bandwidth_remaining,
|
self.bandwidth_remaining,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
use nym_sphinx::framing::codec::SphinxCodec;
|
||||||
use nym_sphinx::framing::codec::NymCodec;
|
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
use nym_sphinx::params::PacketMode;
|
||||||
use nym_sphinx::params::PacketType;
|
use nym_sphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
|
||||||
use nym_sphinx::NymPacket;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -51,8 +50,8 @@ pub trait SendWithoutResponse {
|
|||||||
fn send_without_response(
|
fn send_without_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: NymNodeRoutingAddress,
|
address: NymNodeRoutingAddress,
|
||||||
packet: NymPacket,
|
packet: SphinxPacket,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> io::Result<()>;
|
) -> io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,12 +61,12 @@ pub struct Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ConnectionSender {
|
struct ConnectionSender {
|
||||||
channel: mpsc::Sender<FramedNymPacket>,
|
channel: mpsc::Sender<FramedSphinxPacket>,
|
||||||
current_reconnection_attempt: Arc<AtomicU32>,
|
current_reconnection_attempt: Arc<AtomicU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectionSender {
|
impl ConnectionSender {
|
||||||
fn new(channel: mpsc::Sender<FramedNymPacket>) -> Self {
|
fn new(channel: mpsc::Sender<FramedSphinxPacket>) -> Self {
|
||||||
ConnectionSender {
|
ConnectionSender {
|
||||||
channel,
|
channel,
|
||||||
current_reconnection_attempt: Arc::new(AtomicU32::new(0)),
|
current_reconnection_attempt: Arc::new(AtomicU32::new(0)),
|
||||||
@@ -85,7 +84,7 @@ impl Client {
|
|||||||
|
|
||||||
async fn manage_connection(
|
async fn manage_connection(
|
||||||
address: SocketAddr,
|
address: SocketAddr,
|
||||||
receiver: mpsc::Receiver<FramedNymPacket>,
|
receiver: mpsc::Receiver<FramedSphinxPacket>,
|
||||||
connection_timeout: Duration,
|
connection_timeout: Duration,
|
||||||
current_reconnection: &AtomicU32,
|
current_reconnection: &AtomicU32,
|
||||||
) {
|
) {
|
||||||
@@ -97,7 +96,7 @@ impl Client {
|
|||||||
debug!("Managed to establish connection to {}", address);
|
debug!("Managed to establish connection to {}", address);
|
||||||
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
||||||
current_reconnection.store(0, Ordering::Release);
|
current_reconnection.store(0, Ordering::Release);
|
||||||
Framed::new(stream, NymCodec)
|
Framed::new(stream, SphinxCodec)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!(
|
debug!(
|
||||||
@@ -149,7 +148,11 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
fn make_connection(
|
||||||
|
&mut self,
|
||||||
|
address: NymNodeRoutingAddress,
|
||||||
|
pending_packet: FramedSphinxPacket,
|
||||||
|
) {
|
||||||
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||||
|
|
||||||
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
||||||
@@ -197,12 +200,12 @@ impl SendWithoutResponse for Client {
|
|||||||
fn send_without_response(
|
fn send_without_response(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: NymNodeRoutingAddress,
|
address: NymNodeRoutingAddress,
|
||||||
packet: NymPacket,
|
packet: SphinxPacket,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
trace!("Sending packet to {:?}", address);
|
trace!("Sending packet to {:?}", address);
|
||||||
let framed_packet =
|
let framed_packet =
|
||||||
FramedNymPacket::new(packet, packet_type, self.config.use_legacy_version);
|
FramedSphinxPacket::new(packet, packet_mode, self.config.use_legacy_version);
|
||||||
|
|
||||||
if let Some(sender) = self.conn_new.get_mut(&address) {
|
if let Some(sender) = self.conn_new.get_mut(&address) {
|
||||||
if let Err(err) = sender.channel.try_send(framed_packet) {
|
if let Err(err) = sender.channel.try_send(framed_packet) {
|
||||||
|
|||||||
@@ -59,14 +59,14 @@ impl PacketForwarder {
|
|||||||
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
|
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
|
||||||
|
|
||||||
let next_hop = mix_packet.next_hop();
|
let next_hop = mix_packet.next_hop();
|
||||||
let packet_type = mix_packet.packet_type();
|
let packet_mode = mix_packet.packet_mode();
|
||||||
let packet = mix_packet.into_packet();
|
let sphinx_packet = mix_packet.into_sphinx_packet();
|
||||||
// we don't care about responses, we just want to fire packets
|
// we don't care about responses, we just want to fire packets
|
||||||
// as quickly as possible
|
// as quickly as possible
|
||||||
|
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
self.mixnet_client
|
self.mixnet_client
|
||||||
.send_without_response(next_hop, packet, packet_type)
|
.send_without_response(next_hop, sphinx_packet, packet_mode)
|
||||||
{
|
{
|
||||||
debug!("failed to forward the packet - {err}")
|
debug!("failed to forward the packet - {err}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ pub mod nyxd;
|
|||||||
pub mod signing;
|
pub mod signing;
|
||||||
|
|
||||||
pub use crate::error::ValidatorClientError;
|
pub use crate::error::ValidatorClientError;
|
||||||
pub use client::NymApiClient;
|
|
||||||
pub use nym_api_requests::*;
|
pub use nym_api_requests::*;
|
||||||
|
|
||||||
#[cfg(feature = "nyxd-client")]
|
#[cfg(feature = "nyxd-client")]
|
||||||
pub use client::{Client, CoconutApiClient, Config};
|
pub use client::{Client, CoconutApiClient, Config, NymApiClient};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-mixnet-contract-common"
|
name = "nym-mixnet-contract-common"
|
||||||
version = "0.5.0"
|
version = "0.4.0"
|
||||||
description = "Common library for the Nym mixnet contract"
|
description = "Common library for the Nym mixnet contract"
|
||||||
rust-version = "1.62"
|
rust-version = "1.62"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-vesting-contract-common"
|
name = "nym-vesting-contract-common"
|
||||||
version = "0.6.0"
|
version = "0.5.0"
|
||||||
description = "Common library for the Nym vesting contract"
|
description = "Common library for the Nym vesting contract"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -9,7 +9,7 @@ repository = { workspace = true }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cosmwasm-std = { workspace = true }
|
cosmwasm-std = { workspace = true }
|
||||||
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.5.0" }
|
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
|
|||||||
@@ -3,15 +3,12 @@
|
|||||||
|
|
||||||
use nym_sphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
use nym_sphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
||||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddressError;
|
use nym_sphinx_addressing::nodes::NymNodeRoutingAddressError;
|
||||||
use nym_sphinx_types::{NymPacketError, SphinxError};
|
use nym_sphinx_types::Error as SphinxError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum MixProcessingError {
|
pub enum MixProcessingError {
|
||||||
#[error("failed to process received packet: {0}")]
|
#[error("failed to process received packet: {0}")]
|
||||||
NymPacketProcessingError(#[from] NymPacketError),
|
|
||||||
|
|
||||||
#[error("failed to process received sphinx packet: {0}")]
|
|
||||||
SphinxProcessingError(#[from] SphinxError),
|
SphinxProcessingError(#[from] SphinxError),
|
||||||
|
|
||||||
#[error("the forward hop address was malformed: {0}")]
|
#[error("the forward hop address was malformed: {0}")]
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ use log::*;
|
|||||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||||
use nym_sphinx_forwarding::packet::MixPacket;
|
use nym_sphinx_forwarding::packet::MixPacket;
|
||||||
use nym_sphinx_framing::packet::FramedNymPacket;
|
use nym_sphinx_framing::packet::FramedSphinxPacket;
|
||||||
use nym_sphinx_params::{PacketSize, PacketType};
|
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||||
use nym_sphinx_types::{
|
use nym_sphinx_types::{
|
||||||
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, NymPacket, Payload,
|
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, Payload, PrivateKey,
|
||||||
PrivateKey, ProcessedPacket,
|
ProcessedPacket, SphinxPacket,
|
||||||
};
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -53,14 +53,14 @@ impl SphinxPacketProcessor {
|
|||||||
feature = "cpucycles",
|
feature = "cpucycles",
|
||||||
instrument(skip(self, packet), fields(cpucycles))
|
instrument(skip(self, packet), fields(cpucycles))
|
||||||
)]
|
)]
|
||||||
fn perform_initial_packet_processing(
|
fn perform_initial_sphinx_packet_processing(
|
||||||
&self,
|
&self,
|
||||||
packet: NymPacket,
|
packet: SphinxPacket,
|
||||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||||
measure!({
|
measure!({
|
||||||
packet.process(&self.sphinx_key).map_err(|err| {
|
packet.process(&self.sphinx_key).map_err(|err| {
|
||||||
debug!("Failed to unwrap Sphinx packet: {err}");
|
debug!("Failed to unwrap Sphinx packet: {err}");
|
||||||
MixProcessingError::NymPacketProcessingError(err)
|
MixProcessingError::SphinxProcessingError(err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -72,12 +72,17 @@ impl SphinxPacketProcessor {
|
|||||||
)]
|
)]
|
||||||
fn perform_initial_unwrapping(
|
fn perform_initial_unwrapping(
|
||||||
&self,
|
&self,
|
||||||
received: FramedNymPacket,
|
received: FramedSphinxPacket,
|
||||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||||
measure!({
|
measure!({
|
||||||
let packet = received.into_inner();
|
let packet_mode = received.packet_mode();
|
||||||
|
let sphinx_packet = received.into_inner();
|
||||||
|
|
||||||
self.perform_initial_packet_processing(packet)
|
if packet_mode.is_old_vpn() {
|
||||||
|
return Err(MixProcessingError::ReceivedOldTypeVpnPacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.perform_initial_sphinx_packet_processing(sphinx_packet)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,14 +90,14 @@ impl SphinxPacketProcessor {
|
|||||||
/// and packs all the data in a way that can be easily sent to the next hop.
|
/// and packs all the data in a way that can be easily sent to the next hop.
|
||||||
fn process_forward_hop(
|
fn process_forward_hop(
|
||||||
&self,
|
&self,
|
||||||
packet: NymPacket,
|
packet: SphinxPacket,
|
||||||
forward_address: NodeAddressBytes,
|
forward_address: NodeAddressBytes,
|
||||||
delay: SphinxDelay,
|
delay: SphinxDelay,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||||
let next_hop_address = NymNodeRoutingAddress::try_from(forward_address)?;
|
let next_hop_address = NymNodeRoutingAddress::try_from(forward_address)?;
|
||||||
|
|
||||||
let mix_packet = MixPacket::new(next_hop_address, packet, packet_type);
|
let mix_packet = MixPacket::new(next_hop_address, packet, packet_mode);
|
||||||
Ok(MixProcessingResult::ForwardHop(mix_packet, Some(delay)))
|
Ok(MixProcessingResult::ForwardHop(mix_packet, Some(delay)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,25 +124,21 @@ impl SphinxPacketProcessor {
|
|||||||
&self,
|
&self,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
packet_size: PacketSize,
|
packet_size: PacketSize,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> Result<(Option<MixPacket>, Vec<u8>), MixProcessingError> {
|
) -> Result<(Option<MixPacket>, Vec<u8>), MixProcessingError> {
|
||||||
match packet_size {
|
match packet_size {
|
||||||
PacketSize::AckPacket | PacketSize::OutfoxAckPacket => {
|
PacketSize::AckPacket => {
|
||||||
trace!("received an ack packet!");
|
trace!("received an ack packet!");
|
||||||
Ok((None, data))
|
Ok((None, data))
|
||||||
}
|
}
|
||||||
PacketSize::RegularPacket
|
PacketSize::RegularPacket
|
||||||
| PacketSize::ExtendedPacket8
|
| PacketSize::ExtendedPacket8
|
||||||
| PacketSize::ExtendedPacket16
|
| PacketSize::ExtendedPacket16
|
||||||
| PacketSize::ExtendedPacket32
|
| PacketSize::ExtendedPacket32 => {
|
||||||
| PacketSize::OutfoxRegularPacket
|
|
||||||
| PacketSize::OutfoxExtendedPacket8
|
|
||||||
| PacketSize::OutfoxExtendedPacket16
|
|
||||||
| PacketSize::OutfoxExtendedPacket32 => {
|
|
||||||
trace!("received a normal packet!");
|
trace!("received a normal packet!");
|
||||||
let (ack_data, message) = self.split_hop_data_into_ack_and_message(data)?;
|
let (ack_data, message) = self.split_hop_data_into_ack_and_message(data)?;
|
||||||
let (ack_first_hop, ack_packet) = SurbAck::try_recover_first_hop_packet(&ack_data)?;
|
let (ack_first_hop, ack_packet) = SurbAck::try_recover_first_hop_packet(&ack_data)?;
|
||||||
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_type);
|
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_mode);
|
||||||
Ok((Some(forward_ack), message))
|
Ok((Some(forward_ack), message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,12 +152,12 @@ impl SphinxPacketProcessor {
|
|||||||
destination: DestinationAddressBytes,
|
destination: DestinationAddressBytes,
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
packet_size: PacketSize,
|
packet_size: PacketSize,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||||
let packet_message = payload.recover_plaintext()?;
|
let packet_message = payload.recover_plaintext()?;
|
||||||
|
|
||||||
let (forward_ack, message) =
|
let (forward_ack, message) =
|
||||||
self.split_into_ack_and_message(packet_message, packet_size, packet_type)?;
|
self.split_into_ack_and_message(packet_message, packet_size, packet_mode)?;
|
||||||
|
|
||||||
Ok(MixProcessingResult::FinalHop(ProcessedFinalHop {
|
Ok(MixProcessingResult::FinalHop(ProcessedFinalHop {
|
||||||
destination,
|
destination,
|
||||||
@@ -171,16 +172,16 @@ impl SphinxPacketProcessor {
|
|||||||
&self,
|
&self,
|
||||||
packet: ProcessedPacket,
|
packet: ProcessedPacket,
|
||||||
packet_size: PacketSize,
|
packet_size: PacketSize,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||||
match packet {
|
match packet {
|
||||||
ProcessedPacket::ForwardHop(packet, address, delay) => {
|
ProcessedPacket::ForwardHop(packet, address, delay) => {
|
||||||
self.process_forward_hop(NymPacket::Sphinx(*packet), address, delay, packet_type)
|
self.process_forward_hop(*packet, address, delay, packet_mode)
|
||||||
}
|
}
|
||||||
// right now there's no use for the surb_id included in the header - probably it should get removed from the
|
// right now there's no use for the surb_id included in the header - probably it should get removed from the
|
||||||
// sphinx all together?
|
// sphinx all together?
|
||||||
ProcessedPacket::FinalHop(destination, _, payload) => {
|
ProcessedPacket::FinalHop(destination, _, payload) => {
|
||||||
self.process_final_hop(destination, payload, packet_size, packet_type)
|
self.process_final_hop(destination, payload, packet_size, packet_mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,19 +192,19 @@ impl SphinxPacketProcessor {
|
|||||||
)]
|
)]
|
||||||
pub fn process_received(
|
pub fn process_received(
|
||||||
&self,
|
&self,
|
||||||
received: FramedNymPacket,
|
received: FramedSphinxPacket,
|
||||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||||
// explicit packet size will help to correctly parse final hop
|
// explicit packet size will help to correctly parse final hop
|
||||||
measure!({
|
measure!({
|
||||||
let packet_size = received.packet_size();
|
let packet_size = received.packet_size();
|
||||||
let packet_type = received.packet_type();
|
let packet_mode = received.packet_mode();
|
||||||
|
|
||||||
// unwrap the sphinx packet and if possible and appropriate, cache keys
|
// unwrap the sphinx packet and if possible and appropriate, cache keys
|
||||||
let processed_packet = self.perform_initial_unwrapping(received)?;
|
let processed_packet = self.perform_initial_unwrapping(received)?;
|
||||||
|
|
||||||
// for forward packets, extract next hop and set delay (but do NOT delay here)
|
// for forward packets, extract next hop and set delay (but do NOT delay here)
|
||||||
// for final packets, extract SURBAck
|
// for final packets, extract SURBAck
|
||||||
self.perform_final_processing(processed_packet, packet_size, packet_type)
|
self.perform_final_processing(processed_packet, packet_size, packet_mode)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "nym-node-tester-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
futures = "0.3.28"
|
|
||||||
rand = "0.7.3"
|
|
||||||
|
|
||||||
serde = { workspace = true }
|
|
||||||
serde_json = { workspace = true }
|
|
||||||
thiserror = { workspace = true }
|
|
||||||
tokio = { workspace = true, features = ["macros"]}
|
|
||||||
|
|
||||||
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
|
|
||||||
nym-task = { path = "../task" }
|
|
||||||
nym-topology = { path = "../topology" }
|
|
||||||
nym-sphinx-params = { path = "../nymsphinx/params" }
|
|
||||||
# TODO: do we need the whole nymsphinx?
|
|
||||||
nym-sphinx = { path = "../nymsphinx" }
|
|
||||||
|
|
||||||
## non-wasm-only dependencies
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.log]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
## wasm-only dependencies
|
|
||||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasm-utils]
|
|
||||||
path = "../wasm-utils"
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::MixId;
|
|
||||||
use nym_sphinx::chunking::ChunkingError;
|
|
||||||
use nym_sphinx::receiver::MessageRecoveryError;
|
|
||||||
use nym_topology::NymTopologyError;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum NetworkTestingError {
|
|
||||||
#[error(transparent)]
|
|
||||||
SerializationFailure(#[from] serde_json::Error),
|
|
||||||
|
|
||||||
#[error("could not recover received test message: {source}")]
|
|
||||||
MalformedTestMessageReceived { source: serde_json::Error },
|
|
||||||
|
|
||||||
#[error(transparent)]
|
|
||||||
InvalidTopology(#[from] NymTopologyError),
|
|
||||||
|
|
||||||
#[error("The specified mixnode (id: {mix_id}) doesn't exist")]
|
|
||||||
NonExistentMixnode { mix_id: MixId },
|
|
||||||
|
|
||||||
#[error("The specified mixnode (identity: {mix_identity}) doesn't exist")]
|
|
||||||
NonExistentMixnodeIdentity { mix_identity: String },
|
|
||||||
|
|
||||||
#[error("The specified gateway (id: {gateway_identity}) doesn't exist")]
|
|
||||||
NonExistentGateway { gateway_identity: String },
|
|
||||||
|
|
||||||
#[error("The provided test message is too long to fit in a single sphinx packet")]
|
|
||||||
TestMessageTooLong,
|
|
||||||
|
|
||||||
#[error(
|
|
||||||
"could not recover underlying data from the received packet since it was malformed: {source}"
|
|
||||||
)]
|
|
||||||
MalformedPacketReceived {
|
|
||||||
#[from]
|
|
||||||
source: MessageRecoveryError,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[error("Received ack packet could not be recovered")]
|
|
||||||
UnrecoverableAck,
|
|
||||||
|
|
||||||
#[error("could not recover ack FragmentIdentifier: {source}")]
|
|
||||||
MalformedAckIdentifier { source: ChunkingError },
|
|
||||||
|
|
||||||
#[error("received a packet that could not be reconstructed into a full message with a single fragment")]
|
|
||||||
NonReconstructablePacket,
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
pub mod error;
|
|
||||||
pub mod message;
|
|
||||||
pub mod receiver;
|
|
||||||
pub mod tester;
|
|
||||||
|
|
||||||
pub use message::{Empty, TestMessage};
|
|
||||||
pub use tester::NodeTester;
|
|
||||||
|
|
||||||
// it feels wrong to redefine it, but I don't want to import the whole of contract commons just for this one type
|
|
||||||
pub(crate) type MixId = u32;
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log_err {
|
|
||||||
($($t:tt)*) => {{
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
{::wasm_utils::console_error!($($t)*)}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
{::log::error!($($t)*)}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log_warn {
|
|
||||||
($($t:tt)*) => {{
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
{::wasm_utils::console_warn!($($t)*)}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
{::log::warn!($($t)*)}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! log_info {
|
|
||||||
($($t:tt)*) => {{
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
{::wasm_utils::console_log!($($t)*)}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
{::log::info!($($t)*)}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::NetworkTestingError;
|
|
||||||
use crate::MixId;
|
|
||||||
use nym_sphinx::message::NymMessage;
|
|
||||||
use nym_topology::{gateway, mix};
|
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Hash, Clone, Copy)]
|
|
||||||
pub enum NodeType {
|
|
||||||
Mixnode(MixId),
|
|
||||||
Gateway,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Hash, Clone, Copy)]
|
|
||||||
pub struct Empty;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
pub struct TestMessage<T = Empty> {
|
|
||||||
pub encoded_node_identity: String,
|
|
||||||
pub node_owner: String,
|
|
||||||
pub node_type: NodeType,
|
|
||||||
|
|
||||||
pub msg_id: u32,
|
|
||||||
pub total_msgs: u32,
|
|
||||||
|
|
||||||
// any additional fields that might be required by a specific tester.
|
|
||||||
// For example nym-api might want to attach route ids
|
|
||||||
#[serde(flatten)]
|
|
||||||
pub ext: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TestMessage<T> {
|
|
||||||
pub fn new_mix(node: &mix::Node, msg_id: u32, total_msgs: u32, ext: T) -> Self {
|
|
||||||
TestMessage {
|
|
||||||
encoded_node_identity: node.identity_key.to_base58_string(),
|
|
||||||
node_owner: node.owner.clone(),
|
|
||||||
node_type: NodeType::Mixnode(node.mix_id),
|
|
||||||
msg_id,
|
|
||||||
total_msgs,
|
|
||||||
ext,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_gateway(node: &gateway::Node, msg_id: u32, total_msgs: u32, ext: T) -> Self {
|
|
||||||
TestMessage {
|
|
||||||
encoded_node_identity: node.identity_key.to_base58_string(),
|
|
||||||
node_owner: node.owner.clone(),
|
|
||||||
node_type: NodeType::Gateway,
|
|
||||||
msg_id,
|
|
||||||
total_msgs,
|
|
||||||
ext,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_json_string(&self) -> Result<String, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
serde_json::to_string(self).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_bytes(&self) -> Result<Vec<u8>, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
// the test messages are supposed to be rather small so we can use the good old serde_json
|
|
||||||
// (the performance penalty over bincode or custom serialization should be minimal)
|
|
||||||
serde_json::to_vec(self).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recover(msg: NymMessage) -> Result<Self, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
{
|
|
||||||
let inner = msg.into_inner_data();
|
|
||||||
Self::try_recover_from_bytes(&inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recover_from_bytes(raw: &[u8]) -> Result<Self, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: DeserializeOwned,
|
|
||||||
{
|
|
||||||
serde_json::from_slice(raw)
|
|
||||||
.map_err(|source| NetworkTestingError::MalformedTestMessageReceived { source })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Hash> Hash for TestMessage<T> {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.encoded_node_identity.hash(state);
|
|
||||||
self.node_owner.hash(state);
|
|
||||||
self.node_type.hash(state);
|
|
||||||
self.ext.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::NetworkTestingError;
|
|
||||||
use crate::{log_err, log_info, log_warn};
|
|
||||||
use futures::channel::mpsc;
|
|
||||||
use futures::StreamExt;
|
|
||||||
use nym_crypto::asymmetric::encryption;
|
|
||||||
use nym_sphinx::message::NymMessage;
|
|
||||||
use nym_sphinx::receiver::{MessageReceiver, SphinxMessageReceiver};
|
|
||||||
use nym_sphinx::{
|
|
||||||
acknowledgements::{identifier::recover_identifier, AckKey},
|
|
||||||
chunking::fragment::FragmentIdentifier,
|
|
||||||
};
|
|
||||||
use nym_task::TaskClient;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
pub type ReceivedSender = mpsc::UnboundedSender<Received>;
|
|
||||||
pub type ReceivedReceiver = mpsc::UnboundedReceiver<Received>;
|
|
||||||
|
|
||||||
// simple enum containing aggregated processed results
|
|
||||||
pub enum Received {
|
|
||||||
Message(NymMessage),
|
|
||||||
Ack(FragmentIdentifier),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<NymMessage> for Received {
|
|
||||||
fn from(value: NymMessage) -> Self {
|
|
||||||
Received::Message(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FragmentIdentifier> for Received {
|
|
||||||
fn from(value: FragmentIdentifier) -> Self {
|
|
||||||
Received::Ack(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// the 'Simple' bit comes from the fact that it expects all received messages to consist of a single `Fragment`
|
|
||||||
pub struct SimpleMessageReceiver<R: MessageReceiver = SphinxMessageReceiver> {
|
|
||||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
|
||||||
|
|
||||||
ack_key: Arc<AckKey>,
|
|
||||||
|
|
||||||
/// Structure responsible for decrypting and recovering plaintext message from received ciphertexts.
|
|
||||||
message_receiver: R,
|
|
||||||
|
|
||||||
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
|
||||||
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
|
||||||
|
|
||||||
received_sender: ReceivedSender,
|
|
||||||
shutdown: TaskClient,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SimpleMessageReceiver<SphinxMessageReceiver> {
|
|
||||||
pub fn new_sphinx_receiver(
|
|
||||||
local_encryption_keypair: Arc<encryption::KeyPair>,
|
|
||||||
ack_key: Arc<AckKey>,
|
|
||||||
mixnet_message_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
|
||||||
acks_receiver: mpsc::UnboundedReceiver<Vec<Vec<u8>>>,
|
|
||||||
received_sender: ReceivedSender,
|
|
||||||
shutdown: TaskClient,
|
|
||||||
) -> Self {
|
|
||||||
SimpleMessageReceiver {
|
|
||||||
local_encryption_keypair,
|
|
||||||
ack_key,
|
|
||||||
message_receiver: SphinxMessageReceiver::new(),
|
|
||||||
mixnet_message_receiver,
|
|
||||||
acks_receiver,
|
|
||||||
received_sender,
|
|
||||||
shutdown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: MessageReceiver> SimpleMessageReceiver<R> {
|
|
||||||
fn forward_received<T: Into<Received>>(&self, received: T) {
|
|
||||||
// TODO: remove the unwrap once/if we do graceful shutdowns here
|
|
||||||
self.received_sender
|
|
||||||
.unbounded_send(received.into())
|
|
||||||
.expect("ReceivedReceiver has stopped receiving");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_mixnet_message(&mut self, mut raw_message: Vec<u8>) -> Result<(), NetworkTestingError> {
|
|
||||||
let plaintext = self
|
|
||||||
.message_receiver
|
|
||||||
.recover_plaintext_from_regular_packet(
|
|
||||||
self.local_encryption_keypair.private_key(),
|
|
||||||
&mut raw_message,
|
|
||||||
)?;
|
|
||||||
let fragment = self.message_receiver.recover_fragment(plaintext)?;
|
|
||||||
let (recovered, _) = self
|
|
||||||
.message_receiver
|
|
||||||
.insert_new_fragment(fragment)?
|
|
||||||
.ok_or(NetworkTestingError::NonReconstructablePacket)?; // by definition of this receiver, the message must consist of a single fragment
|
|
||||||
|
|
||||||
self.forward_received(recovered);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_ack(&mut self, raw_ack: Vec<u8>) -> Result<(), NetworkTestingError> {
|
|
||||||
let serialized_ack = recover_identifier(&self.ack_key, &raw_ack)
|
|
||||||
.ok_or(NetworkTestingError::UnrecoverableAck)?;
|
|
||||||
|
|
||||||
let frag_id = FragmentIdentifier::try_from_bytes(serialized_ack)
|
|
||||||
.map_err(|source| NetworkTestingError::MalformedAckIdentifier { source })?;
|
|
||||||
|
|
||||||
self.forward_received(frag_id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run(&mut self) {
|
|
||||||
while !self.shutdown.is_shutdown() {
|
|
||||||
tokio::select! {
|
|
||||||
biased;
|
|
||||||
_ = self.shutdown.recv() => {
|
|
||||||
log_info!("SimpleMessageReceiver: received shutdown")
|
|
||||||
}
|
|
||||||
mixnet_messages = self.mixnet_message_receiver.next() => {
|
|
||||||
let Some(mixnet_messages) = mixnet_messages else {
|
|
||||||
log_err!("the mixnet messages stream has terminated!");
|
|
||||||
// note: this will cause global shutdown, but we have no choice if we stopped receiving mixnet messages
|
|
||||||
break
|
|
||||||
};
|
|
||||||
for message in mixnet_messages {
|
|
||||||
if let Err(err) = self.on_mixnet_message(message) {
|
|
||||||
log_warn!("failed to process received mixnet message: {err}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acks = self.acks_receiver.next() => {
|
|
||||||
let Some(acks) = acks else {
|
|
||||||
log_err!("the ack messages stream has terminated!");
|
|
||||||
// note: this will cause global shutdown, but we have no choice if we stopped receiving mixnet messages
|
|
||||||
break
|
|
||||||
};
|
|
||||||
for ack in acks {
|
|
||||||
if let Err(err) = self.on_ack(ack) {
|
|
||||||
log_warn!("failed to process received ack message: {err}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info!("SimpleMessageReceiver: Exiting")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::error::NetworkTestingError;
|
|
||||||
use crate::Empty;
|
|
||||||
use crate::MixId;
|
|
||||||
use crate::TestMessage;
|
|
||||||
use nym_sphinx::acknowledgements::AckKey;
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use nym_sphinx::message::NymMessage;
|
|
||||||
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
|
||||||
use nym_sphinx::preparer::{FragmentPreparer, PreparedFragment};
|
|
||||||
use nym_sphinx_params::PacketType;
|
|
||||||
use nym_topology::{gateway, mix, NymTopology};
|
|
||||||
use rand::{CryptoRng, Rng};
|
|
||||||
use serde::Serialize;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
pub struct NodeTester<R> {
|
|
||||||
rng: R,
|
|
||||||
|
|
||||||
base_topology: NymTopology,
|
|
||||||
|
|
||||||
recipient: Recipient,
|
|
||||||
|
|
||||||
packet_size: PacketSize,
|
|
||||||
|
|
||||||
/// Average delay a data packet is going to get delay at a single mixnode.
|
|
||||||
average_packet_delay: Duration,
|
|
||||||
|
|
||||||
/// Average delay an acknowledgement packet is going to get delay at a single mixnode.
|
|
||||||
average_ack_delay: Duration,
|
|
||||||
|
|
||||||
/// Number of mix hops each packet ('real' message, ack, reply) is expected to take.
|
|
||||||
/// Note that it does not include gateway hops.
|
|
||||||
num_mix_hops: u8,
|
|
||||||
|
|
||||||
// while acks are going to be ignored they still need to be constructed
|
|
||||||
// so that the gateway would be able to correctly process and forward the message
|
|
||||||
ack_key: Arc<AckKey>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> NodeTester<R>
|
|
||||||
where
|
|
||||||
R: Rng + CryptoRng,
|
|
||||||
{
|
|
||||||
pub fn new(
|
|
||||||
rng: R,
|
|
||||||
base_topology: NymTopology,
|
|
||||||
recipient: Recipient,
|
|
||||||
packet_size: PacketSize,
|
|
||||||
average_packet_delay: Duration,
|
|
||||||
average_ack_delay: Duration,
|
|
||||||
ack_key: Arc<AckKey>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
rng,
|
|
||||||
base_topology,
|
|
||||||
recipient,
|
|
||||||
packet_size,
|
|
||||||
average_packet_delay,
|
|
||||||
average_ack_delay,
|
|
||||||
num_mix_hops: DEFAULT_NUM_MIX_HOPS,
|
|
||||||
ack_key,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allows setting non-default number of expected mix hops in the network.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn with_mix_hops(mut self, hops: u8) -> Self {
|
|
||||||
self.num_mix_hops = hops;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn testable_mix_topology(&self, node: &mix::Node) -> NymTopology {
|
|
||||||
let mut topology = self.base_topology.clone();
|
|
||||||
topology.set_mixes_in_layer(node.layer as u8, vec![node.clone()]);
|
|
||||||
topology
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn testable_gateway_topology(&self, gateway: &gateway::Node) -> NymTopology {
|
|
||||||
let mut topology = self.base_topology.clone();
|
|
||||||
topology.set_gateways(vec![gateway.clone()]);
|
|
||||||
topology
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn simple_mixnode_test_packets(
|
|
||||||
&mut self,
|
|
||||||
mix: &mix::Node,
|
|
||||||
test_packets: u32,
|
|
||||||
) -> Result<Vec<PreparedFragment>, NetworkTestingError> {
|
|
||||||
self.mixnode_test_packets(mix, Empty, test_packets)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mixnode_test_packets<T>(
|
|
||||||
&mut self,
|
|
||||||
mix: &mix::Node,
|
|
||||||
msg_ext: T,
|
|
||||||
test_packets: u32,
|
|
||||||
) -> Result<Vec<PreparedFragment>, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize + Clone,
|
|
||||||
{
|
|
||||||
let ephemeral_topology = self.testable_mix_topology(mix);
|
|
||||||
|
|
||||||
let mut packets = Vec::with_capacity(test_packets as usize);
|
|
||||||
for i in 1..=test_packets {
|
|
||||||
let msg = TestMessage::new_mix(mix, i, test_packets, msg_ext.clone());
|
|
||||||
packets.push(self.create_test_packet(&msg, &ephemeral_topology)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(packets)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn existing_mixnode_test_packets<T>(
|
|
||||||
&mut self,
|
|
||||||
mix_id: MixId,
|
|
||||||
msg_ext: T,
|
|
||||||
test_packets: u32,
|
|
||||||
) -> Result<Vec<PreparedFragment>, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize + Clone,
|
|
||||||
{
|
|
||||||
let Some(node) = self.base_topology.find_mix(mix_id) else {
|
|
||||||
return Err(NetworkTestingError::NonExistentMixnode {mix_id})
|
|
||||||
};
|
|
||||||
|
|
||||||
self.mixnode_test_packets(&node.clone(), msg_ext, test_packets)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn existing_identity_mixnode_test_packets<T>(
|
|
||||||
&mut self,
|
|
||||||
encoded_mix_identity: String,
|
|
||||||
msg_ext: T,
|
|
||||||
test_packets: u32,
|
|
||||||
) -> Result<Vec<PreparedFragment>, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize + Clone,
|
|
||||||
{
|
|
||||||
let Some(node) = self.base_topology.find_mix_by_identity(&encoded_mix_identity) else {
|
|
||||||
return Err(NetworkTestingError::NonExistentMixnodeIdentity { mix_identity: encoded_mix_identity })
|
|
||||||
};
|
|
||||||
|
|
||||||
self.mixnode_test_packets(&node.clone(), msg_ext, test_packets)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_test_packet<T>(
|
|
||||||
&mut self,
|
|
||||||
message: &TestMessage<T>,
|
|
||||||
topology: &NymTopology,
|
|
||||||
) -> Result<PreparedFragment, NetworkTestingError>
|
|
||||||
where
|
|
||||||
T: Serialize,
|
|
||||||
{
|
|
||||||
let serialized = message.as_bytes()?;
|
|
||||||
let message = NymMessage::new_plain(serialized);
|
|
||||||
|
|
||||||
let mut fragments = self.pad_and_split_message(message, self.packet_size);
|
|
||||||
|
|
||||||
if fragments.len() != 1 {
|
|
||||||
return Err(NetworkTestingError::TestMessageTooLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: the unwrap here is fine as if the vec was somehow empty
|
|
||||||
// we would have returned the error when checking for its length
|
|
||||||
let fragment = fragments.pop().unwrap();
|
|
||||||
|
|
||||||
// the packet is designed to be sent from ourselves to ourselves
|
|
||||||
let address = self.recipient;
|
|
||||||
|
|
||||||
// TODO: can we avoid this arc clone?
|
|
||||||
let ack_key = Arc::clone(&self.ack_key);
|
|
||||||
Ok(self.prepare_chunk_for_sending(
|
|
||||||
fragment,
|
|
||||||
topology,
|
|
||||||
&ack_key,
|
|
||||||
&address,
|
|
||||||
&address,
|
|
||||||
&PacketType::Mix,
|
|
||||||
)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: CryptoRng + Rng> FragmentPreparer for NodeTester<R> {
|
|
||||||
type Rng = R;
|
|
||||||
|
|
||||||
fn rng(&mut self) -> &mut Self::Rng {
|
|
||||||
&mut self.rng
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_mix_hops(&self) -> u8 {
|
|
||||||
self.num_mix_hops
|
|
||||||
}
|
|
||||||
|
|
||||||
fn average_packet_delay(&self) -> Duration {
|
|
||||||
self.average_packet_delay
|
|
||||||
}
|
|
||||||
|
|
||||||
fn average_ack_delay(&self) -> Duration {
|
|
||||||
self.average_ack_delay
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,11 @@ use nym_sphinx_addressing::nodes::{
|
|||||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||||
use nym_sphinx_params::DEFAULT_NUM_MIX_HOPS;
|
use nym_sphinx_params::DEFAULT_NUM_MIX_HOPS;
|
||||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||||
use nym_sphinx_types::delays::{self, Delay};
|
use nym_sphinx_types::Error as SphinxError;
|
||||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
use nym_sphinx_types::{
|
||||||
|
delays::{self, Delay},
|
||||||
|
SphinxPacket,
|
||||||
|
};
|
||||||
use nym_topology::{NymTopology, NymTopologyError};
|
use nym_topology::{NymTopology, NymTopologyError};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -19,7 +22,7 @@ use std::time;
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub struct SurbAck {
|
pub struct SurbAck {
|
||||||
surb_ack_packet: NymPacket,
|
surb_ack_packet: SphinxPacket,
|
||||||
first_hop_address: NymNodeRoutingAddress,
|
first_hop_address: NymNodeRoutingAddress,
|
||||||
expected_total_delay: Delay,
|
expected_total_delay: Delay,
|
||||||
}
|
}
|
||||||
@@ -32,8 +35,8 @@ pub enum SurbAckRecoveryError {
|
|||||||
#[error("could not extract first hop address information - {0}")]
|
#[error("could not extract first hop address information - {0}")]
|
||||||
InvalidAddress(#[from] NymNodeRoutingAddressError),
|
InvalidAddress(#[from] NymNodeRoutingAddressError),
|
||||||
|
|
||||||
#[error("packet: {0}")]
|
#[error("the contained sphinx packet was not correctly formed - {0}")]
|
||||||
NymPacket(#[from] NymPacketError),
|
InvalidSphinxPacket(#[from] SphinxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurbAck {
|
impl SurbAck {
|
||||||
@@ -55,12 +58,10 @@ impl SurbAck {
|
|||||||
|
|
||||||
let surb_ack_payload = prepare_identifier(rng, ack_key, marshaled_fragment_id);
|
let surb_ack_payload = prepare_identifier(rng, ack_key, marshaled_fragment_id);
|
||||||
|
|
||||||
let surb_ack_packet = NymPacket::Sphinx(
|
let surb_ack_packet = SphinxPacketBuilder::new()
|
||||||
SphinxPacketBuilder::new()
|
.with_payload_size(PacketSize::AckPacket.payload_size())
|
||||||
.with_payload_size(PacketSize::AckPacket.payload_size())
|
.build_packet(surb_ack_payload, &route, &destination, &delays)
|
||||||
.build_packet(surb_ack_payload, &route, &destination, &delays)
|
.unwrap();
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// in our case, the last hop is a gateway that does NOT do any delays
|
// in our case, the last hop is a gateway that does NOT do any delays
|
||||||
let expected_total_delay = delays.iter().take(delays.len() - 1).sum();
|
let expected_total_delay = delays.iter().take(delays.len() - 1).sum();
|
||||||
@@ -84,21 +85,21 @@ impl SurbAck {
|
|||||||
self.expected_total_delay
|
self.expected_total_delay
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_sending(self) -> Result<(Delay, Vec<u8>), SurbAckRecoveryError> {
|
pub fn prepare_for_sending(self) -> (Delay, Vec<u8>) {
|
||||||
// SURB_FIRST_HOP || SURB_ACK
|
// SURB_FIRST_HOP || SURB_ACK
|
||||||
let surb_bytes: Vec<_> = self
|
let surb_bytes: Vec<_> = self
|
||||||
.first_hop_address
|
.first_hop_address
|
||||||
.as_zero_padded_bytes(MAX_NODE_ADDRESS_UNPADDED_LEN)
|
.as_zero_padded_bytes(MAX_NODE_ADDRESS_UNPADDED_LEN)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(self.surb_ack_packet.to_bytes()?.into_iter())
|
.chain(self.surb_ack_packet.to_bytes().into_iter())
|
||||||
.collect();
|
.collect();
|
||||||
Ok((self.expected_total_delay, surb_bytes))
|
(self.expected_total_delay, surb_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// partial reciprocal of `prepare_for_sending` performed by the gateway
|
// partial reciprocal of `prepare_for_sending` performed by the gateway
|
||||||
pub fn try_recover_first_hop_packet(
|
pub fn try_recover_first_hop_packet(
|
||||||
b: &[u8],
|
b: &[u8],
|
||||||
) -> Result<(NymNodeRoutingAddress, NymPacket), SurbAckRecoveryError> {
|
) -> Result<(NymNodeRoutingAddress, SphinxPacket), SurbAckRecoveryError> {
|
||||||
if b.len() != Self::len() {
|
if b.len() != Self::len() {
|
||||||
Err(SurbAckRecoveryError::InvalidPacketSize {
|
Err(SurbAckRecoveryError::InvalidPacketSize {
|
||||||
received: b.len(),
|
received: b.len(),
|
||||||
@@ -110,7 +111,7 @@ impl SurbAck {
|
|||||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||||
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||||
let packet = NymPacket::sphinx_from_bytes(&b[address_offset..])?;
|
let packet = SphinxPacket::from_bytes(&b[address_offset..])?;
|
||||||
|
|
||||||
Ok((address, packet))
|
Ok((address, packet))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use nym_crypto::{generic_array::typenum::Unsigned, Digest};
|
|||||||
use nym_sphinx_addressing::clients::Recipient;
|
use nym_sphinx_addressing::clients::Recipient;
|
||||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||||
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||||
use nym_sphinx_types::{delays, NymPacket, SURBMaterial, SphinxError, SURB};
|
use nym_sphinx_types::{delays, Error as SphinxError, SURBMaterial, SphinxPacket, SURB};
|
||||||
use nym_topology::{NymTopology, NymTopologyError};
|
use nym_topology::{NymTopology, NymTopologyError};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use serde::de::{Error as SerdeError, Visitor};
|
use serde::de::{Error as SerdeError, Visitor};
|
||||||
@@ -173,8 +173,7 @@ impl ReplySurb {
|
|||||||
self,
|
self,
|
||||||
message: M,
|
message: M,
|
||||||
packet_size: PacketSize,
|
packet_size: PacketSize,
|
||||||
_packet_type: PacketType,
|
) -> Result<(SphinxPacket, NymNodeRoutingAddress), ReplySurbError> {
|
||||||
) -> Result<(NymPacket, NymNodeRoutingAddress), ReplySurbError> {
|
|
||||||
let message_bytes = message.as_ref();
|
let message_bytes = message.as_ref();
|
||||||
if message_bytes.len() != packet_size.plaintext_size() {
|
if message_bytes.len() != packet_size.plaintext_size() {
|
||||||
return Err(ReplySurbError::UnpaddedMessageError);
|
return Err(ReplySurbError::UnpaddedMessageError);
|
||||||
@@ -188,6 +187,6 @@ impl ReplySurb {
|
|||||||
|
|
||||||
let first_hop_address = NymNodeRoutingAddress::try_from(first_hop).unwrap();
|
let first_hop_address = NymNodeRoutingAddress::try_from(first_hop).unwrap();
|
||||||
|
|
||||||
Ok((NymPacket::Sphinx(packet), first_hop_address))
|
Ok((packet, first_hop_address))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||||
use nym_crypto::symmetric::stream_cipher;
|
use nym_crypto::symmetric::stream_cipher;
|
||||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||||
use nym_sphinx_acknowledgements::AckKey;
|
use nym_sphinx_acknowledgements::AckKey;
|
||||||
use nym_sphinx_addressing::clients::Recipient;
|
use nym_sphinx_addressing::clients::Recipient;
|
||||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||||
@@ -11,10 +11,10 @@ use nym_sphinx_chunking::fragment::COVER_FRAG_ID;
|
|||||||
use nym_sphinx_forwarding::packet::MixPacket;
|
use nym_sphinx_forwarding::packet::MixPacket;
|
||||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||||
use nym_sphinx_params::{
|
use nym_sphinx_params::{
|
||||||
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketType, DEFAULT_NUM_MIX_HOPS,
|
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketMode, DEFAULT_NUM_MIX_HOPS,
|
||||||
};
|
};
|
||||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||||
use nym_sphinx_types::{delays, NymPacket};
|
use nym_sphinx_types::{delays, Error as SphinxError};
|
||||||
use nym_topology::{NymTopology, NymTopologyError};
|
use nym_topology::{NymTopology, NymTopologyError};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -28,8 +28,8 @@ pub enum CoverMessageError {
|
|||||||
#[error("Could not construct cover message due to invalid topology - {0}")]
|
#[error("Could not construct cover message due to invalid topology - {0}")]
|
||||||
InvalidTopologyError(#[from] NymTopologyError),
|
InvalidTopologyError(#[from] NymTopologyError),
|
||||||
|
|
||||||
#[error("SurbAck: {0}")]
|
#[error("Could not construct a valid sphinx packet - {0}")]
|
||||||
SurbAck(#[from] SurbAckRecoveryError),
|
SphinxError(#[from] SphinxError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_loop_cover_surb_ack<R>(
|
pub fn generate_loop_cover_surb_ack<R>(
|
||||||
@@ -67,7 +67,7 @@ where
|
|||||||
// we don't care about total ack delay - we will not be retransmitting it anyway
|
// we don't care about total ack delay - we will not be retransmitting it anyway
|
||||||
let (_, ack_bytes) =
|
let (_, ack_bytes) =
|
||||||
generate_loop_cover_surb_ack(rng, topology, ack_key, full_address, average_ack_delay)?
|
generate_loop_cover_surb_ack(rng, topology, ack_key, full_address, average_ack_delay)?
|
||||||
.prepare_for_sending()?;
|
.prepare_for_sending();
|
||||||
|
|
||||||
// cover message can't be distinguishable from a normal traffic so we have to go through
|
// cover message can't be distinguishable from a normal traffic so we have to go through
|
||||||
// all the effort of key generation, encryption, etc. Note here we are generating shared key
|
// all the effort of key generation, encryption, etc. Note here we are generating shared key
|
||||||
@@ -111,17 +111,15 @@ where
|
|||||||
let destination = full_address.as_sphinx_destination();
|
let destination = full_address.as_sphinx_destination();
|
||||||
|
|
||||||
// once merged, that's an easy rng injection point for sphinx packets : )
|
// once merged, that's an easy rng injection point for sphinx packets : )
|
||||||
let packet = NymPacket::Sphinx(
|
let packet = SphinxPacketBuilder::new()
|
||||||
SphinxPacketBuilder::new()
|
.with_payload_size(packet_size.payload_size())
|
||||||
.with_payload_size(packet_size.payload_size())
|
.build_packet(packet_payload, &route, &destination, &delays)
|
||||||
.build_packet(packet_payload, &route, &destination, &delays)
|
.unwrap();
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let first_hop_address =
|
let first_hop_address =
|
||||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||||
|
|
||||||
Ok(MixPacket::new(first_hop_address, packet, PacketType::Mix))
|
Ok(MixPacket::new(first_hop_address, packet, PacketMode::Mix))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function used to determine if given message represents a loop cover message.
|
/// Helper function used to determine if given message represents a loop cover message.
|
||||||
|
|||||||
@@ -12,4 +12,3 @@ nym-sphinx-addressing = { path = "../addressing" }
|
|||||||
nym-sphinx-params = { path = "../params" }
|
nym-sphinx-params = { path = "../params" }
|
||||||
nym-sphinx-types = { path = "../types" }
|
nym-sphinx-types = { path = "../types" }
|
||||||
nym-outfox = { path = "../../../nym-outfox" }
|
nym-outfox = { path = "../../../nym-outfox" }
|
||||||
thiserror = "1"
|
|
||||||
|
|||||||
@@ -2,28 +2,42 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
|
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
|
||||||
use nym_sphinx_params::{PacketSize, PacketType};
|
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
use nym_sphinx_types::SphinxPacket;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug)]
|
||||||
pub enum MixPacketFormattingError {
|
pub enum MixPacketFormattingError {
|
||||||
#[error("too few bytes provided to recover from bytes")]
|
|
||||||
TooFewBytesProvided,
|
TooFewBytesProvided,
|
||||||
#[error("provided packet mode is invalid")]
|
InvalidPacketMode,
|
||||||
InvalidPacketType,
|
|
||||||
#[error("received request had invalid size - received {0}")]
|
|
||||||
InvalidPacketSize(usize),
|
InvalidPacketSize(usize),
|
||||||
#[error("address field was incorrectly encoded")]
|
|
||||||
InvalidAddress,
|
InvalidAddress,
|
||||||
#[error("received sphinx packet was malformed")]
|
|
||||||
MalformedSphinxPacket,
|
MalformedSphinxPacket,
|
||||||
#[error("Packet: {0}")]
|
|
||||||
Packet(#[from] NymPacketError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for MixPacketFormattingError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
use MixPacketFormattingError::*;
|
||||||
|
match self {
|
||||||
|
TooFewBytesProvided => write!(f, "Too few bytes provided to recover from bytes"),
|
||||||
|
InvalidAddress => write!(f, "address field was incorrectly encoded"),
|
||||||
|
InvalidPacketSize(actual) =>
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"received request had invalid size. (actual: {}, but expected one of: {} (ACK), {} (REGULAR), {}, {}, {} (EXTENDED))",
|
||||||
|
actual, PacketSize::AckPacket.size(), PacketSize::RegularPacket.size(),
|
||||||
|
PacketSize::ExtendedPacket8.size(), PacketSize::ExtendedPacket16.size(),
|
||||||
|
PacketSize::ExtendedPacket32.size()
|
||||||
|
),
|
||||||
|
MalformedSphinxPacket => write!(f, "received sphinx packet was malformed"),
|
||||||
|
InvalidPacketMode => write!(f, "provided packet mode is invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for MixPacketFormattingError {}
|
||||||
|
|
||||||
impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
||||||
fn from(_: NymNodeRoutingAddressError) -> Self {
|
fn from(_: NymNodeRoutingAddressError) -> Self {
|
||||||
MixPacketFormattingError::InvalidAddress
|
MixPacketFormattingError::InvalidAddress
|
||||||
@@ -32,16 +46,19 @@ impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
|||||||
|
|
||||||
pub struct MixPacket {
|
pub struct MixPacket {
|
||||||
next_hop: NymNodeRoutingAddress,
|
next_hop: NymNodeRoutingAddress,
|
||||||
packet: NymPacket,
|
sphinx_packet: SphinxPacket,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for MixPacket {
|
impl Debug for MixPacket {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"MixPacket to {:?} with packet_type {:?}. Packet {:?}",
|
"MixPacket to {:?} with packet_mode {:?}. Sphinx header: {:?}, payload length: {}",
|
||||||
self.next_hop, self.packet_type, self.packet
|
self.next_hop,
|
||||||
|
self.packet_mode,
|
||||||
|
self.sphinx_packet.header,
|
||||||
|
self.sphinx_packet.payload.len()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,13 +66,13 @@ impl Debug for MixPacket {
|
|||||||
impl MixPacket {
|
impl MixPacket {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
next_hop: NymNodeRoutingAddress,
|
next_hop: NymNodeRoutingAddress,
|
||||||
packet: NymPacket,
|
sphinx_packet: SphinxPacket,
|
||||||
packet_type: PacketType,
|
packet_mode: PacketMode,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
MixPacket {
|
MixPacket {
|
||||||
next_hop,
|
next_hop,
|
||||||
packet,
|
sphinx_packet,
|
||||||
packet_type,
|
packet_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,52 +80,52 @@ impl MixPacket {
|
|||||||
self.next_hop
|
self.next_hop
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn packet(&self) -> &NymPacket {
|
pub fn sphinx_packet(&self) -> &SphinxPacket {
|
||||||
&self.packet
|
&self.sphinx_packet
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_packet(self) -> NymPacket {
|
pub fn into_sphinx_packet(self) -> SphinxPacket {
|
||||||
self.packet
|
self.sphinx_packet
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn packet_type(&self) -> PacketType {
|
pub fn packet_mode(&self) -> PacketMode {
|
||||||
self.packet_type
|
self.packet_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// the message is formatted as follows:
|
// the message is formatted as follows:
|
||||||
// packet_type || FIRST_HOP || packet
|
// PACKET_MODE || FIRST_HOP || SPHINX_PACKET
|
||||||
pub fn try_from_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
|
pub fn try_from_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
|
||||||
let packet_type = match PacketType::try_from(b[0]) {
|
let packet_mode = match PacketMode::try_from(b[0]) {
|
||||||
Ok(mode) => mode,
|
Ok(mode) => mode,
|
||||||
Err(_) => return Err(MixPacketFormattingError::InvalidPacketType),
|
Err(_) => return Err(MixPacketFormattingError::InvalidPacketMode),
|
||||||
};
|
};
|
||||||
|
|
||||||
let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[1..])?;
|
let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[1..])?;
|
||||||
let addr_offset = next_hop.bytes_min_len();
|
let addr_offset = next_hop.bytes_min_len();
|
||||||
|
|
||||||
let packet_data = &b[addr_offset + 1..];
|
let sphinx_packet_data = &b[addr_offset + 1..];
|
||||||
let packet_size = packet_data.len();
|
let packet_size = sphinx_packet_data.len();
|
||||||
if PacketSize::get_type(packet_size).is_err() {
|
if PacketSize::get_type(packet_size).is_err() {
|
||||||
Err(MixPacketFormattingError::InvalidPacketSize(packet_size))
|
Err(MixPacketFormattingError::InvalidPacketSize(packet_size))
|
||||||
} else {
|
} else {
|
||||||
let packet = match packet_type {
|
let sphinx_packet = match SphinxPacket::from_bytes(sphinx_packet_data) {
|
||||||
PacketType::Outfox => NymPacket::outfox_from_bytes(packet_data)?,
|
Ok(packet) => packet,
|
||||||
_ => NymPacket::sphinx_from_bytes(packet_data)?,
|
Err(_) => return Err(MixPacketFormattingError::MalformedSphinxPacket),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(MixPacket {
|
Ok(MixPacket {
|
||||||
next_hop,
|
next_hop,
|
||||||
packet,
|
sphinx_packet,
|
||||||
packet_type,
|
packet_mode,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
|
pub fn into_bytes(self) -> Vec<u8> {
|
||||||
Ok(std::iter::once(self.packet_type as u8)
|
std::iter::once(self.packet_mode as u8)
|
||||||
.chain(self.next_hop.as_bytes().into_iter())
|
.chain(self.next_hop.as_bytes().into_iter())
|
||||||
.chain(self.packet.to_bytes()?.into_iter())
|
.chain(self.sphinx_packet.to_bytes().into_iter())
|
||||||
.collect())
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,65 @@
|
|||||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::packet::{FramedNymPacket, Header};
|
use crate::packet::{FramedSphinxPacket, Header};
|
||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::{Buf, BufMut, BytesMut};
|
||||||
|
use nym_sphinx_params::packet_modes::InvalidPacketMode;
|
||||||
use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
|
use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
|
||||||
use nym_sphinx_params::packet_types::InvalidPacketType;
|
use nym_sphinx_types::Error as SphinxError;
|
||||||
use nym_sphinx_params::PacketType;
|
use nym_sphinx_types::SphinxPacket;
|
||||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio_util::codec::{Decoder, Encoder};
|
use tokio_util::codec::{Decoder, Encoder};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum NymCodecError {
|
pub enum SphinxCodecError {
|
||||||
#[error("the packet size information was malformed - {0}")]
|
#[error("the packet size information was malformed - {0}")]
|
||||||
InvalidPacketSize(#[from] InvalidPacketSize),
|
InvalidPacketSize(#[from] InvalidPacketSize),
|
||||||
|
|
||||||
#[error("the packet mode information was malformed - {0}")]
|
#[error("the packet mode information was malformed - {0}")]
|
||||||
InvalidPacketType(#[from] InvalidPacketType),
|
InvalidPacketMode(#[from] InvalidPacketMode),
|
||||||
|
|
||||||
|
#[error("the actual sphinx packet was malformed - {0}")]
|
||||||
|
MalformedSphinxPacket(#[from] SphinxError),
|
||||||
|
|
||||||
#[error("encountered an IO error - {0}")]
|
#[error("encountered an IO error - {0}")]
|
||||||
IoError(#[from] io::Error),
|
IoError(#[from] io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
#[error("encountered a packet error - {0}")]
|
impl From<SphinxCodecError> for io::Error {
|
||||||
NymPacket(#[from] NymPacketError),
|
fn from(err: SphinxCodecError) -> Self {
|
||||||
|
match err {
|
||||||
#[error("could not convert to bytes")]
|
SphinxCodecError::InvalidPacketSize(source) => {
|
||||||
ToBytes,
|
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||||
|
}
|
||||||
#[error("could not convert to bytes")]
|
SphinxCodecError::InvalidPacketMode(source) => {
|
||||||
FromBytes,
|
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||||
|
}
|
||||||
|
SphinxCodecError::MalformedSphinxPacket(source) => {
|
||||||
|
io::Error::new(io::ErrorKind::InvalidData, source)
|
||||||
|
}
|
||||||
|
SphinxCodecError::IoError(err) => err,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: in the future it could be extended to have state containing symmetric encryption key
|
// TODO: in the future it could be extended to have state containing symmetric encryption key
|
||||||
// so that all data could be encrypted easily (alternatively we could just slap TLS)
|
// so that all data could be encrypted easily (alternatively we could just slap TLS)
|
||||||
pub struct NymCodec;
|
pub struct SphinxCodec;
|
||||||
|
|
||||||
impl Encoder<FramedNymPacket> for NymCodec {
|
impl Encoder<FramedSphinxPacket> for SphinxCodec {
|
||||||
type Error = NymCodecError;
|
type Error = SphinxCodecError;
|
||||||
|
|
||||||
fn encode(&mut self, item: FramedNymPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
fn encode(&mut self, item: FramedSphinxPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||||
item.header.encode(dst);
|
item.header.encode(dst);
|
||||||
let packet_bytes = item.packet.to_bytes()?;
|
dst.put(item.packet.to_bytes().as_ref());
|
||||||
dst.put(packet_bytes.as_slice());
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder for NymCodec {
|
impl Decoder for SphinxCodec {
|
||||||
type Item = FramedNymPacket;
|
type Item = FramedSphinxPacket;
|
||||||
type Error = NymCodecError;
|
type Error = SphinxCodecError;
|
||||||
|
|
||||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
if src.is_empty() {
|
if src.is_empty() {
|
||||||
@@ -66,32 +76,23 @@ impl Decoder for NymCodec {
|
|||||||
None => return Ok(None), // we have some data but not enough to get header back
|
None => return Ok(None), // we have some data but not enough to get header back
|
||||||
};
|
};
|
||||||
|
|
||||||
let packet_size = header.packet_size.size();
|
let sphinx_packet_size = header.packet_size.size();
|
||||||
let frame_len = header.size() + packet_size;
|
let frame_len = header.size() + sphinx_packet_size;
|
||||||
|
|
||||||
if src.len() < frame_len {
|
if src.len() < frame_len {
|
||||||
// we don't have enough bytes to read the rest of frame
|
// we don't have enough bytes to read the rest of frame
|
||||||
src.reserve(packet_size);
|
src.reserve(sphinx_packet_size);
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance buffer past the header - at this point we have enough bytes
|
// advance buffer past the header - at this point we have enough bytes
|
||||||
src.advance(header.size());
|
src.advance(header.size());
|
||||||
let packet_bytes = src.split_to(packet_size);
|
let sphinx_packet_bytes = src.split_to(sphinx_packet_size);
|
||||||
let packet = if let Some(slice) = packet_bytes.get(..) {
|
|
||||||
// here it could be debatable whether stream is corrupt or not,
|
|
||||||
// but let's go with the safer approach and assume it is.
|
|
||||||
match header.packet_type {
|
|
||||||
PacketType::Outfox => NymPacket::outfox_from_bytes(slice)?,
|
|
||||||
PacketType::Mix => NymPacket::sphinx_from_bytes(slice)?,
|
|
||||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(slice)?,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
// let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
// here it could be debatable whether stream is corrupt or not,
|
||||||
let nymsphinx_packet = FramedNymPacket { header, packet };
|
// but let's go with the safer approach and assume it is.
|
||||||
|
let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||||
|
let nymsphinx_packet = FramedSphinxPacket { header, packet };
|
||||||
|
|
||||||
// As per docs:
|
// As per docs:
|
||||||
// Before returning from the function, implementations should ensure that the buffer
|
// Before returning from the function, implementations should ensure that the buffer
|
||||||
@@ -119,6 +120,7 @@ impl Decoder for NymCodec {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
src.reserve(allocate_for_next_packet);
|
src.reserve(allocate_for_next_packet);
|
||||||
|
|
||||||
Ok(Some(nymsphinx_packet))
|
Ok(Some(nymsphinx_packet))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,42 +128,13 @@ impl Decoder for NymCodec {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod packet_encoding {
|
mod packet_encoding {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||||
use nym_sphinx_types::{
|
use nym_sphinx_types::{
|
||||||
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
|
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
|
||||||
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn make_valid_outfox_packet(size: PacketSize) -> NymPacket {
|
fn make_valid_sphinx_packet(size: PacketSize) -> SphinxPacket {
|
||||||
let (_, node1_pk) = crypto::keygen();
|
|
||||||
let node1 = Node::new(
|
|
||||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
|
||||||
node1_pk,
|
|
||||||
);
|
|
||||||
let (_, node2_pk) = crypto::keygen();
|
|
||||||
let node2 = Node::new(
|
|
||||||
NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
|
|
||||||
node2_pk,
|
|
||||||
);
|
|
||||||
let (_, node3_pk) = crypto::keygen();
|
|
||||||
let node3 = Node::new(
|
|
||||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
|
||||||
node3_pk,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (_, node4_pk) = crypto::keygen();
|
|
||||||
let node4 = Node::new(
|
|
||||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
|
||||||
node4_pk,
|
|
||||||
);
|
|
||||||
|
|
||||||
let route = &[node1, node2, node3, node4];
|
|
||||||
|
|
||||||
let payload = vec![1; 48];
|
|
||||||
|
|
||||||
NymPacket::outfox_build(payload, route, Some(size.plaintext_size())).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_valid_sphinx_packet(size: PacketSize) -> NymPacket {
|
|
||||||
let (_, node1_pk) = crypto::keygen();
|
let (_, node1_pk) = crypto::keygen();
|
||||||
let node1 = Node::new(
|
let node1 = Node::new(
|
||||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||||
@@ -188,7 +161,9 @@ mod packet_encoding {
|
|||||||
SphinxDelay::new_from_nanos(42),
|
SphinxDelay::new_from_nanos(42),
|
||||||
SphinxDelay::new_from_nanos(42),
|
SphinxDelay::new_from_nanos(42),
|
||||||
];
|
];
|
||||||
NymPacket::sphinx_build(size.payload_size(), b"foomp", &route, &destination, &delays)
|
SphinxPacketBuilder::new()
|
||||||
|
.with_payload_size(size.payload_size())
|
||||||
|
.build_packet(b"foomp", &route, &destination, &delays)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,50 +171,32 @@ mod packet_encoding {
|
|||||||
fn whole_packet_can_be_decoded_from_a_valid_encoded_instance() {
|
fn whole_packet_can_be_decoded_from_a_valid_encoded_instance() {
|
||||||
let header = Default::default();
|
let header = Default::default();
|
||||||
let sphinx_packet = make_valid_sphinx_packet(Default::default());
|
let sphinx_packet = make_valid_sphinx_packet(Default::default());
|
||||||
let sphinx_bytes = sphinx_packet.to_bytes().unwrap();
|
let sphinx_bytes = sphinx_packet.to_bytes();
|
||||||
|
|
||||||
let packet = FramedNymPacket {
|
let packet = FramedSphinxPacket {
|
||||||
header,
|
header,
|
||||||
packet: sphinx_packet,
|
packet: sphinx_packet,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
let decoded = SphinxCodec.decode(&mut bytes).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(decoded.header, header);
|
assert_eq!(decoded.header, header);
|
||||||
assert_eq!(decoded.packet.to_bytes().unwrap(), sphinx_bytes)
|
assert_eq!(decoded.packet.to_bytes(), sphinx_bytes)
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn whole_outfox_can_be_decoded_from_a_valid_encoded_instance() {
|
|
||||||
let header = Header::outfox();
|
|
||||||
let packet = make_valid_outfox_packet(PacketSize::OutfoxRegularPacket);
|
|
||||||
let packet_bytes = packet.to_bytes().unwrap();
|
|
||||||
|
|
||||||
NymPacket::outfox_from_bytes(packet_bytes.as_slice()).unwrap();
|
|
||||||
|
|
||||||
let packet = FramedNymPacket { header, packet };
|
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
|
||||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
|
||||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(decoded.header, header);
|
|
||||||
assert_eq!(decoded.packet.to_bytes().unwrap(), packet_bytes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod decode_will_allocate_enough_bytes_for_next_call {
|
mod decode_will_allocate_enough_bytes_for_next_call {
|
||||||
use super::*;
|
use super::*;
|
||||||
use nym_sphinx_params::packet_version::PacketVersion;
|
use nym_sphinx_params::packet_version::PacketVersion;
|
||||||
use nym_sphinx_params::PacketType;
|
use nym_sphinx_params::PacketMode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn for_empty_bytes() {
|
fn for_empty_bytes() {
|
||||||
// empty bytes should allocate for header + ack packet
|
// empty bytes should allocate for header + ack packet
|
||||||
let mut empty_bytes = BytesMut::new();
|
let mut empty_bytes = BytesMut::new();
|
||||||
assert!(NymCodec.decode(&mut empty_bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut empty_bytes).unwrap().is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
empty_bytes.capacity(),
|
empty_bytes.capacity(),
|
||||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||||
@@ -260,11 +217,11 @@ mod packet_encoding {
|
|||||||
let header = Header {
|
let header = Header {
|
||||||
packet_version: PacketVersion::Legacy,
|
packet_version: PacketVersion::Legacy,
|
||||||
packet_size,
|
packet_size,
|
||||||
..Default::default()
|
packet_mode: Default::default(),
|
||||||
};
|
};
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
header.encode(&mut bytes);
|
header.encode(&mut bytes);
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||||
|
|
||||||
assert_eq!(bytes.capacity(), Header::LEGACY_SIZE + packet_size.size())
|
assert_eq!(bytes.capacity(), Header::LEGACY_SIZE + packet_size.size())
|
||||||
}
|
}
|
||||||
@@ -284,11 +241,11 @@ mod packet_encoding {
|
|||||||
let header = Header {
|
let header = Header {
|
||||||
packet_version: PacketVersion::Versioned(123),
|
packet_version: PacketVersion::Versioned(123),
|
||||||
packet_size,
|
packet_size,
|
||||||
..Default::default()
|
packet_mode: Default::default(),
|
||||||
};
|
};
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
header.encode(&mut bytes);
|
header.encode(&mut bytes);
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytes.capacity(),
|
bytes.capacity(),
|
||||||
@@ -300,17 +257,18 @@ mod packet_encoding {
|
|||||||
#[test]
|
#[test]
|
||||||
fn for_full_frame_with_legacy_header() {
|
fn for_full_frame_with_legacy_header() {
|
||||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||||
let packet = FramedNymPacket {
|
let packet = FramedSphinxPacket {
|
||||||
header: Header {
|
header: Header {
|
||||||
packet_version: PacketVersion::Legacy,
|
packet_version: PacketVersion::Legacy,
|
||||||
..Default::default()
|
packet_size: Default::default(),
|
||||||
|
packet_mode: Default::default(),
|
||||||
},
|
},
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytes.capacity(),
|
bytes.capacity(),
|
||||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||||
@@ -320,14 +278,14 @@ mod packet_encoding {
|
|||||||
#[test]
|
#[test]
|
||||||
fn for_full_frame_with_versioned_header() {
|
fn for_full_frame_with_versioned_header() {
|
||||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||||
let packet = FramedNymPacket {
|
let packet = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytes.capacity(),
|
bytes.capacity(),
|
||||||
Header::VERSIONED_SIZE + PacketSize::AckPacket.size()
|
Header::VERSIONED_SIZE + PacketSize::AckPacket.size()
|
||||||
@@ -346,19 +304,20 @@ mod packet_encoding {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for packet_size in packet_sizes {
|
for packet_size in packet_sizes {
|
||||||
let first_packet = FramedNymPacket {
|
let first_packet = FramedSphinxPacket {
|
||||||
header: Header {
|
header: Header {
|
||||||
packet_version: PacketVersion::Legacy,
|
packet_version: PacketVersion::Legacy,
|
||||||
..Default::default()
|
packet_size: Default::default(),
|
||||||
|
packet_mode: Default::default(),
|
||||||
},
|
},
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||||
bytes.put_u8(packet_size as u8);
|
bytes.put_u8(packet_size as u8);
|
||||||
bytes.put_u8(PacketType::default() as u8);
|
bytes.put_u8(PacketMode::default() as u8);
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
|
|
||||||
assert!(bytes.capacity() >= Header::LEGACY_SIZE + packet_size.size())
|
assert!(bytes.capacity() >= Header::LEGACY_SIZE + packet_size.size())
|
||||||
}
|
}
|
||||||
@@ -376,53 +335,53 @@ mod packet_encoding {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for packet_size in packet_sizes {
|
for packet_size in packet_sizes {
|
||||||
let first_packet = FramedNymPacket {
|
let first_packet = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||||
bytes.put_u8(PacketVersion::new_versioned(123).as_u8().unwrap());
|
bytes.put_u8(PacketVersion::new_versioned(123).as_u8().unwrap());
|
||||||
bytes.put_u8(packet_size as u8);
|
bytes.put_u8(packet_size as u8);
|
||||||
bytes.put_u8(PacketType::default() as u8);
|
bytes.put_u8(PacketMode::default() as u8);
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
|
|
||||||
// assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_decode_two_packets_immediately() {
|
fn can_decode_two_packets_immediately() {
|
||||||
let packet1 = FramedNymPacket {
|
let packet1 = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let packet2 = FramedNymPacket {
|
let packet2 = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
|
|
||||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||||
NymCodec.encode(packet2, &mut bytes).unwrap();
|
SphinxCodec.encode(packet2, &mut bytes).unwrap();
|
||||||
|
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_decode_two_packets_in_separate_calls() {
|
fn can_decode_two_packets_in_separate_calls() {
|
||||||
let packet1 = FramedNymPacket {
|
let packet1 = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let packet2 = FramedNymPacket {
|
let packet2 = FramedSphinxPacket {
|
||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
packet: make_valid_sphinx_packet(Default::default()),
|
packet: make_valid_sphinx_packet(Default::default()),
|
||||||
};
|
};
|
||||||
@@ -430,17 +389,18 @@ mod packet_encoding {
|
|||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
let mut bytes_tmp = BytesMut::new();
|
let mut bytes_tmp = BytesMut::new();
|
||||||
|
|
||||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||||
NymCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
SphinxCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
||||||
|
|
||||||
let tmp = bytes_tmp.split_off(100);
|
let tmp = bytes_tmp.split_off(100);
|
||||||
bytes.put(bytes_tmp);
|
bytes.put(bytes_tmp);
|
||||||
|
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||||
|
|
||||||
bytes.put(tmp);
|
bytes.put(tmp);
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
|
||||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||||
|
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,47 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::codec::NymCodecError;
|
use crate::codec::SphinxCodecError;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||||
use nym_sphinx_params::packet_version::PacketVersion;
|
use nym_sphinx_params::packet_version::PacketVersion;
|
||||||
use nym_sphinx_params::PacketType;
|
use nym_sphinx_params::PacketMode;
|
||||||
use nym_sphinx_types::NymPacket;
|
use nym_sphinx_types::SphinxPacket;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub struct FramedSphinxPacket {
|
||||||
pub struct FramedNymPacket {
|
|
||||||
/// Contains any metadata helping receiver to handle the underlying packet.
|
/// Contains any metadata helping receiver to handle the underlying packet.
|
||||||
pub(crate) header: Header,
|
pub(crate) header: Header,
|
||||||
|
|
||||||
/// The actual SphinxPacket being sent.
|
/// The actual SphinxPacket being sent.
|
||||||
pub(crate) packet: NymPacket,
|
pub(crate) packet: SphinxPacket,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FramedNymPacket {
|
impl FramedSphinxPacket {
|
||||||
pub fn new(packet: NymPacket, packet_type: PacketType, use_legacy_version: bool) -> Self {
|
pub fn new(packet: SphinxPacket, packet_mode: PacketMode, use_legacy_version: bool) -> Self {
|
||||||
// If this fails somebody is using the library in a super incorrect way, because they
|
// If this fails somebody is using the library in a super incorrect way, because they
|
||||||
// already managed to somehow create a sphinx packet
|
// already managed to somehow create a sphinx packet
|
||||||
let packet_size = PacketSize::get_type(packet.len()).unwrap();
|
let packet_size = PacketSize::get_type(packet.len()).unwrap();
|
||||||
|
|
||||||
FramedNymPacket {
|
FramedSphinxPacket {
|
||||||
header: Header {
|
header: Header {
|
||||||
packet_version: PacketVersion::new(use_legacy_version),
|
packet_version: PacketVersion::new(use_legacy_version),
|
||||||
packet_size,
|
packet_size,
|
||||||
packet_type,
|
packet_mode,
|
||||||
},
|
},
|
||||||
packet,
|
packet,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header(&self) -> Header {
|
|
||||||
self.header
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn packet_size(&self) -> PacketSize {
|
pub fn packet_size(&self) -> PacketSize {
|
||||||
self.header.packet_size
|
self.header.packet_size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn packet_type(&self) -> PacketType {
|
pub fn packet_mode(&self) -> PacketMode {
|
||||||
self.header.packet_type
|
self.header.packet_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self) -> NymPacket {
|
pub fn into_inner(self) -> SphinxPacket {
|
||||||
self.packet
|
self.packet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,23 +64,15 @@ pub struct Header {
|
|||||||
///
|
///
|
||||||
/// TODO: ask @AP whether this can be sent like this - could it introduce some anonymity issues?
|
/// TODO: ask @AP whether this can be sent like this - could it introduce some anonymity issues?
|
||||||
/// (note: this will be behind some encryption, either something implemented by us or some SSL action)
|
/// (note: this will be behind some encryption, either something implemented by us or some SSL action)
|
||||||
// Note: currently packet_type is deprecated but is still left as a concept behind to not break
|
// Note: currently packet_mode is deprecated but is still left as a concept behind to not break
|
||||||
// compatibility with existing network
|
// compatibility with existing network
|
||||||
pub(crate) packet_type: PacketType,
|
pub(crate) packet_mode: PacketMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
pub(crate) const LEGACY_SIZE: usize = 2;
|
pub(crate) const LEGACY_SIZE: usize = 2;
|
||||||
pub(crate) const VERSIONED_SIZE: usize = 3;
|
pub(crate) const VERSIONED_SIZE: usize = 3;
|
||||||
|
|
||||||
pub fn outfox() -> Header {
|
|
||||||
Header {
|
|
||||||
packet_version: PacketVersion::default(),
|
|
||||||
packet_size: PacketSize::OutfoxRegularPacket,
|
|
||||||
packet_type: PacketType::Outfox,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn size(&self) -> usize {
|
pub(crate) fn size(&self) -> usize {
|
||||||
if self.packet_version.is_legacy() {
|
if self.packet_version.is_legacy() {
|
||||||
Self::LEGACY_SIZE
|
Self::LEGACY_SIZE
|
||||||
@@ -103,12 +90,12 @@ impl Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dst.put_u8(self.packet_size as u8);
|
dst.put_u8(self.packet_size as u8);
|
||||||
dst.put_u8(self.packet_type as u8);
|
dst.put_u8(self.packet_mode as u8);
|
||||||
// reserve bytes for the actual packet
|
// reserve bytes for the actual packet
|
||||||
dst.reserve(self.packet_size.size());
|
dst.reserve(self.packet_size.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, NymCodecError> {
|
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, SphinxCodecError> {
|
||||||
if src.len() < Self::LEGACY_SIZE {
|
if src.len() < Self::LEGACY_SIZE {
|
||||||
// can't do anything if we don't have enough bytes - but reserve enough for the next call
|
// can't do anything if we don't have enough bytes - but reserve enough for the next call
|
||||||
src.reserve(Self::LEGACY_SIZE);
|
src.reserve(Self::LEGACY_SIZE);
|
||||||
@@ -120,7 +107,7 @@ impl Header {
|
|||||||
Ok(Some(Header {
|
Ok(Some(Header {
|
||||||
packet_version,
|
packet_version,
|
||||||
packet_size: PacketSize::try_from(src[0])?,
|
packet_size: PacketSize::try_from(src[0])?,
|
||||||
packet_type: PacketType::try_from(src[1])?,
|
packet_mode: PacketMode::try_from(src[1])?,
|
||||||
}))
|
}))
|
||||||
} else if src.len() < Self::VERSIONED_SIZE {
|
} else if src.len() < Self::VERSIONED_SIZE {
|
||||||
// we're missing that 1 byte to read the full header...
|
// we're missing that 1 byte to read the full header...
|
||||||
@@ -130,7 +117,7 @@ impl Header {
|
|||||||
Ok(Some(Header {
|
Ok(Some(Header {
|
||||||
packet_version,
|
packet_version,
|
||||||
packet_size: PacketSize::try_from(src[1])?,
|
packet_size: PacketSize::try_from(src[1])?,
|
||||||
packet_type: PacketType::try_from(src[2])?,
|
packet_mode: PacketMode::try_from(src[2])?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +148,7 @@ mod header_encoding {
|
|||||||
[
|
[
|
||||||
PacketVersion::new_versioned(123).as_u8().unwrap(),
|
PacketVersion::new_versioned(123).as_u8().unwrap(),
|
||||||
unknown_packet_size,
|
unknown_packet_size,
|
||||||
PacketType::default() as u8,
|
PacketMode::default() as u8,
|
||||||
]
|
]
|
||||||
.as_ref(),
|
.as_ref(),
|
||||||
);
|
);
|
||||||
@@ -169,12 +156,12 @@ mod header_encoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decoding_will_fail_for_unknown_packet_type() {
|
fn decoding_will_fail_for_unknown_packet_mode() {
|
||||||
let unknown_packet_type: u8 = 255;
|
let unknown_packet_mode: u8 = 255;
|
||||||
// make sure this is still 'unknown' for if we make changes in the future
|
// make sure this is still 'unknown' for if we make changes in the future
|
||||||
assert!(PacketType::try_from(unknown_packet_type).is_err());
|
assert!(PacketMode::try_from(unknown_packet_mode).is_err());
|
||||||
|
|
||||||
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_type].as_ref());
|
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_mode].as_ref());
|
||||||
assert!(Header::decode(&mut bytes).is_err())
|
assert!(Header::decode(&mut bytes).is_err())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +191,7 @@ mod header_encoding {
|
|||||||
let header = Header {
|
let header = Header {
|
||||||
packet_version: PacketVersion::Legacy,
|
packet_version: PacketVersion::Legacy,
|
||||||
packet_size,
|
packet_size,
|
||||||
..Default::default()
|
packet_mode: Default::default(),
|
||||||
};
|
};
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
header.encode(&mut bytes);
|
header.encode(&mut bytes);
|
||||||
@@ -225,7 +212,7 @@ mod header_encoding {
|
|||||||
let header = Header {
|
let header = Header {
|
||||||
packet_version: PacketVersion::Versioned(123),
|
packet_version: PacketVersion::Versioned(123),
|
||||||
packet_size,
|
packet_size,
|
||||||
..Default::default()
|
packet_mode: Default::default(),
|
||||||
};
|
};
|
||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
header.encode(&mut bytes);
|
header.encode(&mut bytes);
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ use nym_crypto::ctr;
|
|||||||
type Aes128Ctr = ctr::Ctr64BE<Aes128>;
|
type Aes128Ctr = ctr::Ctr64BE<Aes128>;
|
||||||
|
|
||||||
// Re-export for ease of use
|
// Re-export for ease of use
|
||||||
|
pub use packet_modes::PacketMode;
|
||||||
pub use packet_sizes::PacketSize;
|
pub use packet_sizes::PacketSize;
|
||||||
pub use packet_types::PacketType;
|
|
||||||
|
|
||||||
|
pub mod packet_modes;
|
||||||
pub mod packet_sizes;
|
pub mod packet_sizes;
|
||||||
pub mod packet_types;
|
|
||||||
pub mod packet_version;
|
pub mod packet_version;
|
||||||
|
|
||||||
// If somebody can provide an argument why it might be reasonable to have more than 255 mix hops,
|
// If somebody can provide an argument why it might be reasonable to have more than 255 mix hops,
|
||||||
@@ -29,7 +29,7 @@ pub type SerializedFragmentIdentifier = [u8; FRAG_ID_LEN];
|
|||||||
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
|
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
|
||||||
// - packet_version (starting with v1.1.0)
|
// - packet_version (starting with v1.1.0)
|
||||||
// - packet_size indicator
|
// - packet_size indicator
|
||||||
// - packet_type
|
// - packet_mode
|
||||||
// it also just so happens that the only valid values for packet_size indicator include values 1-6
|
// it also just so happens that the only valid values for packet_size indicator include values 1-6
|
||||||
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
|
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
|
||||||
// otherwise we should treat it as legacy
|
// otherwise we should treat it as legacy
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("{received} is not a valid packet mode tag")]
|
||||||
|
pub struct InvalidPacketMode {
|
||||||
|
received: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||||
|
pub enum PacketMode {
|
||||||
|
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||||
|
/// value at each hop.
|
||||||
|
#[default]
|
||||||
|
Mix = 0,
|
||||||
|
|
||||||
|
/// Represents a VPN packet that should not be delayed and ideally cached pre-computed keys
|
||||||
|
/// should be used for unwrapping data. Note that it does not offer the same level of anonymity.
|
||||||
|
Vpn = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketMode {
|
||||||
|
pub fn is_mix(self) -> bool {
|
||||||
|
self == PacketMode::Mix
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_old_vpn(self) -> bool {
|
||||||
|
self == PacketMode::Vpn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for PacketMode {
|
||||||
|
type Error = InvalidPacketMode;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
_ if value == (PacketMode::Mix as u8) => Ok(Self::Mix),
|
||||||
|
_ if value == (PacketMode::Vpn as u8) => Ok(Self::Vpn),
|
||||||
|
v => Err(InvalidPacketMode { received: v }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::FRAG_ID_LEN;
|
use crate::FRAG_ID_LEN;
|
||||||
use nym_sphinx_types::header::HEADER_SIZE;
|
use nym_sphinx_types::header::HEADER_SIZE;
|
||||||
use nym_sphinx_types::{MIX_PARAMS_LEN, OUTFOX_PACKET_OVERHEAD, PAYLOAD_OVERHEAD_SIZE};
|
use nym_sphinx_types::PAYLOAD_OVERHEAD_SIZE;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -12,27 +12,20 @@ use std::str::FromStr;
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
// each sphinx packet contains mandatory header and payload padding + markers
|
// each sphinx packet contains mandatory header and payload padding + markers
|
||||||
const SPHINX_PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
const PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
||||||
|
|
||||||
// it's up to the smart people to figure those values out : )
|
// it's up to the smart people to figure those values out : )
|
||||||
|
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + PACKET_OVERHEAD;
|
||||||
// TODO: even though we have 16B IV, is having just 5B (FRAG_ID_LEN) of the ID possibly insecure?
|
// TODO: even though we have 16B IV, is having just 5B (FRAG_ID_LEN) of the ID possibly insecure?
|
||||||
|
|
||||||
// TODO: I'm not entirely sure if we can easily extract `<AckEncryptionAlgorithm as NewStreamCipher>::NonceSize`
|
// TODO: I'm not entirely sure if we can easily extract `<AckEncryptionAlgorithm as NewStreamCipher>::NonceSize`
|
||||||
// into a const usize before relevant stuff is stabilised in rust...
|
// into a const usize before relevant stuff is stabilised in rust...
|
||||||
const ACK_IV_SIZE: usize = 16;
|
const ACK_IV_SIZE: usize = 16;
|
||||||
|
|
||||||
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + SPHINX_PACKET_OVERHEAD;
|
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + PACKET_OVERHEAD;
|
||||||
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + SPHINX_PACKET_OVERHEAD;
|
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + PACKET_OVERHEAD;
|
||||||
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + SPHINX_PACKET_OVERHEAD;
|
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + PACKET_OVERHEAD;
|
||||||
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + SPHINX_PACKET_OVERHEAD;
|
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + PACKET_OVERHEAD;
|
||||||
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + SPHINX_PACKET_OVERHEAD;
|
|
||||||
|
|
||||||
const OUTFOX_ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + OUTFOX_PACKET_OVERHEAD;
|
|
||||||
const OUTFOX_REGULAR_PACKET_SIZE: usize = 2 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
|
||||||
const OUTFOX_EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
|
||||||
const OUTFOX_EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
|
||||||
const OUTFOX_EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum InvalidPacketSize {
|
pub enum InvalidPacketSize {
|
||||||
@@ -69,25 +62,6 @@ pub enum PacketSize {
|
|||||||
// for example for streaming fast and furious in compressed XviD quality
|
// for example for streaming fast and furious in compressed XviD quality
|
||||||
#[serde(rename = "extended16")]
|
#[serde(rename = "extended16")]
|
||||||
ExtendedPacket16 = 5,
|
ExtendedPacket16 = 5,
|
||||||
|
|
||||||
#[serde(rename = "outfox_regular")]
|
|
||||||
OutfoxRegularPacket = 6,
|
|
||||||
|
|
||||||
// for sending SURB-ACKs
|
|
||||||
#[serde(rename = "outfox_ack")]
|
|
||||||
OutfoxAckPacket = 7,
|
|
||||||
|
|
||||||
// for example for streaming fast and furious in uncompressed 10bit 4K HDR quality
|
|
||||||
#[serde(rename = "outfox_extended32")]
|
|
||||||
OutfoxExtendedPacket32 = 8,
|
|
||||||
|
|
||||||
// for example for streaming fast and furious in heavily compressed lossy RealPlayer quality
|
|
||||||
#[serde(rename = "outfox_extended8")]
|
|
||||||
OutfoxExtendedPacket8 = 9,
|
|
||||||
|
|
||||||
// for example for streaming fast and furious in compressed XviD quality
|
|
||||||
#[serde(rename = "outfox_extended16")]
|
|
||||||
OutfoxExtendedPacket16 = 10,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for PacketSize {
|
impl PartialOrd for PacketSize {
|
||||||
@@ -114,11 +88,6 @@ impl FromStr for PacketSize {
|
|||||||
"extended8" => Ok(Self::ExtendedPacket8),
|
"extended8" => Ok(Self::ExtendedPacket8),
|
||||||
"extended16" => Ok(Self::ExtendedPacket16),
|
"extended16" => Ok(Self::ExtendedPacket16),
|
||||||
"extended32" => Ok(Self::ExtendedPacket32),
|
"extended32" => Ok(Self::ExtendedPacket32),
|
||||||
"outfox_regular" => Ok(Self::OutfoxRegularPacket),
|
|
||||||
"outfox_ack" => Ok(Self::OutfoxAckPacket),
|
|
||||||
"outfox_extended8" => Ok(Self::OutfoxExtendedPacket8),
|
|
||||||
"outfox_extended16" => Ok(Self::OutfoxExtendedPacket16),
|
|
||||||
"outfox_extended32" => Ok(Self::OutfoxExtendedPacket32),
|
|
||||||
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
|
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
|
||||||
received: s.to_string(),
|
received: s.to_string(),
|
||||||
}),
|
}),
|
||||||
@@ -134,11 +103,6 @@ impl Display for PacketSize {
|
|||||||
PacketSize::ExtendedPacket32 => write!(f, "extended32"),
|
PacketSize::ExtendedPacket32 => write!(f, "extended32"),
|
||||||
PacketSize::ExtendedPacket8 => write!(f, "extended8"),
|
PacketSize::ExtendedPacket8 => write!(f, "extended8"),
|
||||||
PacketSize::ExtendedPacket16 => write!(f, "extended16"),
|
PacketSize::ExtendedPacket16 => write!(f, "extended16"),
|
||||||
PacketSize::OutfoxRegularPacket => write!(f, "outfox_regular"),
|
|
||||||
PacketSize::OutfoxAckPacket => write!(f, "outfox_ack"),
|
|
||||||
PacketSize::OutfoxExtendedPacket32 => write!(f, "outfox_extended32"),
|
|
||||||
PacketSize::OutfoxExtendedPacket8 => write!(f, "outfox_extended8"),
|
|
||||||
PacketSize::OutfoxExtendedPacket16 => write!(f, "outfox_extended16"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,17 +127,6 @@ impl TryFrom<u8> for PacketSize {
|
|||||||
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
|
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
|
||||||
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
|
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
|
||||||
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
|
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
|
||||||
_ if value == (PacketSize::OutfoxRegularPacket as u8) => Ok(Self::OutfoxRegularPacket),
|
|
||||||
_ if value == (PacketSize::OutfoxAckPacket as u8) => Ok(Self::OutfoxAckPacket),
|
|
||||||
_ if value == (PacketSize::OutfoxExtendedPacket8 as u8) => {
|
|
||||||
Ok(Self::OutfoxExtendedPacket8)
|
|
||||||
}
|
|
||||||
_ if value == (PacketSize::OutfoxExtendedPacket16 as u8) => {
|
|
||||||
Ok(Self::OutfoxExtendedPacket16)
|
|
||||||
}
|
|
||||||
_ if value == (PacketSize::OutfoxExtendedPacket32 as u8) => {
|
|
||||||
Ok(Self::OutfoxExtendedPacket32)
|
|
||||||
}
|
|
||||||
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
|
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,50 +140,15 @@ impl PacketSize {
|
|||||||
PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
|
PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
|
||||||
PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
|
PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
|
||||||
PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
|
PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
|
||||||
PacketSize::OutfoxRegularPacket => OUTFOX_REGULAR_PACKET_SIZE,
|
|
||||||
PacketSize::OutfoxAckPacket => OUTFOX_ACK_PACKET_SIZE,
|
|
||||||
PacketSize::OutfoxExtendedPacket8 => OUTFOX_EXTENDED_PACKET_SIZE_8,
|
|
||||||
PacketSize::OutfoxExtendedPacket16 => OUTFOX_EXTENDED_PACKET_SIZE_16,
|
|
||||||
PacketSize::OutfoxExtendedPacket32 => OUTFOX_EXTENDED_PACKET_SIZE_32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn header_size(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
PacketSize::RegularPacket
|
|
||||||
| PacketSize::AckPacket
|
|
||||||
| PacketSize::ExtendedPacket8
|
|
||||||
| PacketSize::ExtendedPacket16
|
|
||||||
| PacketSize::ExtendedPacket32 => HEADER_SIZE,
|
|
||||||
PacketSize::OutfoxRegularPacket
|
|
||||||
| PacketSize::OutfoxAckPacket
|
|
||||||
| PacketSize::OutfoxExtendedPacket8
|
|
||||||
| PacketSize::OutfoxExtendedPacket16
|
|
||||||
| PacketSize::OutfoxExtendedPacket32 => MIX_PARAMS_LEN,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn payload_overhead(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
PacketSize::RegularPacket
|
|
||||||
| PacketSize::AckPacket
|
|
||||||
| PacketSize::ExtendedPacket8
|
|
||||||
| PacketSize::ExtendedPacket16
|
|
||||||
| PacketSize::ExtendedPacket32 => PAYLOAD_OVERHEAD_SIZE,
|
|
||||||
PacketSize::OutfoxRegularPacket
|
|
||||||
| PacketSize::OutfoxAckPacket
|
|
||||||
| PacketSize::OutfoxExtendedPacket8
|
|
||||||
| PacketSize::OutfoxExtendedPacket16
|
|
||||||
| PacketSize::OutfoxExtendedPacket32 => OUTFOX_PACKET_OVERHEAD - MIX_PARAMS_LEN,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn plaintext_size(self) -> usize {
|
pub const fn plaintext_size(self) -> usize {
|
||||||
self.size() - self.header_size() - self.payload_overhead()
|
self.size() - HEADER_SIZE - PAYLOAD_OVERHEAD_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn payload_size(self) -> usize {
|
pub const fn payload_size(self) -> usize {
|
||||||
self.size() - self.header_size()
|
self.size() - HEADER_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
|
pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
|
||||||
@@ -244,16 +162,6 @@ impl PacketSize {
|
|||||||
Ok(PacketSize::ExtendedPacket16)
|
Ok(PacketSize::ExtendedPacket16)
|
||||||
} else if PacketSize::ExtendedPacket32.size() == size {
|
} else if PacketSize::ExtendedPacket32.size() == size {
|
||||||
Ok(PacketSize::ExtendedPacket32)
|
Ok(PacketSize::ExtendedPacket32)
|
||||||
} else if PacketSize::OutfoxRegularPacket.size() == size {
|
|
||||||
Ok(PacketSize::OutfoxRegularPacket)
|
|
||||||
} else if PacketSize::OutfoxAckPacket.size() == size {
|
|
||||||
Ok(PacketSize::OutfoxAckPacket)
|
|
||||||
} else if PacketSize::OutfoxExtendedPacket8.size() == size {
|
|
||||||
Ok(PacketSize::OutfoxExtendedPacket8)
|
|
||||||
} else if PacketSize::OutfoxExtendedPacket16.size() == size {
|
|
||||||
Ok(PacketSize::OutfoxExtendedPacket16)
|
|
||||||
} else if PacketSize::OutfoxExtendedPacket32.size() == size {
|
|
||||||
Ok(PacketSize::OutfoxExtendedPacket32)
|
|
||||||
} else {
|
} else {
|
||||||
Err(InvalidPacketSize::UnknownPacketSize { received: size })
|
Err(InvalidPacketSize::UnknownPacketSize { received: size })
|
||||||
}
|
}
|
||||||
@@ -261,16 +169,10 @@ impl PacketSize {
|
|||||||
|
|
||||||
pub fn is_extended_size(&self) -> bool {
|
pub fn is_extended_size(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PacketSize::RegularPacket
|
PacketSize::RegularPacket | PacketSize::AckPacket => false,
|
||||||
| PacketSize::AckPacket
|
|
||||||
| PacketSize::OutfoxAckPacket
|
|
||||||
| PacketSize::OutfoxRegularPacket => false,
|
|
||||||
PacketSize::ExtendedPacket8
|
PacketSize::ExtendedPacket8
|
||||||
| PacketSize::ExtendedPacket16
|
| PacketSize::ExtendedPacket16
|
||||||
| PacketSize::ExtendedPacket32
|
| PacketSize::ExtendedPacket32 => true,
|
||||||
| PacketSize::OutfoxExtendedPacket8
|
|
||||||
| PacketSize::OutfoxExtendedPacket16
|
|
||||||
| PacketSize::OutfoxExtendedPacket32 => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,15 +185,8 @@ impl PacketSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type_from_plaintext(plaintext_size: usize) -> Result<Self, InvalidPacketSize> {
|
pub fn get_type_from_plaintext(plaintext_size: usize) -> Result<Self, InvalidPacketSize> {
|
||||||
let sphinx_packet_size = plaintext_size + SPHINX_PACKET_OVERHEAD;
|
let packet_size = plaintext_size + PACKET_OVERHEAD;
|
||||||
let outfox_packet_size = plaintext_size + OUTFOX_PACKET_OVERHEAD;
|
Self::get_type(packet_size)
|
||||||
match Self::get_type(sphinx_packet_size) {
|
|
||||||
Ok(t) => Ok(t),
|
|
||||||
Err(_) => {
|
|
||||||
println!("Got Outfox!");
|
|
||||||
Self::get_type(outfox_packet_size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
#[error("{received} is not a valid packet mode tag")]
|
|
||||||
pub struct InvalidPacketType {
|
|
||||||
received: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
|
||||||
pub enum PacketType {
|
|
||||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
|
||||||
/// value at each hop.
|
|
||||||
#[default]
|
|
||||||
Mix = 0,
|
|
||||||
|
|
||||||
/// Represents a packet that should be sent through the network as fast as possible.
|
|
||||||
Vpn = 1,
|
|
||||||
|
|
||||||
/// Abusing this to add Outfox support
|
|
||||||
Outfox = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketType {
|
|
||||||
pub fn is_mix(self) -> bool {
|
|
||||||
self == PacketType::Mix
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_outfox(self) -> bool {
|
|
||||||
self == PacketType::Outfox
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for PacketType {
|
|
||||||
type Error = InvalidPacketType;
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
_ if value == (PacketType::Mix as u8) => Ok(Self::Mix),
|
|
||||||
_ if value == (PacketType::Outfox as u8) => Ok(Self::Outfox),
|
|
||||||
v => Err(InvalidPacketType { received: v }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{PacketSize, CURRENT_PACKET_VERSION_NUMBER};
|
use crate::{PacketSize, CURRENT_PACKET_VERSION_NUMBER};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum PacketVersion {
|
pub enum PacketVersion {
|
||||||
// this will allow updated mixnodes to still understand packets from before the update
|
// this will allow updated mixnodes to still understand packets from before the update
|
||||||
Legacy,
|
Legacy,
|
||||||
|
|||||||
@@ -19,4 +19,4 @@ pub use nym_sphinx_params as params;
|
|||||||
pub use nym_sphinx_types::*;
|
pub use nym_sphinx_types::*;
|
||||||
|
|
||||||
// TEMP UNTIL FURTHER REFACTORING
|
// TEMP UNTIL FURTHER REFACTORING
|
||||||
pub use preparer::payload::NymPayloadBuilder;
|
pub use preparer::payload::NymsphinxPayloadBuilder;
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::message::{NymMessage, ACK_OVERHEAD};
|
use crate::message::{NymMessage, ACK_OVERHEAD};
|
||||||
use crate::NymPayloadBuilder;
|
use crate::NymsphinxPayloadBuilder;
|
||||||
use nym_crypto::asymmetric::encryption;
|
use nym_crypto::asymmetric::encryption;
|
||||||
use nym_crypto::Digest;
|
use nym_crypto::Digest;
|
||||||
use nym_outfox::packet::OutfoxPacket;
|
|
||||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||||
use nym_sphinx_acknowledgements::AckKey;
|
use nym_sphinx_acknowledgements::AckKey;
|
||||||
use nym_sphinx_addressing::clients::Recipient;
|
use nym_sphinx_addressing::clients::Recipient;
|
||||||
@@ -14,9 +13,9 @@ use nym_sphinx_anonymous_replies::reply_surb::ReplySurb;
|
|||||||
use nym_sphinx_chunking::fragment::{Fragment, FragmentIdentifier};
|
use nym_sphinx_chunking::fragment::{Fragment, FragmentIdentifier};
|
||||||
use nym_sphinx_forwarding::packet::MixPacket;
|
use nym_sphinx_forwarding::packet::MixPacket;
|
||||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||||
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||||
use nym_sphinx_types::{delays, Delay, NymPacket};
|
use nym_sphinx_types::{delays, Delay};
|
||||||
use nym_topology::{NymTopology, NymTopologyError};
|
use nym_topology::{NymTopology, NymTopologyError};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@@ -39,226 +38,6 @@ pub struct PreparedFragment {
|
|||||||
pub fragment_identifier: FragmentIdentifier,
|
pub fragment_identifier: FragmentIdentifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is extracted into a trait with default implementation to remove duplicate code
|
|
||||||
// (which we REALLY want to avoid with crypto)
|
|
||||||
pub trait FragmentPreparer {
|
|
||||||
type Rng: CryptoRng + Rng;
|
|
||||||
|
|
||||||
fn rng(&mut self) -> &mut Self::Rng;
|
|
||||||
fn num_mix_hops(&self) -> u8;
|
|
||||||
fn average_packet_delay(&self) -> Duration;
|
|
||||||
fn average_ack_delay(&self) -> Duration;
|
|
||||||
|
|
||||||
fn generate_reply_surbs(
|
|
||||||
&mut self,
|
|
||||||
amount: usize,
|
|
||||||
topology: &NymTopology,
|
|
||||||
reply_recipient: &Recipient,
|
|
||||||
) -> Result<Vec<ReplySurb>, NymTopologyError> {
|
|
||||||
let mut reply_surbs = Vec::with_capacity(amount);
|
|
||||||
let packet_delay = self.average_packet_delay();
|
|
||||||
for _ in 0..amount {
|
|
||||||
let reply_surb =
|
|
||||||
ReplySurb::construct(self.rng(), reply_recipient, packet_delay, topology)?;
|
|
||||||
reply_surbs.push(reply_surb)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(reply_surbs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_surb_ack(
|
|
||||||
&mut self,
|
|
||||||
recipient: &Recipient,
|
|
||||||
fragment_id: FragmentIdentifier,
|
|
||||||
topology: &NymTopology,
|
|
||||||
ack_key: &AckKey,
|
|
||||||
) -> Result<SurbAck, NymTopologyError> {
|
|
||||||
let ack_delay = self.average_ack_delay();
|
|
||||||
|
|
||||||
SurbAck::construct(
|
|
||||||
self.rng(),
|
|
||||||
recipient,
|
|
||||||
ack_key,
|
|
||||||
fragment_id.to_bytes(),
|
|
||||||
ack_delay,
|
|
||||||
topology,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The procedure is as follows:
|
|
||||||
/// For each fragment:
|
|
||||||
/// - compute SURB_ACK
|
|
||||||
/// - generate (x, g^x)
|
|
||||||
/// - obtain key k from the reply-surb which was computed as follows:
|
|
||||||
/// k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
|
||||||
/// - compute v_b = AES-128-CTR(k, serialized_fragment)
|
|
||||||
/// - compute vk_b = H(k) || v_b
|
|
||||||
/// - compute sphinx_plaintext = SURB_ACK || H(k) || v_b
|
|
||||||
/// - compute sphinx_packet by applying the reply surb on the sphinx_plaintext
|
|
||||||
fn prepare_reply_chunk_for_sending(
|
|
||||||
&mut self,
|
|
||||||
fragment: Fragment,
|
|
||||||
topology: &NymTopology,
|
|
||||||
ack_key: &AckKey,
|
|
||||||
reply_surb: ReplySurb,
|
|
||||||
packet_sender: &Recipient,
|
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<PreparedFragment, NymTopologyError> {
|
|
||||||
// each reply attaches the digest of the encryption key so that the recipient could
|
|
||||||
// lookup correct key for decryption,
|
|
||||||
let reply_overhead = ReplySurbKeyDigestAlgorithm::output_size();
|
|
||||||
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + reply_overhead;
|
|
||||||
|
|
||||||
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
|
||||||
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
|
||||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
|
||||||
.expect("the message has been incorrectly fragmented");
|
|
||||||
|
|
||||||
// this is not going to be accurate by any means. but that's the best estimation we can do
|
|
||||||
let expected_forward_delay = Delay::new_from_millis(
|
|
||||||
(self.average_packet_delay().as_millis() * self.num_mix_hops() as u128) as u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fragment_identifier = fragment.fragment_identifier();
|
|
||||||
|
|
||||||
// create an ack
|
|
||||||
let surb_ack =
|
|
||||||
self.generate_surb_ack(packet_sender, fragment_identifier, topology, ack_key)?;
|
|
||||||
let ack_delay = surb_ack.expected_total_delay();
|
|
||||||
|
|
||||||
let packet_payload = match NymPayloadBuilder::new(fragment, surb_ack)
|
|
||||||
.build_reply(reply_surb.encryption_key())
|
|
||||||
{
|
|
||||||
Ok(payload) => payload,
|
|
||||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
|
||||||
};
|
|
||||||
|
|
||||||
// the unwrap here is fine as the failures can only originate from attempting to use invalid payload lengths
|
|
||||||
// and we just very carefully constructed a (presumably) valid one
|
|
||||||
let (sphinx_packet, first_hop_address) = reply_surb
|
|
||||||
.apply_surb(packet_payload, packet_size, packet_type)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Ok(PreparedFragment {
|
|
||||||
// the round-trip delay is the sum of delays of all hops on the forward route as
|
|
||||||
// well as the total delay of the ack packet.
|
|
||||||
// we don't know the delays inside the reply surbs so we use best-effort estimation from our poisson distribution
|
|
||||||
total_delay: expected_forward_delay + ack_delay,
|
|
||||||
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, Default::default()),
|
|
||||||
fragment_identifier,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to convert this [`Fragment`] into a [`SphinxPacket`] that can be sent through the Nym mix-network,
|
|
||||||
/// such that it contains required SURB-ACK and public component of the ephemeral key used to
|
|
||||||
/// derive the shared key.
|
|
||||||
/// Also all the data, apart from the said public component, is encrypted with an ephemeral shared key.
|
|
||||||
/// This method can fail if the provided network topology is invalid.
|
|
||||||
/// It returns total expected delay as well as the [`SphinxPacket`] (including first hop address)
|
|
||||||
/// to be sent through the network.
|
|
||||||
///
|
|
||||||
/// The procedure is as follows:
|
|
||||||
/// For each fragment:
|
|
||||||
/// - compute SURB_ACK
|
|
||||||
/// - generate (x, g^x)
|
|
||||||
/// - compute k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
|
||||||
/// - compute v_b = AES-128-CTR(k, serialized_fragment)
|
|
||||||
/// - compute vk_b = g^x || v_b
|
|
||||||
/// - compute sphinx_plaintext = SURB_ACK || g^x || v_b
|
|
||||||
/// - compute sphinx_packet = Sphinx(recipient, sphinx_plaintext)
|
|
||||||
fn prepare_chunk_for_sending(
|
|
||||||
&mut self,
|
|
||||||
fragment: Fragment,
|
|
||||||
topology: &NymTopology,
|
|
||||||
ack_key: &AckKey,
|
|
||||||
packet_sender: &Recipient,
|
|
||||||
packet_recipient: &Recipient,
|
|
||||||
packet_type: &PacketType,
|
|
||||||
) -> Result<PreparedFragment, NymTopologyError> {
|
|
||||||
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
|
|
||||||
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
|
|
||||||
// the packet encryption key
|
|
||||||
let non_reply_overhead = encryption::PUBLIC_KEY_SIZE;
|
|
||||||
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + non_reply_overhead;
|
|
||||||
|
|
||||||
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
|
||||||
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
|
||||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
|
||||||
.expect("the message has been incorrectly fragmented");
|
|
||||||
|
|
||||||
let fragment_identifier = fragment.fragment_identifier();
|
|
||||||
|
|
||||||
// create an ack
|
|
||||||
let surb_ack =
|
|
||||||
self.generate_surb_ack(packet_sender, fragment_identifier, topology, ack_key)?;
|
|
||||||
let ack_delay = surb_ack.expected_total_delay();
|
|
||||||
|
|
||||||
let packet_payload = match NymPayloadBuilder::new(fragment, surb_ack)
|
|
||||||
.build_regular(self.rng(), packet_recipient.encryption_key())
|
|
||||||
{
|
|
||||||
Ok(payload) => payload,
|
|
||||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate pseudorandom route for the packet
|
|
||||||
let hops = self.num_mix_hops();
|
|
||||||
let route =
|
|
||||||
topology.random_route_to_gateway(self.rng(), hops, packet_recipient.gateway())?;
|
|
||||||
let destination = packet_recipient.as_sphinx_destination();
|
|
||||||
|
|
||||||
// including set of delays
|
|
||||||
let delays =
|
|
||||||
delays::generate_from_average_duration(route.len(), self.average_packet_delay());
|
|
||||||
|
|
||||||
// create the actual sphinx packet here. With valid route and correct payload size,
|
|
||||||
// there's absolutely no reason for this call to fail.
|
|
||||||
let packet = match packet_type {
|
|
||||||
PacketType::Outfox => NymPacket::Outfox(OutfoxPacket::build(
|
|
||||||
packet_payload,
|
|
||||||
route.as_slice().try_into()?,
|
|
||||||
Some(packet_size.payload_size()),
|
|
||||||
)?),
|
|
||||||
PacketType::Mix => NymPacket::Sphinx({
|
|
||||||
SphinxPacketBuilder::new()
|
|
||||||
.with_payload_size(packet_size.payload_size())
|
|
||||||
.build_packet(packet_payload, &route, &destination, &delays)
|
|
||||||
.unwrap()
|
|
||||||
}),
|
|
||||||
PacketType::Vpn => NymPacket::Sphinx(
|
|
||||||
SphinxPacketBuilder::new()
|
|
||||||
.with_payload_size(packet_size.payload_size())
|
|
||||||
.build_packet(packet_payload, &route, &destination, &delays)
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// from the previously constructed route extract the first hop
|
|
||||||
let first_hop_address =
|
|
||||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
|
||||||
|
|
||||||
Ok(PreparedFragment {
|
|
||||||
// the round-trip delay is the sum of delays of all hops on the forward route as
|
|
||||||
// well as the total delay of the ack packet.
|
|
||||||
// note that the last hop of the packet is a gateway that does not do any delays
|
|
||||||
total_delay: delays.iter().take(delays.len() - 1).sum::<Delay>() + ack_delay,
|
|
||||||
mix_packet: MixPacket::new(first_hop_address, packet, Default::default()),
|
|
||||||
fragment_identifier,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pad_and_split_message(
|
|
||||||
&mut self,
|
|
||||||
message: NymMessage,
|
|
||||||
packet_size: PacketSize,
|
|
||||||
) -> Vec<Fragment> {
|
|
||||||
let plaintext_per_packet = message.available_sphinx_plaintext_per_packet(packet_size);
|
|
||||||
|
|
||||||
message
|
|
||||||
.pad_to_full_packet_lengths(plaintext_per_packet)
|
|
||||||
.split_into_fragments(self.rng(), plaintext_per_packet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepares the message that is to be sent through the mix network by attaching
|
/// Prepares the message that is to be sent through the mix network by attaching
|
||||||
/// an optional reply-SURB, padding it to appropriate length, encrypting its content,
|
/// an optional reply-SURB, padding it to appropriate length, encrypting its content,
|
||||||
/// and chunking into appropriate size [`Fragment`]s.
|
/// and chunking into appropriate size [`Fragment`]s.
|
||||||
@@ -332,57 +111,153 @@ where
|
|||||||
Ok(reply_surbs)
|
Ok(reply_surbs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The procedure is as follows:
|
||||||
|
/// For each fragment:
|
||||||
|
/// - compute SURB_ACK
|
||||||
|
/// - generate (x, g^x)
|
||||||
|
/// - obtain key k from the reply-surb which was computed as follows:
|
||||||
|
/// k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
||||||
|
/// - compute v_b = AES-128-CTR(k, serialized_fragment)
|
||||||
|
/// - compute vk_b = H(k) || v_b
|
||||||
|
/// - compute sphinx_plaintext = SURB_ACK || H(k) || v_b
|
||||||
|
/// - compute sphinx_packet by applying the reply surb on the sphinx_plaintext
|
||||||
pub fn prepare_reply_chunk_for_sending(
|
pub fn prepare_reply_chunk_for_sending(
|
||||||
&mut self,
|
&mut self,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
topology: &NymTopology,
|
topology: &NymTopology,
|
||||||
ack_key: &AckKey,
|
ack_key: &AckKey,
|
||||||
reply_surb: ReplySurb,
|
reply_surb: ReplySurb,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Result<PreparedFragment, NymTopologyError> {
|
) -> Result<PreparedFragment, NymTopologyError> {
|
||||||
let sender = self.sender_address;
|
// each reply attaches the digest of the encryption key so that the recipient could
|
||||||
|
// lookup correct key for decryption,
|
||||||
|
let reply_overhead = ReplySurbKeyDigestAlgorithm::output_size();
|
||||||
|
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + reply_overhead;
|
||||||
|
|
||||||
<Self as FragmentPreparer>::prepare_reply_chunk_for_sending(
|
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
||||||
self,
|
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
||||||
fragment,
|
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
||||||
topology,
|
.expect("the message has been incorrectly fragmented");
|
||||||
ack_key,
|
|
||||||
reply_surb,
|
// this is not going to be accurate by any means. but that's the best estimation we can do
|
||||||
&sender,
|
let expected_forward_delay = Delay::new_from_millis(
|
||||||
packet_type,
|
(self.average_packet_delay.as_millis() * self.num_mix_hops as u128) as u64,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
let fragment_identifier = fragment.fragment_identifier();
|
||||||
|
|
||||||
|
// create an ack
|
||||||
|
let surb_ack = self.generate_surb_ack(fragment_identifier, topology, ack_key)?;
|
||||||
|
let ack_delay = surb_ack.expected_total_delay();
|
||||||
|
|
||||||
|
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||||
|
.build_reply(reply_surb.encryption_key());
|
||||||
|
|
||||||
|
// the unwrap here is fine as the failures can only originate from attempting to use invalid payload lengths
|
||||||
|
// and we just very carefully constructed a (presumably) valid one
|
||||||
|
let (sphinx_packet, first_hop_address) =
|
||||||
|
reply_surb.apply_surb(packet_payload, packet_size).unwrap();
|
||||||
|
|
||||||
|
Ok(PreparedFragment {
|
||||||
|
// the round-trip delay is the sum of delays of all hops on the forward route as
|
||||||
|
// well as the total delay of the ack packet.
|
||||||
|
// we don't know the delays inside the reply surbs so we use best-effort estimation from our poisson distribution
|
||||||
|
total_delay: expected_forward_delay + ack_delay,
|
||||||
|
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, Default::default()),
|
||||||
|
fragment_identifier,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to convert this [`Fragment`] into a [`SphinxPacket`] that can be sent through the Nym mix-network,
|
||||||
|
/// such that it contains required SURB-ACK and public component of the ephemeral key used to
|
||||||
|
/// derive the shared key.
|
||||||
|
/// Also all the data, apart from the said public component, is encrypted with an ephemeral shared key.
|
||||||
|
/// This method can fail if the provided network topology is invalid.
|
||||||
|
/// It returns total expected delay as well as the [`SphinxPacket`] (including first hop address)
|
||||||
|
/// to be sent through the network.
|
||||||
|
///
|
||||||
|
/// The procedure is as follows:
|
||||||
|
/// For each fragment:
|
||||||
|
/// - compute SURB_ACK
|
||||||
|
/// - generate (x, g^x)
|
||||||
|
/// - compute k = KDF(remote encryption key ^ x) this is equivalent to KDF( dh(remote, x) )
|
||||||
|
/// - compute v_b = AES-128-CTR(k, serialized_fragment)
|
||||||
|
/// - compute vk_b = g^x || v_b
|
||||||
|
/// - compute sphinx_plaintext = SURB_ACK || g^x || v_b
|
||||||
|
/// - compute sphinx_packet = Sphinx(recipient, sphinx_plaintext)
|
||||||
pub fn prepare_chunk_for_sending(
|
pub fn prepare_chunk_for_sending(
|
||||||
&mut self,
|
&mut self,
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
topology: &NymTopology,
|
topology: &NymTopology,
|
||||||
ack_key: &AckKey,
|
ack_key: &AckKey,
|
||||||
packet_recipient: &Recipient,
|
packet_recipient: &Recipient,
|
||||||
packet_type: &PacketType,
|
|
||||||
) -> Result<PreparedFragment, NymTopologyError> {
|
) -> Result<PreparedFragment, NymTopologyError> {
|
||||||
let sender = self.sender_address;
|
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
|
||||||
|
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
|
||||||
|
// the packet encryption key
|
||||||
|
let non_reply_overhead = encryption::PUBLIC_KEY_SIZE;
|
||||||
|
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + non_reply_overhead;
|
||||||
|
|
||||||
<Self as FragmentPreparer>::prepare_chunk_for_sending(
|
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
||||||
self,
|
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
||||||
fragment,
|
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
||||||
topology,
|
.expect("the message has been incorrectly fragmented");
|
||||||
ack_key,
|
|
||||||
&sender,
|
let fragment_identifier = fragment.fragment_identifier();
|
||||||
packet_recipient,
|
|
||||||
packet_type,
|
// create an ack
|
||||||
)
|
let surb_ack = self.generate_surb_ack(fragment_identifier, topology, ack_key)?;
|
||||||
|
let ack_delay = surb_ack.expected_total_delay();
|
||||||
|
|
||||||
|
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||||
|
.build_regular(&mut self.rng, packet_recipient.encryption_key());
|
||||||
|
|
||||||
|
// generate pseudorandom route for the packet
|
||||||
|
let route = topology.random_route_to_gateway(
|
||||||
|
&mut self.rng,
|
||||||
|
self.num_mix_hops,
|
||||||
|
packet_recipient.gateway(),
|
||||||
|
)?;
|
||||||
|
let destination = packet_recipient.as_sphinx_destination();
|
||||||
|
|
||||||
|
// including set of delays
|
||||||
|
let delays = delays::generate_from_average_duration(route.len(), self.average_packet_delay);
|
||||||
|
|
||||||
|
// create the actual sphinx packet here. With valid route and correct payload size,
|
||||||
|
// there's absolutely no reason for this call to fail.
|
||||||
|
let sphinx_packet = SphinxPacketBuilder::new()
|
||||||
|
.with_payload_size(packet_size.payload_size())
|
||||||
|
.build_packet(packet_payload, &route, &destination, &delays)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// from the previously constructed route extract the first hop
|
||||||
|
let first_hop_address =
|
||||||
|
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||||
|
|
||||||
|
Ok(PreparedFragment {
|
||||||
|
// the round-trip delay is the sum of delays of all hops on the forward route as
|
||||||
|
// well as the total delay of the ack packet.
|
||||||
|
// note that the last hop of the packet is a gateway that does not do any delays
|
||||||
|
total_delay: delays.iter().take(delays.len() - 1).sum::<Delay>() + ack_delay,
|
||||||
|
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, Default::default()),
|
||||||
|
fragment_identifier,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an acknowledgement SURB for the given [`FragmentIdentifier`]
|
/// Construct an acknowledgement SURB for the given [`FragmentIdentifier`]
|
||||||
pub fn generate_surb_ack(
|
fn generate_surb_ack(
|
||||||
&mut self,
|
&mut self,
|
||||||
fragment_id: FragmentIdentifier,
|
fragment_id: FragmentIdentifier,
|
||||||
topology: &NymTopology,
|
topology: &NymTopology,
|
||||||
ack_key: &AckKey,
|
ack_key: &AckKey,
|
||||||
) -> Result<SurbAck, NymTopologyError> {
|
) -> Result<SurbAck, NymTopologyError> {
|
||||||
let sender = self.sender_address;
|
SurbAck::construct(
|
||||||
<Self as FragmentPreparer>::generate_surb_ack(self, &sender, fragment_id, topology, ack_key)
|
&mut self.rng,
|
||||||
|
&self.sender_address,
|
||||||
|
ack_key,
|
||||||
|
fragment_id.to_bytes(),
|
||||||
|
self.average_ack_delay,
|
||||||
|
topology,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pad_and_split_message(
|
pub fn pad_and_split_message(
|
||||||
@@ -390,27 +265,11 @@ where
|
|||||||
message: NymMessage,
|
message: NymMessage,
|
||||||
packet_size: PacketSize,
|
packet_size: PacketSize,
|
||||||
) -> Vec<Fragment> {
|
) -> Vec<Fragment> {
|
||||||
<Self as FragmentPreparer>::pad_and_split_message(self, message, packet_size)
|
let plaintext_per_packet = message.available_sphinx_plaintext_per_packet(packet_size);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: CryptoRng + Rng> FragmentPreparer for MessagePreparer<R> {
|
message
|
||||||
type Rng = R;
|
.pad_to_full_packet_lengths(plaintext_per_packet)
|
||||||
|
.split_into_fragments(&mut self.rng, plaintext_per_packet)
|
||||||
fn rng(&mut self) -> &mut Self::Rng {
|
|
||||||
&mut self.rng
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_mix_hops(&self) -> u8 {
|
|
||||||
self.num_mix_hops
|
|
||||||
}
|
|
||||||
|
|
||||||
fn average_packet_delay(&self) -> Duration {
|
|
||||||
self.average_packet_delay
|
|
||||||
}
|
|
||||||
|
|
||||||
fn average_ack_delay(&self) -> Duration {
|
|
||||||
self.average_ack_delay
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use nym_crypto::asymmetric::encryption;
|
|||||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||||
use nym_crypto::symmetric::stream_cipher;
|
use nym_crypto::symmetric::stream_cipher;
|
||||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||||
use nym_sphinx_chunking::fragment::Fragment;
|
use nym_sphinx_chunking::fragment::Fragment;
|
||||||
use nym_sphinx_params::{
|
use nym_sphinx_params::{
|
||||||
@@ -14,25 +14,25 @@ use nym_sphinx_params::{
|
|||||||
};
|
};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
|
|
||||||
pub struct NymPayloadBuilder {
|
pub struct NymsphinxPayloadBuilder {
|
||||||
fragment: Fragment,
|
fragment: Fragment,
|
||||||
surb_ack: SurbAck,
|
surb_ack: SurbAck,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NymPayloadBuilder {
|
impl NymsphinxPayloadBuilder {
|
||||||
pub fn new(fragment: Fragment, surb_ack: SurbAck) -> Self {
|
pub fn new(fragment: Fragment, surb_ack: SurbAck) -> Self {
|
||||||
NymPayloadBuilder { fragment, surb_ack }
|
NymsphinxPayloadBuilder { fragment, surb_ack }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<C>(
|
fn build<C>(
|
||||||
self,
|
self,
|
||||||
packet_encryption_key: &CipherKey<C>,
|
packet_encryption_key: &CipherKey<C>,
|
||||||
variant_data: impl IntoIterator<Item = u8>,
|
variant_data: impl IntoIterator<Item = u8>,
|
||||||
) -> Result<NymPayload, SurbAckRecoveryError>
|
) -> NymsphinxPayload
|
||||||
where
|
where
|
||||||
C: StreamCipher + KeyIvInit,
|
C: StreamCipher + KeyIvInit,
|
||||||
{
|
{
|
||||||
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending()?;
|
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending();
|
||||||
|
|
||||||
let mut fragment_data = self.fragment.into_bytes();
|
let mut fragment_data = self.fragment.into_bytes();
|
||||||
stream_cipher::encrypt_in_place::<C>(
|
stream_cipher::encrypt_in_place::<C>(
|
||||||
@@ -46,19 +46,16 @@ impl NymPayloadBuilder {
|
|||||||
// where variant-specific data is as follows:
|
// where variant-specific data is as follows:
|
||||||
// for replies it would be the digest of the encryption key used
|
// for replies it would be the digest of the encryption key used
|
||||||
// for 'regular' messages it would be the public component used in DH later used in the KDF
|
// for 'regular' messages it would be the public component used in DH later used in the KDF
|
||||||
Ok(NymPayload(
|
NymsphinxPayload(
|
||||||
surb_ack_bytes
|
surb_ack_bytes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(variant_data.into_iter())
|
.chain(variant_data.into_iter())
|
||||||
.chain(fragment_data.into_iter())
|
.chain(fragment_data.into_iter())
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_reply(
|
pub fn build_reply(self, packet_encryption_key: &SurbEncryptionKey) -> NymsphinxPayload {
|
||||||
self,
|
|
||||||
packet_encryption_key: &SurbEncryptionKey,
|
|
||||||
) -> Result<NymPayload, SurbAckRecoveryError> {
|
|
||||||
let key_digest = packet_encryption_key.compute_digest();
|
let key_digest = packet_encryption_key.compute_digest();
|
||||||
self.build::<ReplySurbEncryptionAlgorithm>(
|
self.build::<ReplySurbEncryptionAlgorithm>(
|
||||||
packet_encryption_key.inner(),
|
packet_encryption_key.inner(),
|
||||||
@@ -70,7 +67,7 @@ impl NymPayloadBuilder {
|
|||||||
self,
|
self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
recipient_encryption_key: &encryption::PublicKey,
|
recipient_encryption_key: &encryption::PublicKey,
|
||||||
) -> Result<NymPayload, SurbAckRecoveryError>
|
) -> NymsphinxPayload
|
||||||
where
|
where
|
||||||
R: RngCore + CryptoRng,
|
R: RngCore + CryptoRng,
|
||||||
{
|
{
|
||||||
@@ -91,9 +88,9 @@ impl NymPayloadBuilder {
|
|||||||
// the actual byte data that will be put into the sphinx packet paylaod.
|
// the actual byte data that will be put into the sphinx packet paylaod.
|
||||||
// no more transformations are going to happen to it
|
// no more transformations are going to happen to it
|
||||||
// TODO: use that fact for some better compile time assertions
|
// TODO: use that fact for some better compile time assertions
|
||||||
pub struct NymPayload(Vec<u8>);
|
pub struct NymsphinxPayload(Vec<u8>);
|
||||||
|
|
||||||
impl AsRef<[u8]> for NymPayload {
|
impl AsRef<[u8]> for NymsphinxPayload {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use nym_crypto::asymmetric::encryption;
|
|||||||
use nym_crypto::shared_key::recompute_shared_key;
|
use nym_crypto::shared_key::recompute_shared_key;
|
||||||
use nym_crypto::symmetric::stream_cipher;
|
use nym_crypto::symmetric::stream_cipher;
|
||||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||||
|
use nym_outfox::error::OutfoxError;
|
||||||
|
use nym_outfox::lion::lion_transform_decrypt;
|
||||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||||
use nym_sphinx_chunking::fragment::Fragment;
|
use nym_sphinx_chunking::fragment::Fragment;
|
||||||
@@ -74,6 +76,49 @@ pub enum MessageRecoveryError {
|
|||||||
|
|
||||||
#[error("Failed to recover message fragment - {0}")]
|
#[error("Failed to recover message fragment - {0}")]
|
||||||
FragmentRecoveryError(#[from] ChunkingError),
|
FragmentRecoveryError(#[from] ChunkingError),
|
||||||
|
|
||||||
|
#[error("Outfox: {source}")]
|
||||||
|
OutfoxRecoveryError {
|
||||||
|
#[from]
|
||||||
|
source: OutfoxError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct OutfoxMessageReceiver {
|
||||||
|
reconstructor: MessageReconstructor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutfoxMessageReceiver {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageReceiver for OutfoxMessageReceiver {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstructor(&mut self) -> &mut MessageReconstructor {
|
||||||
|
&mut self.reconstructor
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_mix_hops(&self) -> u8 {
|
||||||
|
DEFAULT_NUM_MIX_HOPS
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt_raw_message<C>(
|
||||||
|
&self,
|
||||||
|
message: &mut [u8],
|
||||||
|
key: &CipherKey<C>,
|
||||||
|
) -> Result<(), MessageRecoveryError>
|
||||||
|
where
|
||||||
|
C: StreamCipher + KeyIvInit,
|
||||||
|
{
|
||||||
|
lion_transform_decrypt(message, key)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait MessageReceiver {
|
pub trait MessageReceiver {
|
||||||
@@ -218,7 +263,7 @@ mod message_receiver {
|
|||||||
use nym_crypto::asymmetric::identity;
|
use nym_crypto::asymmetric::identity;
|
||||||
use nym_mixnet_contract_common::Layer;
|
use nym_mixnet_contract_common::Layer;
|
||||||
use nym_topology::{gateway, mix, NymTopology};
|
use nym_topology::{gateway, mix, NymTopology};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
// TODO: is it somehow maybe possible to move it to `topology` and have if conditionally
|
// TODO: is it somehow maybe possible to move it to `topology` and have if conditionally
|
||||||
// available to other modules?
|
// available to other modules?
|
||||||
@@ -226,7 +271,7 @@ mod message_receiver {
|
|||||||
/// tests requiring instance of topology.
|
/// tests requiring instance of topology.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn topology_fixture() -> NymTopology {
|
fn topology_fixture() -> NymTopology {
|
||||||
let mut mixes = BTreeMap::new();
|
let mut mixes = HashMap::new();
|
||||||
mixes.insert(
|
mixes.insert(
|
||||||
1,
|
1,
|
||||||
vec![mix::Node {
|
vec![mix::Node {
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ repository = { workspace = true }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
sphinx-packet = { version = "0.1.0" }
|
sphinx-packet = { version = "0.1.0" }
|
||||||
nym-outfox = { path = "../../../nym-outfox" }
|
|
||||||
thiserror = "1"
|
#[patch.crates-io]
|
||||||
|
#sphinx-packet = { path = "../../../../sphinx" }
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub use nym_outfox::{
|
|
||||||
constants::MIX_PARAMS_LEN, constants::OUTFOX_PACKET_OVERHEAD, error::OutfoxError,
|
|
||||||
};
|
|
||||||
// re-exporting types and constants available in sphinx
|
// re-exporting types and constants available in sphinx
|
||||||
use nym_outfox::packet::OutfoxPacket;
|
|
||||||
pub use sphinx_packet::{
|
pub use sphinx_packet::{
|
||||||
constants::{
|
constants::{
|
||||||
self, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, MAX_PATH_LENGTH, NODE_ADDRESS_LENGTH,
|
self, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, MAX_PATH_LENGTH, NODE_ADDRESS_LENGTH,
|
||||||
@@ -17,101 +13,5 @@ pub use sphinx_packet::{
|
|||||||
payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
|
payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
|
||||||
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
|
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
|
||||||
surb::{SURBMaterial, SURB},
|
surb::{SURBMaterial, SURB},
|
||||||
Error as SphinxError, ProcessedPacket,
|
Error, ProcessedPacket, Result, SphinxPacket,
|
||||||
};
|
};
|
||||||
use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
|
|
||||||
use std::{array::TryFromSliceError, fmt};
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum NymPacketError {
|
|
||||||
#[error("Sphinx error: {0}")]
|
|
||||||
Sphinx(#[from] sphinx_packet::Error),
|
|
||||||
|
|
||||||
#[error("Outfox error: {0}")]
|
|
||||||
Outfox(#[from] nym_outfox::error::OutfoxError),
|
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
FromSlice(#[from] TryFromSliceError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
pub enum NymPacket {
|
|
||||||
Sphinx(SphinxPacket),
|
|
||||||
Outfox(OutfoxPacket),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for NymPacket {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match &self {
|
|
||||||
NymPacket::Sphinx(packet) => f
|
|
||||||
.debug_struct("NymPacket::Sphinx")
|
|
||||||
.field("len", &packet.len())
|
|
||||||
.finish(),
|
|
||||||
NymPacket::Outfox(packet) => f
|
|
||||||
.debug_struct("NymPacket::Outfox")
|
|
||||||
.field("len", &packet.len())
|
|
||||||
.finish(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NymPacket {
|
|
||||||
pub fn sphinx_build<M: AsRef<[u8]>>(
|
|
||||||
size: usize,
|
|
||||||
message: M,
|
|
||||||
route: &[Node],
|
|
||||||
destination: &Destination,
|
|
||||||
delays: &[Delay],
|
|
||||||
) -> Result<NymPacket, NymPacketError> {
|
|
||||||
Ok(NymPacket::Sphinx(
|
|
||||||
SphinxPacketBuilder::new()
|
|
||||||
.with_payload_size(size)
|
|
||||||
.build_packet(message, route, destination, delays)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
pub fn sphinx_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
|
||||||
Ok(NymPacket::Sphinx(SphinxPacket::from_bytes(bytes)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn outfox_build<M: AsRef<[u8]>>(
|
|
||||||
payload: M,
|
|
||||||
route: &[Node],
|
|
||||||
size: Option<usize>,
|
|
||||||
) -> Result<NymPacket, NymPacketError> {
|
|
||||||
Ok(NymPacket::Outfox(OutfoxPacket::build(
|
|
||||||
payload,
|
|
||||||
route.try_into()?,
|
|
||||||
size,
|
|
||||||
)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn outfox_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
|
||||||
Ok(NymPacket::Outfox(OutfoxPacket::try_from(bytes)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
NymPacket::Sphinx(packet) => packet.len(),
|
|
||||||
NymPacket::Outfox(packet) => packet.len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, NymPacketError> {
|
|
||||||
match self {
|
|
||||||
NymPacket::Sphinx(packet) => Ok(packet.to_bytes()),
|
|
||||||
NymPacket::Outfox(packet) => Ok(packet.to_bytes()?),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process(self, node_secret_key: &PrivateKey) -> Result<ProcessedPacket, NymPacketError> {
|
|
||||||
match self {
|
|
||||||
NymPacket::Sphinx(packet) => Ok(packet.process(node_secret_key)?),
|
|
||||||
NymPacket::Outfox(_packet) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,12 +5,17 @@ use crate::config::{Config, Socks5};
|
|||||||
use crate::error::Socks5ClientCoreError;
|
use crate::error::Socks5ClientCoreError;
|
||||||
use crate::socks::{
|
use crate::socks::{
|
||||||
authentication::{AuthenticationMethods, Authenticator, User},
|
authentication::{AuthenticationMethods, Authenticator, User},
|
||||||
server::NymSocksServer,
|
server::SphinxSocksServer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nym_bandwidth_controller::BandwidthController;
|
use nym_bandwidth_controller::BandwidthController;
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
use nym_client_core::client::base_client::helpers::setup_empty_reply_surb_backend;
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
use nym_client_core::client::base_client::non_wasm_helpers;
|
||||||
use nym_client_core::client::base_client::{
|
use nym_client_core::client::base_client::{
|
||||||
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
BaseClientBuilder, ClientInput, ClientOutput, ClientState,
|
||||||
};
|
};
|
||||||
@@ -18,18 +23,11 @@ use nym_client_core::client::key_manager::KeyManager;
|
|||||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use nym_credential_storage::storage::Storage;
|
use nym_credential_storage::storage::Storage;
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::{TaskClient, TaskManager};
|
use nym_task::{TaskClient, TaskManager};
|
||||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||||
use nym_validator_client::Client;
|
use nym_validator_client::Client;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use nym_client_core::client::base_client::helpers::setup_empty_reply_surb_backend;
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
use nym_client_core::client::base_client::non_wasm_helpers;
|
|
||||||
use nym_client_core::config::DebugConfig;
|
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod socks;
|
pub mod socks;
|
||||||
@@ -102,16 +100,13 @@ impl NymClient {
|
|||||||
BandwidthController::new(storage, client)
|
BandwidthController::new(storage, client)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn start_socks5_listener(
|
pub fn start_socks5_listener(
|
||||||
socks5_config: &Socks5,
|
socks5_config: &Socks5,
|
||||||
debug_config: DebugConfig,
|
|
||||||
client_input: ClientInput,
|
client_input: ClientInput,
|
||||||
client_output: ClientOutput,
|
client_output: ClientOutput,
|
||||||
client_status: ClientState,
|
client_status: ClientState,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
packet_type: PacketType,
|
|
||||||
) {
|
) {
|
||||||
info!("Starting socks5 listener...");
|
info!("Starting socks5 listener...");
|
||||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||||
@@ -131,20 +126,14 @@ impl NymClient {
|
|||||||
..
|
..
|
||||||
} = client_status;
|
} = client_status;
|
||||||
|
|
||||||
let packet_size = debug_config
|
|
||||||
.traffic
|
|
||||||
.secondary_packet_size
|
|
||||||
.unwrap_or(debug_config.traffic.primary_packet_size);
|
|
||||||
|
|
||||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||||
let mut sphinx_socks = NymSocksServer::new(
|
let mut sphinx_socks = SphinxSocksServer::new(
|
||||||
socks5_config.get_listening_port(),
|
socks5_config.get_listening_port(),
|
||||||
authenticator,
|
authenticator,
|
||||||
socks5_config.get_provider_mix_address(),
|
socks5_config.get_provider_mix_address(),
|
||||||
self_address,
|
self_address,
|
||||||
shared_lane_queue_lengths,
|
shared_lane_queue_lengths,
|
||||||
socks::client::Config::new(
|
socks::client::Config::new(
|
||||||
packet_size,
|
|
||||||
socks5_config.get_provider_interface_version(),
|
socks5_config.get_provider_interface_version(),
|
||||||
socks5_config.get_socks5_protocol_version(),
|
socks5_config.get_socks5_protocol_version(),
|
||||||
socks5_config.get_send_anonymously(),
|
socks5_config.get_send_anonymously(),
|
||||||
@@ -152,7 +141,6 @@ impl NymClient {
|
|||||||
socks5_config.get_per_request_surbs(),
|
socks5_config.get_per_request_surbs(),
|
||||||
),
|
),
|
||||||
shutdown.clone(),
|
shutdown.clone(),
|
||||||
packet_type,
|
|
||||||
);
|
);
|
||||||
nym_task::spawn_with_report_error(
|
nym_task::spawn_with_report_error(
|
||||||
async move {
|
async move {
|
||||||
@@ -265,17 +253,13 @@ impl NymClient {
|
|||||||
let client_output = started_client.client_output.register_consumer();
|
let client_output = started_client.client_output.register_consumer();
|
||||||
let client_state = started_client.client_state;
|
let client_state = started_client.client_state;
|
||||||
|
|
||||||
info!("{:?}", self.config.get_base().get_packet_type());
|
|
||||||
|
|
||||||
Self::start_socks5_listener(
|
Self::start_socks5_listener(
|
||||||
self.config.get_socks5(),
|
self.config.get_socks5(),
|
||||||
*self.config.get_debug_settings(),
|
|
||||||
client_input,
|
client_input,
|
||||||
client_output,
|
client_output,
|
||||||
client_state,
|
client_state,
|
||||||
self_address,
|
self_address,
|
||||||
started_client.task_manager.subscribe(),
|
started_client.task_manager.subscribe(),
|
||||||
self.config.get_base().get_packet_type(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Client startup finished!");
|
info!("Client startup finished!");
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ use nym_socks5_requests::{
|
|||||||
ConnectionId, RemoteAddress, Socks5ProtocolVersion, Socks5ProviderRequest, Socks5Request,
|
ConnectionId, RemoteAddress, Socks5ProtocolVersion, Socks5ProviderRequest, Socks5Request,
|
||||||
};
|
};
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::params::PacketSize;
|
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::connections::{LaneQueueLengths, TransmissionLane};
|
use nym_task::connections::{LaneQueueLengths, TransmissionLane};
|
||||||
use nym_task::TaskClient;
|
use nym_task::TaskClient;
|
||||||
use pin_project::pin_project;
|
use pin_project::pin_project;
|
||||||
@@ -133,7 +131,6 @@ impl AsyncWrite for StreamState {
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(crate) struct Config {
|
pub(crate) struct Config {
|
||||||
biggest_packet_size: PacketSize,
|
|
||||||
provider_interface_version: ProviderInterfaceVersion,
|
provider_interface_version: ProviderInterfaceVersion,
|
||||||
socks5_protocol_version: Socks5ProtocolVersion,
|
socks5_protocol_version: Socks5ProtocolVersion,
|
||||||
use_surbs_for_responses: bool,
|
use_surbs_for_responses: bool,
|
||||||
@@ -143,7 +140,6 @@ pub(crate) struct Config {
|
|||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
biggest_packet_size: PacketSize,
|
|
||||||
provider_interface_version: ProviderInterfaceVersion,
|
provider_interface_version: ProviderInterfaceVersion,
|
||||||
socks5_protocol_version: Socks5ProtocolVersion,
|
socks5_protocol_version: Socks5ProtocolVersion,
|
||||||
use_surbs_for_responses: bool,
|
use_surbs_for_responses: bool,
|
||||||
@@ -151,7 +147,6 @@ impl Config {
|
|||||||
per_request_surbs: u32,
|
per_request_surbs: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
biggest_packet_size,
|
|
||||||
provider_interface_version,
|
provider_interface_version,
|
||||||
socks5_protocol_version,
|
socks5_protocol_version,
|
||||||
use_surbs_for_responses,
|
use_surbs_for_responses,
|
||||||
@@ -186,7 +181,6 @@ pub(crate) struct SocksClient {
|
|||||||
started_proxy: bool,
|
started_proxy: bool,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
shutdown_listener: TaskClient,
|
shutdown_listener: TaskClient,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SocksClient {
|
impl Drop for SocksClient {
|
||||||
@@ -215,7 +209,6 @@ impl SocksClient {
|
|||||||
self_address: &Recipient,
|
self_address: &Recipient,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
mut shutdown_listener: TaskClient,
|
mut shutdown_listener: TaskClient,
|
||||||
packet_type: Option<PacketType>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// If this task fails and exits, we don't want to send shutdown signal
|
// If this task fails and exits, we don't want to send shutdown signal
|
||||||
shutdown_listener.mark_as_success();
|
shutdown_listener.mark_as_success();
|
||||||
@@ -236,7 +229,6 @@ impl SocksClient {
|
|||||||
started_proxy: false,
|
started_proxy: false,
|
||||||
lane_queue_lengths,
|
lane_queue_lengths,
|
||||||
shutdown_listener,
|
shutdown_listener,
|
||||||
packet_type,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +345,6 @@ impl SocksClient {
|
|||||||
msg.into_bytes(),
|
msg.into_bytes(),
|
||||||
self.config.connection_start_surbs,
|
self.config.connection_start_surbs,
|
||||||
TransmissionLane::ConnectionId(self.connection_id),
|
TransmissionLane::ConnectionId(self.connection_id),
|
||||||
self.packet_type,
|
|
||||||
);
|
);
|
||||||
self.input_sender
|
self.input_sender
|
||||||
.send(input_message)
|
.send(input_message)
|
||||||
@@ -376,7 +367,6 @@ impl SocksClient {
|
|||||||
self.service_provider,
|
self.service_provider,
|
||||||
msg.into_bytes(),
|
msg.into_bytes(),
|
||||||
TransmissionLane::ConnectionId(self.connection_id),
|
TransmissionLane::ConnectionId(self.connection_id),
|
||||||
self.packet_type,
|
|
||||||
);
|
);
|
||||||
self.input_sender
|
self.input_sender
|
||||||
.send(input_message)
|
.send(input_message)
|
||||||
@@ -414,16 +404,12 @@ impl SocksClient {
|
|||||||
let request_version = self.config.request_version();
|
let request_version = self.config.request_version();
|
||||||
|
|
||||||
let recipient = self.service_provider;
|
let recipient = self.service_provider;
|
||||||
let packet_type = self.packet_type;
|
|
||||||
let (stream, _) = ProxyRunner::new(
|
let (stream, _) = ProxyRunner::new(
|
||||||
stream,
|
stream,
|
||||||
local_stream_remote,
|
local_stream_remote,
|
||||||
remote_proxy_target,
|
remote_proxy_target,
|
||||||
conn_receiver,
|
conn_receiver,
|
||||||
input_sender,
|
input_sender,
|
||||||
// FIXME: this does NOT include overhead due to acks or chunking
|
|
||||||
// (so actual true plaintext is smaller)
|
|
||||||
self.config.biggest_packet_size.plaintext_size(),
|
|
||||||
connection_id,
|
connection_id,
|
||||||
Some(self.lane_queue_lengths.clone()),
|
Some(self.lane_queue_lengths.clone()),
|
||||||
self.shutdown_listener.clone(),
|
self.shutdown_listener.clone(),
|
||||||
@@ -446,15 +432,9 @@ impl SocksClient {
|
|||||||
provider_message.into_bytes(),
|
provider_message.into_bytes(),
|
||||||
per_request_surbs,
|
per_request_surbs,
|
||||||
lane,
|
lane,
|
||||||
packet_type,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
InputMessage::new_regular(
|
InputMessage::new_regular(recipient, provider_message.into_bytes(), lane)
|
||||||
recipient,
|
|
||||||
provider_message.into_bytes(),
|
|
||||||
lane,
|
|
||||||
packet_type,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use nym_client_core::client::{
|
|||||||
};
|
};
|
||||||
use nym_socks5_proxy_helpers::connection_controller::Controller;
|
use nym_socks5_proxy_helpers::connection_controller::Controller;
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
use nym_sphinx::params::PacketType;
|
|
||||||
use nym_task::connections::{ConnectionCommandSender, LaneQueueLengths};
|
use nym_task::connections::{ConnectionCommandSender, LaneQueueLengths};
|
||||||
use nym_task::TaskClient;
|
use nym_task::TaskClient;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@@ -18,7 +17,7 @@ use tap::TapFallible;
|
|||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
/// A Socks5 server that listens for connections.
|
/// A Socks5 server that listens for connections.
|
||||||
pub struct NymSocksServer {
|
pub struct SphinxSocksServer {
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
listening_address: SocketAddr,
|
listening_address: SocketAddr,
|
||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
@@ -26,12 +25,10 @@ pub struct NymSocksServer {
|
|||||||
client_config: client::Config,
|
client_config: client::Config,
|
||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
packet_type: PacketType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NymSocksServer {
|
impl SphinxSocksServer {
|
||||||
/// Create a new SphinxSocks instance
|
/// Create a new SphinxSocks instance
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
port: u16,
|
port: u16,
|
||||||
authenticator: Authenticator,
|
authenticator: Authenticator,
|
||||||
@@ -40,13 +37,12 @@ impl NymSocksServer {
|
|||||||
lane_queue_lengths: LaneQueueLengths,
|
lane_queue_lengths: LaneQueueLengths,
|
||||||
client_config: client::Config,
|
client_config: client::Config,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
packet_type: PacketType,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
||||||
// just modify the config
|
// just modify the config
|
||||||
let ip = "127.0.0.1";
|
let ip = "127.0.0.1";
|
||||||
info!("Listening on {}:{}", ip, port);
|
info!("Listening on {}:{}", ip, port);
|
||||||
NymSocksServer {
|
SphinxSocksServer {
|
||||||
authenticator,
|
authenticator,
|
||||||
listening_address: format!("{ip}:{port}").parse().unwrap(),
|
listening_address: format!("{ip}:{port}").parse().unwrap(),
|
||||||
service_provider,
|
service_provider,
|
||||||
@@ -54,7 +50,6 @@ impl NymSocksServer {
|
|||||||
client_config,
|
client_config,
|
||||||
lane_queue_lengths,
|
lane_queue_lengths,
|
||||||
shutdown,
|
shutdown,
|
||||||
packet_type,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +104,6 @@ impl NymSocksServer {
|
|||||||
&self.self_address,
|
&self.self_address,
|
||||||
self.lane_queue_lengths.clone(),
|
self.lane_queue_lengths.clone(),
|
||||||
self.shutdown.clone(),
|
self.shutdown.clone(),
|
||||||
Some(self.packet_type)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
@@ -125,8 +119,8 @@ impl NymSocksServer {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_ = self.shutdown.recv() => {
|
_ = self.shutdown.recv() => {
|
||||||
log::trace!("NymSocksServer: Received shutdown");
|
log::trace!("SphinxSocksServer: Received shutdown");
|
||||||
log::debug!("NymSocksServer: Exiting");
|
log::debug!("SphinxSocksServer: Exiting");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,208 @@
|
|||||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::{BufMut, Bytes, BytesMut};
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::future::Future;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::ops::DerefMut;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::io::AsyncRead;
|
use tokio::io::AsyncRead;
|
||||||
|
use tokio::time::{sleep, Duration, Instant, Sleep};
|
||||||
|
use tokio_util::io::poll_read_buf;
|
||||||
|
|
||||||
// note, min_capacity doesn't mean we're going to always read at least this amount of data,
|
const MAX_READ_AMOUNT: usize = 500 * 1000; // 0.5MB
|
||||||
// it defines the smallest allowed (by yours truly) upper bound
|
const GRACE_DURATION: Duration = Duration::from_millis(1);
|
||||||
const MIN_CAPACITY: usize = 16 * 1024;
|
|
||||||
const DEFAULT_CAPACITY: usize = 64 * 1024;
|
|
||||||
|
|
||||||
pub struct AvailableReader<R> {
|
pub struct AvailableReader<'a, R: AsyncRead + Unpin> {
|
||||||
inner: tokio_util::io::ReaderStream<R>,
|
// TODO: come up with a way to avoid using RefCell (not sure if possible though due to having to
|
||||||
|
// mutably borrow both inner reader and buffer at the same time)
|
||||||
|
buf: RefCell<BytesMut>,
|
||||||
|
inner: RefCell<&'a mut R>,
|
||||||
|
grace_period: Option<Pin<Box<Sleep>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AsyncRead> AvailableReader<R> {
|
impl<'a, R> AvailableReader<'a, R>
|
||||||
pub fn new(reader: R, capacity: Option<usize>) -> Self {
|
where
|
||||||
let capacity = capacity.unwrap_or(DEFAULT_CAPACITY).max(MIN_CAPACITY);
|
R: AsyncRead + Unpin,
|
||||||
|
{
|
||||||
|
const BUF_INCREMENT: usize = 4096;
|
||||||
|
|
||||||
|
pub fn new(reader: &'a mut R) -> Self {
|
||||||
AvailableReader {
|
AvailableReader {
|
||||||
inner: tokio_util::io::ReaderStream::with_capacity(reader, capacity),
|
buf: RefCell::new(BytesMut::with_capacity(Self::BUF_INCREMENT)),
|
||||||
|
inner: RefCell::new(reader),
|
||||||
|
grace_period: Some(Box::pin(sleep(GRACE_DURATION))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AsyncRead + Unpin> Stream for AvailableReader<R> {
|
impl<'a, R: AsyncRead + Unpin> Stream for AvailableReader<'a, R> {
|
||||||
type Item = io::Result<Bytes>;
|
type Item = io::Result<Bytes>;
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
Pin::new(&mut self.inner).poll_next(cx)
|
// if we have no space in buffer left - expand it
|
||||||
|
if !self.buf.borrow().has_remaining_mut() {
|
||||||
|
self.buf.borrow_mut().reserve(Self::BUF_INCREMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: poll_read_buf calls `buf.advance_mut(n)`
|
||||||
|
let poll_res = poll_read_buf(
|
||||||
|
Pin::new(self.inner.borrow_mut().deref_mut()),
|
||||||
|
cx,
|
||||||
|
self.buf.borrow_mut().deref_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
|
match poll_res {
|
||||||
|
Poll::Pending => {
|
||||||
|
// there's nothing for us here, just return whatever we have (assuming we read anything!)
|
||||||
|
if self.buf.borrow().is_empty() {
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
// if exists - check grace period
|
||||||
|
if let Some(grace_period) = self.grace_period.as_mut() {
|
||||||
|
if Pin::new(grace_period).poll(cx).is_pending() {
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = self.buf.replace(BytesMut::new());
|
||||||
|
Poll::Ready(Some(Ok(buf.freeze())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Poll::Ready(Err(err)) => Poll::Ready(Some(Err(err))),
|
||||||
|
Poll::Ready(Ok(n)) => {
|
||||||
|
// if exists - reset grace period
|
||||||
|
if let Some(grace_period) = self.grace_period.as_mut() {
|
||||||
|
let now = Instant::now();
|
||||||
|
grace_period.as_mut().reset(now + GRACE_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we read a non-0 amount, we're not done yet!
|
||||||
|
if n == 0 {
|
||||||
|
let buf = self.buf.replace(BytesMut::new());
|
||||||
|
if !buf.is_empty() {
|
||||||
|
Poll::Ready(Some(Ok(buf.freeze())))
|
||||||
|
} else {
|
||||||
|
Poll::Ready(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// tell the waker we should be polled again!
|
||||||
|
cx.waker().wake_by_ref();
|
||||||
|
|
||||||
|
// if we reached our maximum amount - return it
|
||||||
|
let read_bytes_len = self.buf.borrow().len();
|
||||||
|
if read_bytes_len >= MAX_READ_AMOUNT {
|
||||||
|
let buf = self.buf.replace(BytesMut::new());
|
||||||
|
return Poll::Ready(Some(Ok(buf.freeze())));
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use futures::{poll, StreamExt};
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
use tokio_test::assert_pending;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn available_reader_reads_all_available_data_smaller_than_its_buf() {
|
||||||
|
let data = vec![42u8; 100];
|
||||||
|
let mut reader = Cursor::new(data.clone());
|
||||||
|
|
||||||
|
let mut available_reader = AvailableReader::new(&mut reader);
|
||||||
|
let read_data = available_reader.next().await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(read_data, data);
|
||||||
|
assert!(available_reader.next().await.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn available_reader_reads_all_available_data_bigger_than_its_buf() {
|
||||||
|
let data = vec![42u8; AvailableReader::<Cursor<Vec<u8>>>::BUF_INCREMENT + 100];
|
||||||
|
let mut reader = Cursor::new(data.clone());
|
||||||
|
|
||||||
|
let mut available_reader = AvailableReader::new(&mut reader);
|
||||||
|
let read_data = available_reader.next().await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(read_data, data);
|
||||||
|
assert!(available_reader.next().await.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn available_reader_will_not_wait_for_more_data_if_it_already_has_some() {
|
||||||
|
let first_data_chunk = vec![42u8; 100];
|
||||||
|
let second_data_chunk = vec![123u8; 100];
|
||||||
|
|
||||||
|
let mut reader_mock = tokio_test::io::Builder::new()
|
||||||
|
.read(&first_data_chunk)
|
||||||
|
.wait(Duration::from_millis(100)) // delay is irrelevant, what matters is that we don't get everything immediately
|
||||||
|
.read(&second_data_chunk)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut available_reader = AvailableReader::new(&mut reader_mock);
|
||||||
|
let read_data = available_reader.next().await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(read_data, first_data_chunk);
|
||||||
|
assert_pending!(poll!(available_reader.next()));
|
||||||
|
|
||||||
|
// before dropping the mock, we need to empty it
|
||||||
|
let mut buf = vec![0u8; second_data_chunk.len()];
|
||||||
|
assert_eq!(reader_mock.read(&mut buf).await.unwrap(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn available_reader_will_wait_for_more_data_if_it_doesnt_have_anything() {
|
||||||
|
let data = vec![42u8; 100];
|
||||||
|
|
||||||
|
let mut reader_mock = tokio_test::io::Builder::new()
|
||||||
|
.wait(Duration::from_millis(100))
|
||||||
|
.read(&data)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let mut available_reader = AvailableReader::new(&mut reader_mock);
|
||||||
|
let read_data = available_reader.next().await.unwrap().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(read_data, data);
|
||||||
|
assert!(available_reader.next().await.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
// perhaps the issue of tokio io builder will be resolved in tokio 0.3?
|
||||||
|
// #[tokio::test]
|
||||||
|
// async fn available_reader_will_wait_for_more_data_if_its_within_grace_period() {
|
||||||
|
// let first_data_chunk = vec![42u8; 100];
|
||||||
|
// let second_data_chunk = vec![123u8; 100];
|
||||||
|
//
|
||||||
|
// let combined_chunks: Vec<_> = first_data_chunk
|
||||||
|
// .iter()
|
||||||
|
// .cloned()
|
||||||
|
// .chain(second_data_chunk.iter().cloned())
|
||||||
|
// .collect();
|
||||||
|
//
|
||||||
|
// let mut reader_mock = tokio_test::io::Builder::new()
|
||||||
|
// .read(&first_data_chunk)
|
||||||
|
// .wait(Duration::from_millis(2))
|
||||||
|
// .read(&second_data_chunk)
|
||||||
|
// .build();
|
||||||
|
//
|
||||||
|
// let mut available_reader = AvailableReader {
|
||||||
|
// buf: RefCell::new(BytesMut::with_capacity(4096)),
|
||||||
|
// inner: RefCell::new(&mut reader_mock),
|
||||||
|
// grace_period: Some(delay_for(Duration::from_millis(5))),
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// let read_data = available_reader.next().await.unwrap().unwrap();
|
||||||
|
//
|
||||||
|
// assert_eq!(read_data, combined_chunks);
|
||||||
|
// assert!(available_reader.next().await.is_none())
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
use super::MixProxySender;
|
use super::MixProxySender;
|
||||||
use super::SHUTDOWN_TIMEOUT;
|
use super::SHUTDOWN_TIMEOUT;
|
||||||
use crate::available_reader::AvailableReader;
|
use crate::available_reader::AvailableReader;
|
||||||
use crate::proxy_runner::KEEPALIVE_INTERVAL;
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@@ -36,23 +35,6 @@ async fn send_empty_close<F, S>(
|
|||||||
.expect("BatchRealMessageReceiver has stopped receiving!");
|
.expect("BatchRealMessageReceiver has stopped receiving!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_empty_keepalive<F, S>(
|
|
||||||
connection_id: ConnectionId,
|
|
||||||
message_sender: &mut OrderedMessageSender,
|
|
||||||
mix_sender: &MixProxySender<S>,
|
|
||||||
adapter_fn: F,
|
|
||||||
) where
|
|
||||||
F: Fn(ConnectionId, Vec<u8>, bool) -> S,
|
|
||||||
S: Debug,
|
|
||||||
{
|
|
||||||
log::trace!("Sending keepalive for connection: {connection_id}");
|
|
||||||
let ordered_msg = message_sender.wrap_message(Vec::new()).into_bytes();
|
|
||||||
mix_sender
|
|
||||||
.send(adapter_fn(connection_id, ordered_msg, false))
|
|
||||||
.await
|
|
||||||
.expect("BatchRealMessageReceiver has stopped receiving!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn deal_with_data<F, S>(
|
async fn deal_with_data<F, S>(
|
||||||
read_data: Option<io::Result<Bytes>>,
|
read_data: Option<io::Result<Bytes>>,
|
||||||
@@ -185,7 +167,6 @@ pub(super) async fn run_inbound<F, S>(
|
|||||||
remote_source_address: String,
|
remote_source_address: String,
|
||||||
connection_id: ConnectionId,
|
connection_id: ConnectionId,
|
||||||
mix_sender: MixProxySender<S>,
|
mix_sender: MixProxySender<S>,
|
||||||
available_plaintext_per_mix_packet: usize,
|
|
||||||
adapter_fn: F,
|
adapter_fn: F,
|
||||||
shutdown_notify: Arc<Notify>,
|
shutdown_notify: Arc<Notify>,
|
||||||
lane_queue_lengths: Option<LaneQueueLengths>,
|
lane_queue_lengths: Option<LaneQueueLengths>,
|
||||||
@@ -195,16 +176,12 @@ where
|
|||||||
F: Fn(ConnectionId, Vec<u8>, bool) -> S + Send + 'static,
|
F: Fn(ConnectionId, Vec<u8>, bool) -> S + Send + 'static,
|
||||||
S: Debug,
|
S: Debug,
|
||||||
{
|
{
|
||||||
// TODO: this multiplication by 4 is completely arbitrary here
|
let mut available_reader = AvailableReader::new(&mut reader);
|
||||||
let mut available_reader =
|
|
||||||
AvailableReader::new(&mut reader, Some(available_plaintext_per_mix_packet * 4));
|
|
||||||
let mut message_sender = OrderedMessageSender::new();
|
let mut message_sender = OrderedMessageSender::new();
|
||||||
let shutdown_future = shutdown_notify.notified().then(|_| sleep(SHUTDOWN_TIMEOUT));
|
let shutdown_future = shutdown_notify.notified().then(|_| sleep(SHUTDOWN_TIMEOUT));
|
||||||
|
|
||||||
tokio::pin!(shutdown_future);
|
tokio::pin!(shutdown_future);
|
||||||
|
|
||||||
let mut keepalive_timer = tokio::time::interval(KEEPALIVE_INTERVAL);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
read_data = &mut available_reader.next() => {
|
read_data = &mut available_reader.next() => {
|
||||||
@@ -220,10 +197,6 @@ where
|
|||||||
).await {
|
).await {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
keepalive_timer.reset();
|
|
||||||
}
|
|
||||||
_ = keepalive_timer.tick() => {
|
|
||||||
send_empty_keepalive(connection_id, &mut message_sender, &mix_sender, &adapter_fn).await;
|
|
||||||
}
|
}
|
||||||
_ = &mut shutdown_future => {
|
_ = &mut shutdown_future => {
|
||||||
debug!(
|
debug!(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::connection_controller::ConnectionReceiver;
|
use crate::connection_controller::ConnectionReceiver;
|
||||||
@@ -15,10 +15,6 @@ mod outbound;
|
|||||||
// TODO: make this configurable
|
// TODO: make this configurable
|
||||||
const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(30);
|
const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
|
|
||||||
// Send empty keepalive messages regurarly to keep the connection alive. This should be smaller
|
|
||||||
// than [`MIX_TTL`].
|
|
||||||
const KEEPALIVE_INTERVAL: Duration = Duration::from_secs(60);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProxyMessage {
|
pub struct ProxyMessage {
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
@@ -53,8 +49,6 @@ pub struct ProxyRunner<S> {
|
|||||||
connection_id: ConnectionId,
|
connection_id: ConnectionId,
|
||||||
lane_queue_lengths: Option<LaneQueueLengths>,
|
lane_queue_lengths: Option<LaneQueueLengths>,
|
||||||
|
|
||||||
available_plaintext_per_mix_packet: usize,
|
|
||||||
|
|
||||||
// Listens to shutdown commands from higher up
|
// Listens to shutdown commands from higher up
|
||||||
shutdown_listener: TaskClient,
|
shutdown_listener: TaskClient,
|
||||||
}
|
}
|
||||||
@@ -70,7 +64,6 @@ where
|
|||||||
remote_source_address: String,
|
remote_source_address: String,
|
||||||
mix_receiver: ConnectionReceiver,
|
mix_receiver: ConnectionReceiver,
|
||||||
mix_sender: MixProxySender<S>,
|
mix_sender: MixProxySender<S>,
|
||||||
available_plaintext_per_mix_packet: usize,
|
|
||||||
connection_id: ConnectionId,
|
connection_id: ConnectionId,
|
||||||
lane_queue_lengths: Option<LaneQueueLengths>,
|
lane_queue_lengths: Option<LaneQueueLengths>,
|
||||||
shutdown_listener: TaskClient,
|
shutdown_listener: TaskClient,
|
||||||
@@ -83,7 +76,6 @@ where
|
|||||||
remote_source_address,
|
remote_source_address,
|
||||||
connection_id,
|
connection_id,
|
||||||
lane_queue_lengths,
|
lane_queue_lengths,
|
||||||
available_plaintext_per_mix_packet,
|
|
||||||
shutdown_listener,
|
shutdown_listener,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +96,6 @@ where
|
|||||||
self.remote_source_address.clone(),
|
self.remote_source_address.clone(),
|
||||||
self.connection_id,
|
self.connection_id,
|
||||||
self.mix_sender.clone(),
|
self.mix_sender.clone(),
|
||||||
self.available_plaintext_per_mix_packet,
|
|
||||||
adapter_fn,
|
adapter_fn,
|
||||||
Arc::clone(&shutdown_notify),
|
Arc::clone(&shutdown_notify),
|
||||||
self.lane_queue_lengths.clone(),
|
self.lane_queue_lengths.clone(),
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ pub use manager::{StatusReceiver, StatusSender, TaskClient, TaskManager};
|
|||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub use signal::wait_for_signal_and_error;
|
pub use signal::wait_for_signal_and_error;
|
||||||
|
|
||||||
pub use spawn::{spawn, spawn_with_report_error};
|
pub use spawn::spawn_with_report_error;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use crate::TaskClient;
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub fn spawn<F>(future: F)
|
pub(crate) fn spawn<F>(future: F)
|
||||||
where
|
where
|
||||||
F: Future<Output = ()> + 'static,
|
F: Future<Output = ()> + 'static,
|
||||||
{
|
{
|
||||||
@@ -10,7 +10,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn spawn<F>(future: F)
|
pub(crate) fn spawn<F>(future: F)
|
||||||
where
|
where
|
||||||
F: Future + Send + 'static,
|
F: Future + Send + 'static,
|
||||||
F::Output: Send + 'static,
|
F::Output: Send + 'static,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use nym_bin_common::version_checker;
|
use nym_bin_common::version_checker;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
pub trait Versioned: Clone {
|
pub trait Versioned: Clone {
|
||||||
@@ -40,16 +40,3 @@ where
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, K, V> VersionFilterable<T> for BTreeMap<K, V>
|
|
||||||
where
|
|
||||||
K: Eq + Ord + Clone,
|
|
||||||
V: VersionFilterable<T>,
|
|
||||||
T: Versioned,
|
|
||||||
{
|
|
||||||
fn filter_by_version(&self, expected_version: &str) -> Self {
|
|
||||||
self.iter()
|
|
||||||
.map(|(k, v)| (k.clone(), v.filter_by_version(expected_version)))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -42,26 +42,6 @@ pub struct Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn parse_host(raw: &str) -> Result<NetworkAddress, GatewayConversionError> {
|
|
||||||
raw.parse()
|
|
||||||
.map_err(|err| GatewayConversionError::InvalidAddress {
|
|
||||||
value: raw.to_owned(),
|
|
||||||
source: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_mix_host(
|
|
||||||
host: &NetworkAddress,
|
|
||||||
mix_port: u16,
|
|
||||||
) -> Result<SocketAddr, GatewayConversionError> {
|
|
||||||
Ok(host.to_socket_addrs(mix_port).map_err(|err| {
|
|
||||||
GatewayConversionError::InvalidAddress {
|
|
||||||
value: host.to_string(),
|
|
||||||
source: err,
|
|
||||||
}
|
|
||||||
})?[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn identity(&self) -> &NodeIdentity {
|
pub fn identity(&self) -> &NodeIdentity {
|
||||||
&self.identity_key
|
&self.identity_key
|
||||||
}
|
}
|
||||||
@@ -101,11 +81,23 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
|
|||||||
type Error = GatewayConversionError;
|
type Error = GatewayConversionError;
|
||||||
|
|
||||||
fn try_from(bond: &'a GatewayBond) -> Result<Self, Self::Error> {
|
fn try_from(bond: &'a GatewayBond) -> Result<Self, Self::Error> {
|
||||||
let host = Self::parse_host(&bond.gateway.host)?;
|
let host: NetworkAddress =
|
||||||
|
bond.gateway
|
||||||
|
.host
|
||||||
|
.parse()
|
||||||
|
.map_err(|err| GatewayConversionError::InvalidAddress {
|
||||||
|
value: bond.gateway.host.clone(),
|
||||||
|
source: err,
|
||||||
|
})?;
|
||||||
|
|
||||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
// try to completely resolve the host in the mix situation to avoid doing it every
|
||||||
// single time we want to construct a path
|
// single time we want to construct a path
|
||||||
let mix_host = Self::extract_mix_host(&host, bond.gateway.mix_port)?;
|
let mix_host = host.to_socket_addrs(bond.gateway.mix_port).map_err(|err| {
|
||||||
|
GatewayConversionError::InvalidAddress {
|
||||||
|
value: bond.gateway.host.clone(),
|
||||||
|
source: err,
|
||||||
|
}
|
||||||
|
})?[0];
|
||||||
|
|
||||||
Ok(Node {
|
Ok(Node {
|
||||||
owner: bond.owner.as_str().to_owned(),
|
owner: bond.owner.as_str().to_owned(),
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::filter::VersionFilterable;
|
use crate::filter::VersionFilterable;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
||||||
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
use nym_mixnet_contract_common::GatewayBond;
|
||||||
use nym_sphinx_addressing::nodes::NodeIdentity;
|
use nym_sphinx_addressing::nodes::NodeIdentity;
|
||||||
use nym_sphinx_types::Node as SphinxNode;
|
use nym_sphinx_types::Node as SphinxNode;
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
use std::array::TryFromSliceError;
|
use std::collections::HashMap;
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -53,15 +52,6 @@ pub enum NymTopologyError {
|
|||||||
total_nodes: usize,
|
total_nodes: usize,
|
||||||
layer_distribution: Vec<(MixLayer, usize)>,
|
layer_distribution: Vec<(MixLayer, usize)>,
|
||||||
},
|
},
|
||||||
// We can't import SurbAckRecoveryError due to cyclic dependency, this is a bit dirty
|
|
||||||
#[error("Could not build payload")]
|
|
||||||
PayloadBuilder,
|
|
||||||
|
|
||||||
#[error("Outfox: {0}")]
|
|
||||||
Outfox(#[from] nym_sphinx_types::OutfoxError),
|
|
||||||
|
|
||||||
#[error("{0}")]
|
|
||||||
FromSlice(#[from] TryFromSliceError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -106,45 +96,16 @@ pub type MixLayer = u8;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NymTopology {
|
pub struct NymTopology {
|
||||||
mixes: BTreeMap<MixLayer, Vec<mix::Node>>,
|
mixes: HashMap<MixLayer, Vec<mix::Node>>,
|
||||||
gateways: Vec<gateway::Node>,
|
gateways: Vec<gateway::Node>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NymTopology {
|
impl NymTopology {
|
||||||
pub fn new(mixes: BTreeMap<MixLayer, Vec<mix::Node>>, gateways: Vec<gateway::Node>) -> Self {
|
pub fn new(mixes: HashMap<MixLayer, Vec<mix::Node>>, gateways: Vec<gateway::Node>) -> Self {
|
||||||
NymTopology { mixes, gateways }
|
NymTopology { mixes, gateways }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_detailed(
|
pub fn mixes(&self) -> &HashMap<MixLayer, Vec<mix::Node>> {
|
||||||
mix_details: Vec<MixNodeDetails>,
|
|
||||||
gateway_bonds: Vec<GatewayBond>,
|
|
||||||
) -> Self {
|
|
||||||
nym_topology_from_detailed(mix_details, gateway_bonds)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_mix(&self, mix_id: MixId) -> Option<&mix::Node> {
|
|
||||||
for nodes in self.mixes.values() {
|
|
||||||
for node in nodes {
|
|
||||||
if node.mix_id == mix_id {
|
|
||||||
return Some(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_mix_by_identity(&self, mixnode_identity: IdentityKeyRef) -> Option<&mix::Node> {
|
|
||||||
for nodes in self.mixes.values() {
|
|
||||||
for node in nodes {
|
|
||||||
if node.identity_key.to_base58_string() == mixnode_identity {
|
|
||||||
return Some(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mixes(&self) -> &BTreeMap<MixLayer, Vec<mix::Node>> {
|
|
||||||
&self.mixes
|
&self.mixes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +308,7 @@ pub fn nym_topology_from_detailed(
|
|||||||
mix_details: Vec<MixNodeDetails>,
|
mix_details: Vec<MixNodeDetails>,
|
||||||
gateway_bonds: Vec<GatewayBond>,
|
gateway_bonds: Vec<GatewayBond>,
|
||||||
) -> NymTopology {
|
) -> NymTopology {
|
||||||
let mut mixes = BTreeMap::new();
|
let mut mixes = HashMap::new();
|
||||||
for bond in mix_details
|
for bond in mix_details
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|details| details.bond_information)
|
.map(|details| details.bond_information)
|
||||||
@@ -428,7 +389,7 @@ mod converting_mixes_to_vec {
|
|||||||
..node1.clone()
|
..node1.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut mixes: BTreeMap<MixLayer, Vec<mix::Node>> = BTreeMap::new();
|
let mut mixes: HashMap<MixLayer, Vec<mix::Node>> = HashMap::new();
|
||||||
mixes.insert(1, vec![node1, node2]);
|
mixes.insert(1, vec![node1, node2]);
|
||||||
mixes.insert(2, vec![node3]);
|
mixes.insert(2, vec![node3]);
|
||||||
|
|
||||||
@@ -444,7 +405,7 @@ mod converting_mixes_to_vec {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_an_empty_vec() {
|
fn returns_an_empty_vec() {
|
||||||
let topology = NymTopology::new(BTreeMap::new(), vec![]);
|
let topology = NymTopology::new(HashMap::new(), vec![]);
|
||||||
let mixvec = topology.mixes_as_vec();
|
let mixvec = topology.mixes_as_vec();
|
||||||
assert!(mixvec.is_empty());
|
assert!(mixvec.is_empty());
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-24
@@ -42,28 +42,6 @@ pub struct Node {
|
|||||||
pub version: String,
|
pub version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
|
||||||
pub fn parse_host(raw: &str) -> Result<NetworkAddress, MixnodeConversionError> {
|
|
||||||
raw.parse()
|
|
||||||
.map_err(|err| MixnodeConversionError::InvalidAddress {
|
|
||||||
value: raw.to_owned(),
|
|
||||||
source: err,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_mix_host(
|
|
||||||
host: &NetworkAddress,
|
|
||||||
mix_port: u16,
|
|
||||||
) -> Result<SocketAddr, MixnodeConversionError> {
|
|
||||||
Ok(host.to_socket_addrs(mix_port).map_err(|err| {
|
|
||||||
MixnodeConversionError::InvalidAddress {
|
|
||||||
value: host.to_string(),
|
|
||||||
source: err,
|
|
||||||
}
|
|
||||||
})?[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl filter::Versioned for Node {
|
impl filter::Versioned for Node {
|
||||||
fn version(&self) -> String {
|
fn version(&self) -> String {
|
||||||
self.version.clone()
|
self.version.clone()
|
||||||
@@ -84,11 +62,23 @@ impl<'a> TryFrom<&'a MixNodeBond> for Node {
|
|||||||
type Error = MixnodeConversionError;
|
type Error = MixnodeConversionError;
|
||||||
|
|
||||||
fn try_from(bond: &'a MixNodeBond) -> Result<Self, Self::Error> {
|
fn try_from(bond: &'a MixNodeBond) -> Result<Self, Self::Error> {
|
||||||
let host = Self::parse_host(&bond.mix_node.host)?;
|
let host: NetworkAddress =
|
||||||
|
bond.mix_node
|
||||||
|
.host
|
||||||
|
.parse()
|
||||||
|
.map_err(|err| MixnodeConversionError::InvalidAddress {
|
||||||
|
value: bond.mix_node.host.clone(),
|
||||||
|
source: err,
|
||||||
|
})?;
|
||||||
|
|
||||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
// try to completely resolve the host in the mix situation to avoid doing it every
|
||||||
// single time we want to construct a path
|
// single time we want to construct a path
|
||||||
let mix_host = Self::extract_mix_host(&host, bond.mix_node.mix_port)?;
|
let mix_host = host
|
||||||
|
.to_socket_addrs(bond.mix_node.mix_port)
|
||||||
|
.map_err(|err| MixnodeConversionError::InvalidAddress {
|
||||||
|
value: bond.mix_node.host.clone(),
|
||||||
|
source: err,
|
||||||
|
})?[0];
|
||||||
|
|
||||||
Ok(Node {
|
Ok(Node {
|
||||||
mix_id: bond.mix_id,
|
mix_id: bond.mix_id,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ macro_rules! console_log {
|
|||||||
($($t:tt)*) => ($crate::log(&format_args!($($t)*).to_string()))
|
($($t:tt)*) => ($crate::log(&format_args!($($t)*).to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// will cause messages to be written as if console.warn("...") was called
|
// will cause messages to be written as if console.warm("...") was called
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! console_warn {
|
macro_rules! console_warn {
|
||||||
($($t:tt)*) => ($crate::warn(&format_args!($($t)*).to_string()))
|
($($t:tt)*) => ($crate::warn(&format_args!($($t)*).to_string()))
|
||||||
@@ -50,76 +50,3 @@ pub async fn sleep(ms: i32) -> Result<(), JsValue> {
|
|||||||
js_fut.await?;
|
js_fut.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper that construct a `JsValue` containing an error with the provided message.
|
|
||||||
pub fn simple_js_error<S: AsRef<str>>(message: S) -> JsValue {
|
|
||||||
let js_error = js_sys::Error::new(message.as_ref());
|
|
||||||
JsValue::from(js_error)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! js_error {
|
|
||||||
($($t:tt)*) => {{
|
|
||||||
let js_error = js_sys::Error::new(&format!($($t)*));
|
|
||||||
wasm_bindgen::JsValue::from(js_error)
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maps provided `Result`'s inner values into a pair of `JsValue` that can be returned
|
|
||||||
/// inside a promise (and in particular from inside `future_to_promise`)
|
|
||||||
pub fn into_promise_result<T, E>(res: Result<T, E>) -> Result<JsValue, JsValue>
|
|
||||||
where
|
|
||||||
T: Into<JsValue>,
|
|
||||||
E: Into<JsValue>,
|
|
||||||
{
|
|
||||||
res.map(Into::into).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_promise_err<T, E>(res: Result<T, E>) -> Result<T, JsValue>
|
|
||||||
where
|
|
||||||
E: Into<JsValue>,
|
|
||||||
{
|
|
||||||
res.map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PromisableResult {
|
|
||||||
fn into_promise_result(self) -> Result<JsValue, JsValue>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this should probably get renamed : )
|
|
||||||
pub trait PromisableResultError {
|
|
||||||
type Ok;
|
|
||||||
|
|
||||||
fn map_promise_err(self) -> Result<Self::Ok, JsValue>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E> PromisableResult for Result<T, E>
|
|
||||||
where
|
|
||||||
T: Into<JsValue>,
|
|
||||||
E: Into<JsValue>,
|
|
||||||
{
|
|
||||||
fn into_promise_result(self) -> Result<JsValue, JsValue> {
|
|
||||||
into_promise_result(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E> PromisableResultError for Result<T, E>
|
|
||||||
where
|
|
||||||
E: Into<JsValue>,
|
|
||||||
{
|
|
||||||
type Ok = T;
|
|
||||||
|
|
||||||
fn map_promise_err(self) -> Result<T, JsValue> {
|
|
||||||
map_promise_err(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! check_promise_result {
|
|
||||||
( $x:expr ) => {
|
|
||||||
match $crate::PromisableResultError::map_promise_err($x) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(err) => return js_sys::Promise::reject(&err),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,17 +2,6 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
## [v1.4.0] (2023-04-25)
|
|
||||||
- Allow mixnode operators to decrease their bond amount without having to rebond (will require a lot of testing EXACT reward values to make sure the "unit delegation" isn't broken afterwards) ([#3233])
|
|
||||||
- Fix a few clippy warnings in contract test code ([#3340])
|
|
||||||
- Add --all-targets to clippy for contracts ([#3337])
|
|
||||||
- A branch with all clippy warnings dealt with in contracts ([#3294])
|
|
||||||
|
|
||||||
[#3233]: https://github.com/nymtech/nym/issues/3233
|
|
||||||
[#3340]: https://github.com/nymtech/nym/pull/3340
|
|
||||||
[#3337]: https://github.com/nymtech/nym/pull/3337
|
|
||||||
[#3294]: https://github.com/nymtech/nym/pull/3294
|
|
||||||
|
|
||||||
## [v1.3.1] (2023-04-18)
|
## [v1.3.1] (2023-04-18)
|
||||||
- Add a query to the vesting contract for the amount of delegated tokens towards a particular `mix_id` (might be needed by NG) ([#3228])
|
- Add a query to the vesting contract for the amount of delegated tokens towards a particular `mix_id` (might be needed by NG) ([#3228])
|
||||||
|
|
||||||
|
|||||||
Generated
+135
-396
@@ -2,16 +2,6 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aead"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"generic-array 0.14.7",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aes"
|
name = "aes"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@@ -19,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cipher 0.3.0",
|
"cipher",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"ctr",
|
"ctr",
|
||||||
"opaque-debug 0.3.0",
|
"opaque-debug 0.3.0",
|
||||||
@@ -31,7 +21,7 @@ version = "0.7.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.9",
|
"getrandom 0.2.8",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
@@ -44,15 +34,9 @@ checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.7"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arrayvec"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@@ -102,36 +86,13 @@ dependencies = [
|
|||||||
"opaque-debug 0.2.3",
|
"opaque-debug 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "blake3"
|
|
||||||
version = "1.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef"
|
|
||||||
dependencies = [
|
|
||||||
"arrayref",
|
|
||||||
"arrayvec",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"constant_time_eq",
|
|
||||||
"digest 0.10.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "block-buffer"
|
|
||||||
version = "0.10.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array 0.14.7",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -142,9 +103,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.12.1"
|
version = "3.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
|
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byte-tools"
|
name = "byte-tools"
|
||||||
@@ -189,48 +150,13 @@ dependencies = [
|
|||||||
"keystream",
|
"keystream",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chacha20"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"cipher 0.4.4",
|
|
||||||
"cpufeatures",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chacha20poly1305"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
|
||||||
dependencies = [
|
|
||||||
"aead",
|
|
||||||
"chacha20",
|
|
||||||
"cipher 0.4.4",
|
|
||||||
"poly1305",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cipher"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"inout",
|
|
||||||
"zeroize",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -264,12 +190,6 @@ version = "0.7.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
|
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "constant_time_eq"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmwasm-crypto"
|
name = "cosmwasm-crypto"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@@ -331,56 +251,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.7"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
|
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-epoch",
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"cfg-if",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"memoffset",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-utils"
|
|
||||||
version = "0.8.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crunchy"
|
name = "crunchy"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -393,23 +270,12 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21"
|
checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"subtle 2.4.1",
|
"subtle 2.4.1",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crypto-common"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array 0.14.7",
|
|
||||||
"rand_core 0.6.4",
|
|
||||||
"typenum",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-mac"
|
name = "crypto-mac"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@@ -426,7 +292,7 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
|
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
"subtle 2.4.1",
|
"subtle 2.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -436,14 +302,14 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cipher 0.3.0",
|
"cipher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "curve25519-dalek"
|
name = "curve25519-dalek"
|
||||||
version = "3.2.0"
|
version = "3.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
|
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
@@ -632,18 +498,7 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "digest"
|
|
||||||
version = "0.10.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
|
||||||
dependencies = [
|
|
||||||
"block-buffer 0.10.4",
|
|
||||||
"crypto-common",
|
|
||||||
"subtle 2.4.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -718,7 +573,7 @@ dependencies = [
|
|||||||
"crypto-bigint",
|
"crypto-bigint",
|
||||||
"der",
|
"der",
|
||||||
"ff",
|
"ff",
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
"group",
|
"group",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"sec1",
|
"sec1",
|
||||||
@@ -748,13 +603,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.1"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"errno-dragonfly",
|
"errno-dragonfly",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.48.0",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -818,9 +673,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.7"
|
version = "0.14.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
@@ -841,15 +696,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.9"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -897,15 +750,6 @@ dependencies = [
|
|||||||
"ahash",
|
"ahash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -964,15 +808,6 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inout"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
|
||||||
dependencies = [
|
|
||||||
"generic-array 0.14.7",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@@ -984,13 +819,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.10"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.1",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1053,9 +888,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.142"
|
version = "0.2.140"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libgit2-sys"
|
name = "libgit2-sys"
|
||||||
@@ -1089,9 +924,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.3.4"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf"
|
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lioness"
|
name = "lioness"
|
||||||
@@ -1114,15 +949,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mixnet-vesting-integration-tests"
|
name = "mixnet-vesting-integration-tests"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1149,16 +975,6 @@ dependencies = [
|
|||||||
"libm",
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.2.6",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-coconut-bandwidth"
|
name = "nym-coconut-bandwidth"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1252,7 +1068,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnet-contract"
|
name = "nym-mixnet-contract"
|
||||||
version = "1.4.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"cosmwasm-derive",
|
"cosmwasm-derive",
|
||||||
@@ -1276,7 +1092,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-mixnet-contract-common"
|
name = "nym-mixnet-contract-common"
|
||||||
version = "0.5.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
@@ -1305,22 +1121,6 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nym-outfox"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"blake3",
|
|
||||||
"chacha20",
|
|
||||||
"chacha20poly1305",
|
|
||||||
"curve25519-dalek",
|
|
||||||
"getrandom 0.2.9",
|
|
||||||
"rand",
|
|
||||||
"rayon",
|
|
||||||
"sphinx-packet",
|
|
||||||
"thiserror",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-pemstore"
|
name = "nym-pemstore"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -1359,14 +1159,12 @@ dependencies = [
|
|||||||
name = "nym-sphinx-types"
|
name = "nym-sphinx-types"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nym-outfox",
|
|
||||||
"sphinx-packet",
|
"sphinx-packet",
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract"
|
name = "nym-vesting-contract"
|
||||||
version = "1.4.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.0",
|
"base64 0.21.0",
|
||||||
"cosmwasm-crypto",
|
"cosmwasm-crypto",
|
||||||
@@ -1389,7 +1187,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-vesting-contract-common"
|
name = "nym-vesting-contract-common"
|
||||||
version = "0.6.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"nym-contracts-common",
|
"nym-contracts-common",
|
||||||
@@ -1450,17 +1248,6 @@ version = "0.3.26"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "poly1305"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
|
||||||
dependencies = [
|
|
||||||
"cpufeatures",
|
|
||||||
"opaque-debug 0.3.0",
|
|
||||||
"universal-hash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -1493,9 +1280,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.56"
|
version = "1.0.52"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -1586,7 +1373,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.9",
|
"getrandom 0.2.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1608,51 +1395,29 @@ dependencies = [
|
|||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"rayon-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"crossbeam-deque",
|
|
||||||
"crossbeam-utils",
|
|
||||||
"num_cpus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.3.5"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.8.1"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
|
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.7.1"
|
version = "0.6.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rfc6979"
|
name = "rfc6979"
|
||||||
@@ -1676,16 +1441,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.37.15"
|
version = "0.36.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece"
|
checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1736,12 +1501,6 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sec1"
|
name = "sec1"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -1749,7 +1508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1"
|
checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"der",
|
"der",
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.6",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"subtle 2.4.1",
|
"subtle 2.4.1",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
@@ -1763,9 +1522,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.160"
|
version = "1.0.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@@ -1781,13 +1540,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.160"
|
version = "1.0.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
|
checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.15",
|
"syn 2.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1803,9 +1562,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.96"
|
version = "1.0.94"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -1820,7 +1579,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.15",
|
"syn 2.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1829,7 +1588,7 @@ version = "0.9.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.9.0",
|
"block-buffer",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
@@ -1920,9 +1679,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.15"
|
version = "2.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
checksum = "e8234ae35e70582bfa0f1fedffa6daa248e41dd045310b19800c4a36382c8f60"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1930,16 +1689,28 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "synstructure"
|
||||||
version = "3.5.0"
|
version = "0.12.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1959,7 +1730,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.15",
|
"syn 2.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2024,9 +1795,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.13"
|
version = "0.3.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
checksum = "7d502c968c6a838ead8e69b2ee18ec708802f99db92a0d156705ec9ef801993b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@@ -2044,14 +1815,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "universal-hash"
|
name = "unicode-xid"
|
||||||
version = "0.5.0"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
|
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||||
dependencies = [
|
|
||||||
"crypto-common",
|
|
||||||
"subtle 2.4.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
@@ -2168,22 +1935,50 @@ version = "0.2.84"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.42.2",
|
"windows-targets",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2192,28 +1987,13 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.42.2",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc 0.42.2",
|
"windows_aarch64_msvc",
|
||||||
"windows_i686_gnu 0.42.2",
|
"windows_i686_gnu",
|
||||||
"windows_i686_msvc 0.42.2",
|
"windows_i686_msvc",
|
||||||
"windows_x86_64_gnu 0.42.2",
|
"windows_x86_64_gnu",
|
||||||
"windows_x86_64_gnullvm 0.42.2",
|
"windows_x86_64_gnullvm",
|
||||||
"windows_x86_64_msvc 0.42.2",
|
"windows_x86_64_msvc",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.48.0",
|
|
||||||
"windows_aarch64_msvc 0.48.0",
|
|
||||||
"windows_i686_gnu 0.48.0",
|
|
||||||
"windows_i686_msvc 0.48.0",
|
|
||||||
"windows_x86_64_gnu 0.48.0",
|
|
||||||
"windows_x86_64_gnullvm 0.48.0",
|
|
||||||
"windows_x86_64_msvc 0.48.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2222,89 +2002,47 @@ version = "0.42.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x25519-dalek"
|
name = "x25519-dalek"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
|
checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
@@ -2313,20 +2051,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.6.0"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zeroize_derive",
|
"zeroize_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize_derive"
|
name = "zeroize_derive"
|
||||||
version = "1.4.2"
|
version = "1.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.15",
|
"syn 1.0.109",
|
||||||
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-mixnet-contract"
|
name = "nym-mixnet-contract"
|
||||||
version = "1.4.0"
|
version = "1.3.1"
|
||||||
description = "Nym mixnet contract"
|
description = "Nym mixnet contract"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -22,8 +22,8 @@ name = "mixnet_contract"
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.5.0" }
|
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.6.0" }
|
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.5.0" }
|
||||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.4.0" }
|
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", version = "0.4.0" }
|
||||||
|
|
||||||
cosmwasm-std = { workspace = true }
|
cosmwasm-std = { workspace = true }
|
||||||
|
|||||||
@@ -226,8 +226,6 @@ pub(crate) fn _try_update_gateway_config(
|
|||||||
|
|
||||||
let cfg_update_event = new_gateway_config_update_event(&owner, &proxy, &new_config);
|
let cfg_update_event = new_gateway_config_update_event(&owner, &proxy, &new_config);
|
||||||
|
|
||||||
// clippy beta 1.70.0-beta.1 false positive
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
let mut updated_bond = existing_bond.clone();
|
let mut updated_bond = existing_bond.clone();
|
||||||
updated_bond.gateway.host = new_config.host;
|
updated_bond.gateway.host = new_config.host;
|
||||||
updated_bond.gateway.mix_port = new_config.mix_port;
|
updated_bond.gateway.mix_port = new_config.mix_port;
|
||||||
|
|||||||
@@ -355,8 +355,6 @@ pub(crate) fn _try_remove_mixnode(
|
|||||||
ensure_no_pending_pledge_changes(&pending_changes)?;
|
ensure_no_pending_pledge_changes(&pending_changes)?;
|
||||||
|
|
||||||
// set `is_unbonding` field
|
// set `is_unbonding` field
|
||||||
// clippy beta 1.70.0-beta.1 false positive
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
let mut updated_bond = existing_bond.clone();
|
let mut updated_bond = existing_bond.clone();
|
||||||
updated_bond.is_unbonding = true;
|
updated_bond.is_unbonding = true;
|
||||||
storage::mixnode_bonds().replace(
|
storage::mixnode_bonds().replace(
|
||||||
@@ -418,8 +416,6 @@ pub(crate) fn _try_update_mixnode_config(
|
|||||||
let cfg_update_event =
|
let cfg_update_event =
|
||||||
new_mixnode_config_update_event(existing_bond.mix_id, &owner, &proxy, &new_config);
|
new_mixnode_config_update_event(existing_bond.mix_id, &owner, &proxy, &new_config);
|
||||||
|
|
||||||
// clippy beta 1.70.0-beta.1 false positive
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
let mut updated_bond = existing_bond.clone();
|
let mut updated_bond = existing_bond.clone();
|
||||||
updated_bond.mix_node.host = new_config.host;
|
updated_bond.mix_node.host = new_config.host;
|
||||||
updated_bond.mix_node.mix_port = new_config.mix_port;
|
updated_bond.mix_node.mix_port = new_config.mix_port;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-vesting-contract"
|
name = "nym-vesting-contract"
|
||||||
version = "1.4.0"
|
version = "1.3.1"
|
||||||
description = "Nym vesting contract"
|
description = "Nym vesting contract"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -20,9 +20,9 @@ name = "vesting_contract"
|
|||||||
crate-type = ["cdylib", "rlib"]
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.5.0" }
|
mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", package = "nym-mixnet-contract-common", version = "0.4.0" }
|
||||||
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", package = "nym-contracts-common", version = "0.4.0" }
|
||||||
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.6.0" }
|
vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vesting-contract", package = "nym-vesting-contract-common", version = "0.5.0" }
|
||||||
|
|
||||||
cosmwasm-std = { workspace = true }
|
cosmwasm-std = { workspace = true }
|
||||||
cosmwasm-derive = { workspace = true }
|
cosmwasm-derive = { workspace = true }
|
||||||
|
|||||||
@@ -135,8 +135,8 @@ pub fn try_withdraw_vested_coins(
|
|||||||
return Err(ContractError::WrongDenom(amount.denom, mix_denom));
|
return Err(ContractError::WrongDenom(amount.denom, mix_denom));
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = info.sender;
|
let address = info.sender.clone();
|
||||||
let account = account_from_address(address.as_str(), deps.storage, deps.api)?;
|
let account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||||
if address != account.owner_address() {
|
if address != account.owner_address() {
|
||||||
return Err(ContractError::NotOwner(account.owner_address().to_string()));
|
return Err(ContractError::NotOwner(account.owner_address().to_string()));
|
||||||
}
|
}
|
||||||
@@ -170,9 +170,9 @@ pub fn try_transfer_ownership(
|
|||||||
info: MessageInfo,
|
info: MessageInfo,
|
||||||
deps: DepsMut<'_>,
|
deps: DepsMut<'_>,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
let address = info.sender;
|
let address = info.sender.clone();
|
||||||
let to_address = deps.api.addr_validate(&to_address)?;
|
let to_address = deps.api.addr_validate(&to_address)?;
|
||||||
let mut account = account_from_address(address.as_str(), deps.storage, deps.api)?;
|
let mut account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||||
if address == account.owner_address() {
|
if address == account.owner_address() {
|
||||||
account.transfer_ownership(&to_address, deps.storage)?;
|
account.transfer_ownership(&to_address, deps.storage)?;
|
||||||
Ok(Response::new().add_event(new_ownership_transfer_event(&address, &to_address)))
|
Ok(Response::new().add_event(new_ownership_transfer_event(&address, &to_address)))
|
||||||
@@ -194,9 +194,9 @@ pub fn try_update_staking_address(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = info.sender;
|
let address = info.sender.clone();
|
||||||
let to_address = to_address.and_then(|x| deps.api.addr_validate(&x).ok());
|
let to_address = to_address.and_then(|x| deps.api.addr_validate(&x).ok());
|
||||||
let mut account = account_from_address(address.as_str(), deps.storage, deps.api)?;
|
let mut account = account_from_address(info.sender.as_str(), deps.storage, deps.api)?;
|
||||||
if address == account.owner_address() {
|
if address == account.owner_address() {
|
||||||
let old = account.staking_address().cloned();
|
let old = account.staking_address().cloned();
|
||||||
account.update_staking_address(to_address.clone(), deps.storage)?;
|
account.update_staking_address(to_address.clone(), deps.storage)?;
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
|
|||||||
[preprocessor.variables.variables]
|
[preprocessor.variables.variables]
|
||||||
# code prerequisites versions
|
# code prerequisites versions
|
||||||
minimum_rust_version = "1.66"
|
minimum_rust_version = "1.66"
|
||||||
platform_release_version = "v1.1.16"
|
# minimum_node_version = ""
|
||||||
upcoming_platform_release_version = "v1.1.17" # to use when adding 'edit on github' plugin
|
# nym platform code most recent release
|
||||||
mix_node_release_version = "v1.1.17"
|
platform_release_version = "v1.1.15"
|
||||||
#
|
|
||||||
[preprocessor.last-changed]
|
[preprocessor.last-changed]
|
||||||
command = "mdbook-last-changed"
|
command = "mdbook-last-changed"
|
||||||
renderer = ["html"]
|
renderer = ["html"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[book]
|
[book]
|
||||||
title = "Nym Docs v1.1.16"
|
title = "Nym Docs v1.1.15"
|
||||||
authors = ["Max Hampshire"]
|
authors = ["Max Hampshire"]
|
||||||
description = "Nym technical documentation"
|
description = "Nym technical documentation"
|
||||||
language = "en"
|
language = "en"
|
||||||
@@ -48,9 +48,8 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
|
|||||||
# https://gitlab.com/tglman/mdbook-variables/
|
# https://gitlab.com/tglman/mdbook-variables/
|
||||||
[preprocessor.variables.variables]
|
[preprocessor.variables.variables]
|
||||||
minimum_rust_version = "1.66"
|
minimum_rust_version = "1.66"
|
||||||
platform_release_version = "v1.1.16"
|
platform_release_version = "v1.1.15"
|
||||||
upcoming_platform_release_version = "v1.1.17" # to use in 'edit page on github' plugin (coming soon)
|
mix_node_release_version = "v1.1.16"
|
||||||
mix_node_release_version = "v1.1.17"
|
|
||||||
# used by the cmdrun preprocessor - relative path from inside src/<dir>
|
# used by the cmdrun preprocessor - relative path from inside src/<dir>
|
||||||
# binaries_path = '../../../../target/release/'
|
# binaries_path = '../../../../target/release/'
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user