Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f0c427734 | |||
| 7dfc396f4f | |||
| 2bf44db72f | |||
| ebfecba933 |
@@ -19,16 +19,6 @@ jobs:
|
||||
node-version: 16
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Build dependencies
|
||||
run: yarn && yarn build
|
||||
- name: Build storybook
|
||||
|
||||
@@ -36,16 +36,6 @@ jobs:
|
||||
node-version: 16
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build packages
|
||||
|
||||
+2
-1
@@ -43,4 +43,5 @@ envs/qwerty.env
|
||||
.parcel-cache
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
foxyfox.env
|
||||
foxyfox.env
|
||||
gateway/deploy.sh
|
||||
@@ -4,14 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.23] (2023-06-27)
|
||||
|
||||
- nym-cli: add client identity key signing support ([#3576])
|
||||
- Don't fully turn off background task when cover traffic is disabled ([#3596])
|
||||
|
||||
[#3576]: https://github.com/nymtech/nym/issues/3576
|
||||
[#3596]: https://github.com/nymtech/nym/pull/3596
|
||||
|
||||
## [v1.1.22] (2023-06-20)
|
||||
|
||||
- CLI tool for querying network-requesters ([#3539])
|
||||
|
||||
Generated
+1078
-264
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.23"
|
||||
version = "1.1.22"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// all variable size data is always prefixed with u64 length
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// all variable size data is always prefixed with u64 length
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::ErrorKind;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.23"
|
||||
version = "1.1.22"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -94,7 +94,6 @@ impl From<Init> for OverrideConfig {
|
||||
use_anonymous_replies: init_config.use_reply_surbs,
|
||||
fastmode: init_config.fastmode,
|
||||
no_cover: init_config.no_cover,
|
||||
medium_toggle: false,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
outfox: false,
|
||||
|
||||
@@ -19,7 +19,7 @@ use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -72,7 +72,6 @@ pub(crate) struct OverrideConfig {
|
||||
use_anonymous_replies: Option<bool>,
|
||||
fastmode: bool,
|
||||
no_cover: bool,
|
||||
medium_toggle: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
@@ -92,10 +91,6 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let disable_cover_traffic_with_keepalive = args.medium_toggle;
|
||||
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
|
||||
let no_per_hop_delays = args.medium_toggle;
|
||||
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
@@ -106,17 +101,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
BaseClientConfig::with_high_default_traffic_volume,
|
||||
args.fastmode,
|
||||
)
|
||||
.with_base(
|
||||
// NOTE: This interacts with disabling cover traffic fully, so we want to this to be set before
|
||||
BaseClientConfig::with_disabled_cover_traffic_with_keepalive,
|
||||
disable_cover_traffic_with_keepalive,
|
||||
)
|
||||
.with_base(
|
||||
BaseClientConfig::with_secondary_packet_size,
|
||||
secondary_packet_size,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_no_per_hop_delays, no_per_hop_delays)
|
||||
// NOTE: see comment above about the order of the other disble cover traffic config
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
|
||||
@@ -60,11 +60,6 @@ pub(crate) struct Run {
|
||||
#[clap(long, hide = true)]
|
||||
no_cover: bool,
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[clap(long, hide = true)]
|
||||
medium_toggle: bool,
|
||||
|
||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long, hide = true)]
|
||||
@@ -82,7 +77,6 @@ impl From<Run> for OverrideConfig {
|
||||
use_anonymous_replies: run_config.use_anonymous_replies,
|
||||
fastmode: run_config.fastmode,
|
||||
no_cover: run_config.no_cover,
|
||||
medium_toggle: run_config.medium_toggle,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
outfox: run_config.outfox,
|
||||
|
||||
@@ -3,6 +3,3 @@ clippy:
|
||||
|
||||
test:
|
||||
wasm-pack test --node
|
||||
|
||||
wasm-build:
|
||||
wasm-pack build
|
||||
@@ -8,7 +8,6 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"build:wasm": "cd ../ && make wasm-build",
|
||||
"start": "webpack-dev-server --port 8001"
|
||||
},
|
||||
"repository": {
|
||||
@@ -37,4 +36,4 @@
|
||||
"dependencies": {
|
||||
"@nymproject/nym-client-wasm": "file:../pkg"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,371 +12,370 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
importScripts("nym_client_wasm.js");
|
||||
importScripts('nym_client_wasm.js');
|
||||
|
||||
console.log("Initializing worker");
|
||||
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,
|
||||
ClientStorage,
|
||||
current_network_topology,
|
||||
make_key,
|
||||
make_key2,
|
||||
NymNodeTester,
|
||||
WasmGateway,
|
||||
WasmMixNode,
|
||||
WasmNymTopology,
|
||||
default_debug,
|
||||
NymClientBuilder,
|
||||
NymClient,
|
||||
set_panic_hook,
|
||||
Config,
|
||||
GatewayEndpointConfig,
|
||||
ClientStorage,
|
||||
current_network_topology,
|
||||
make_key,
|
||||
make_key2
|
||||
} = wasm_bindgen;
|
||||
|
||||
let client = null;
|
||||
let tester = null;
|
||||
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
|
||||
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 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 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 mixnodes = new Map();
|
||||
mixnodes.set(1, [l1Mixnode]);
|
||||
mixnodes.set(2, [l2Mixnode]);
|
||||
mixnodes.set(3, [l3Mixnode]);
|
||||
|
||||
const gateways = [gateway];
|
||||
|
||||
return new WasmNymTopology(mixnodes, gateways);
|
||||
const gateways = [gateway];
|
||||
|
||||
return new WasmNymTopology(mixnodes, gateways)
|
||||
}
|
||||
|
||||
function printAndDisplayTestResult(result) {
|
||||
result.log_details();
|
||||
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,
|
||||
},
|
||||
});
|
||||
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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function testWithTester() {
|
||||
// A) construct with hardcoded topology
|
||||
const topology = dummyTopology();
|
||||
const nodeTester = await new NymNodeTester(topology, preferredGateway);
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
|
||||
// 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(topology, preferredGateway);
|
||||
//
|
||||
// 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(validator, preferredGateway)
|
||||
// A) construct with hardcoded topology
|
||||
const topology = dummyTopology()
|
||||
const nodeTester = await new NymNodeTester(topology, preferredGateway);
|
||||
|
||||
// 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(topology, undefined, preferredGateway);
|
||||
//
|
||||
// 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(validator, undefined, preferredGateway)
|
||||
// D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
|
||||
// const topology = dummyTopology()
|
||||
// const nodeTester = await new NymNodeTester(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(topology, undefined, preferredGateway);
|
||||
//
|
||||
// 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(validator, undefined, preferredGateway)
|
||||
|
||||
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...");
|
||||
// D, E, F) you also don't have to specify the gateway. if you don't, a random one (from your topology) will be used
|
||||
// const topology = dummyTopology()
|
||||
// const nodeTester = await new NymNodeTester(topology);
|
||||
|
||||
let result = await nodeTester.test_node(mixnodeIdentity);
|
||||
printAndDisplayTestResult(result);
|
||||
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 testerReconnection() {
|
||||
const validator = "https://qwerty-validator-api.qa.nymte.ch/api";
|
||||
const nodeTester = await NymNodeTester.new_with_api(validator);
|
||||
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
const nodeTester = await NymNodeTester.new_with_api(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...");
|
||||
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 result1 = await nodeTester.test_node(mixnodeIdentity);
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
await nodeTester.disconnect_from_gateway();
|
||||
let result1 = await nodeTester.test_node(mixnodeIdentity);
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await nodeTester.disconnect_from_gateway();
|
||||
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise((r) => setTimeout(r, 5000));
|
||||
console.log("sleeping for 5s");
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
await nodeTester.reconnect_to_gateway();
|
||||
let result2 = await nodeTester.test_node(mixnodeIdentity);
|
||||
await nodeTester.reconnect_to_gateway();
|
||||
let result2 = await nodeTester.test_node(mixnodeIdentity);
|
||||
|
||||
printAndDisplayTestResult(result1);
|
||||
printAndDisplayTestResult(result2);
|
||||
printAndDisplayTestResult(result1)
|
||||
printAndDisplayTestResult(result2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function testWithNymClient() {
|
||||
const topology = dummyTopology();
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const topology = dummyTopology()
|
||||
|
||||
let received = 0;
|
||||
let received = 0
|
||||
|
||||
const onMessageHandler = (message) => {
|
||||
received += 1;
|
||||
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(topology, onMessageHandler, preferredGateway)
|
||||
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: "ReceiveMessage",
|
||||
args: {
|
||||
message,
|
||||
senderTag: undefined,
|
||||
isTestPacket: true,
|
||||
},
|
||||
kind: 'Ready',
|
||||
args: {
|
||||
selfAddress,
|
||||
},
|
||||
});
|
||||
|
||||
// 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(
|
||||
topology,
|
||||
onMessageHandler,
|
||||
preferredGateway
|
||||
);
|
||||
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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" });
|
||||
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();
|
||||
// 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.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);
|
||||
debug.topology_refresh_rate_ms = BigInt(60000)
|
||||
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const validator = "https://qwerty-validator-api.qa.nymte.ch/api";
|
||||
const preferredGateway = "336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9";
|
||||
const validator = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
|
||||
const config = new Config("my-awesome-wasm-client", validator, debug);
|
||||
const config = new Config('my-awesome-wasm-client', validator, debug);
|
||||
|
||||
const onMessageHandler = (message) => {
|
||||
console.log(message);
|
||||
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: "ReceiveMessage",
|
||||
args: {
|
||||
message,
|
||||
},
|
||||
kind: 'Ready',
|
||||
args: {
|
||||
selfAddress,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
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;
|
||||
// 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 messWithStorage() {
|
||||
self.onmessage = async (event) => {
|
||||
if (event.data && event.data.kind) {
|
||||
switch (event.data.kind) {
|
||||
case "TestPacket": {
|
||||
const { mixnodeIdentity } = event.data.args;
|
||||
console.log("button clicked...", mixnodeIdentity);
|
||||
self.onmessage = async event => {
|
||||
if (event.data && event.data.kind) {
|
||||
switch (event.data.kind) {
|
||||
case 'TestPacket': {
|
||||
const { mixnodeIdentity } = event.data.args;
|
||||
console.log("button clicked...", mixnodeIdentity);
|
||||
|
||||
let id1 = "one";
|
||||
let id2 = "two";
|
||||
let id1 = "one";
|
||||
let id2 = "two";
|
||||
|
||||
console.log("making store1 NO-ENC");
|
||||
let _storage1 = await ClientStorage.new_unencrypted(id1);
|
||||
console.log("making store1 NO-ENC");
|
||||
let _storage1 = await ClientStorage.new_unencrypted(id1);
|
||||
|
||||
console.log("making store2 ENC");
|
||||
let _storage2 = await new ClientStorage(id2, "my-secret-password");
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store1 WITH PASSWORD")
|
||||
// let _storage1_alt = await new ClientStorage(id1, "password");
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store2 WITHOUT PASSWORD")
|
||||
// let _storage2_alt = await ClientStorage.new_unencrypted(id2);
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store2 with WRONG PASSWORD")
|
||||
// let _storage2_bad = await new ClientStorage(id2, "bad-password")
|
||||
console.log("making store2 ENC")
|
||||
let _storage2 = await new ClientStorage(id2, "my-secret-password");
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store1 WITH PASSWORD")
|
||||
// let _storage1_alt = await new ClientStorage(id1, "password");
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store2 WITHOUT PASSWORD")
|
||||
// let _storage2_alt = await ClientStorage.new_unencrypted(id2);
|
||||
//
|
||||
//
|
||||
//
|
||||
// console.log("attempting to use store2 with WRONG PASSWORD")
|
||||
// let _storage2_bad = await new ClientStorage(id2, "bad-password")
|
||||
|
||||
//
|
||||
// console.log("read1: ", await storage1.read());
|
||||
// console.log("read2: ", await storage2.read());
|
||||
//
|
||||
// console.log("store1: ", await storage1.store("FOOMP"));
|
||||
//
|
||||
// console.log("read1: ", await storage1.read());
|
||||
// console.log("read2: ", await storage2.read());
|
||||
|
||||
//
|
||||
// console.log("read1: ", await storage1.read());
|
||||
// console.log("read2: ", await storage2.read());
|
||||
//
|
||||
// console.log("store1: ", await storage1.store("FOOMP"));
|
||||
//
|
||||
// console.log("read1: ", await storage1.read());
|
||||
// console.log("read2: ", await storage2.read());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// load WASM package
|
||||
await wasm_bindgen("nym_client_wasm_bg.wasm");
|
||||
console.log("Loaded WASM");
|
||||
// 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();
|
||||
// sets up better stack traces in case of in-rust panics
|
||||
set_panic_hook();
|
||||
|
||||
// show reconnection capabilities
|
||||
// await testerReconnection()
|
||||
// show reconnection capabilities
|
||||
// await testerReconnection()
|
||||
|
||||
// run test on simplified and dedicated tester:
|
||||
await testWithTester();
|
||||
// run test on simplified and dedicated tester:
|
||||
await testWithTester()
|
||||
|
||||
// 'Normal' client setup (to send 'normal' messages)
|
||||
// await normalNymClientUsage()
|
||||
// hook-up the whole client for testing
|
||||
// await testWithNymClient()
|
||||
|
||||
// 'Normal' client setup (to send 'normal' messages)
|
||||
// await normalNymClientUsage()
|
||||
}
|
||||
|
||||
// Let's get started!
|
||||
main();
|
||||
main();
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver};
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::{
|
||||
|
||||
@@ -137,46 +137,14 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn with_disabled_cover_traffic_with_keepalive(mut self, disabled: bool) -> Self {
|
||||
if disabled {
|
||||
self.set_no_cover_traffic_with_keepalive()
|
||||
}
|
||||
self
|
||||
}
|
||||
pub fn set_no_cover_traffic_with_keepalive(&mut self) {
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
self.debug.cover_traffic.loop_cover_traffic_average_delay = Duration::from_secs(5);
|
||||
}
|
||||
|
||||
pub fn with_disabled_topology_refresh(mut self, disable_topology_refresh: bool) -> Self {
|
||||
self.debug.topology.disable_refreshing = disable_topology_refresh;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_no_per_hop_delays(mut self, no_per_hop_delays: bool) -> Self {
|
||||
if no_per_hop_delays {
|
||||
self.set_no_per_hop_delays()
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_no_per_hop_delays(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::ZERO;
|
||||
self.debug.acknowledgements.average_ack_delay = Duration::ZERO;
|
||||
}
|
||||
|
||||
pub fn with_secondary_packet_size(mut self, secondary_packet_size: Option<PacketSize>) -> Self {
|
||||
self.set_secondary_packet_size(secondary_packet_size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_secondary_packet_size(&mut self, secondary_packet_size: Option<PacketSize>) {
|
||||
self.debug.traffic.secondary_packet_size = secondary_packet_size;
|
||||
pub fn set_no_cover_traffic(&mut self) {
|
||||
self.debug.cover_traffic.disable_loop_cover_traffic_stream = true;
|
||||
self.debug.traffic.disable_main_poisson_packet_distribution = true;
|
||||
}
|
||||
|
||||
pub fn set_custom_version(&mut self, version: &str) {
|
||||
@@ -314,7 +282,7 @@ impl Client {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
#[serde(default)]
|
||||
pub struct Traffic {
|
||||
/// The parameter of Poisson distribution determining how long, on average,
|
||||
/// sent packet is going to be delayed at any given mix node.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::GatewayClientError;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{nym_api, ValidatorClientError};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nym_api::error::NymAPIError;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TODO: There's a significant argument to pull those out of the package and make a PR on https://github.com/cosmos/cosmos-rust/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// TODO: expose query-related capabilities to wasm client...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to code generated by JsonSchema
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to code generated by JsonSchema
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to code generated by JsonSchema
|
||||
@@ -88,7 +88,7 @@ impl MixNodeDetails {
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeRewarding {
|
||||
/// Information provided by the operator that influence the cost function.
|
||||
/// Information provided by the operator that influence the cost function.
|
||||
pub cost_params: MixNodeCostParams,
|
||||
|
||||
/// Total pledge and compounded reward earned by the node operator.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::delegation::OwnerProxySubKey;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::MixnetContractError;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::encryption_key::{SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::ChunkingError;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::packet::{FramedNymPacket, Header};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::message::{NymMessage, ACK_OVERHEAD, OUTFOX_ACK_OVERHEAD};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::constants::{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::helpers::must_get_gateway_bond_by_owner;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod queries;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::constants::CONTRACT_STATE_KEY;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::{coin, Addr, Coin, DepsMut, Env, MessageInfo, Response, Storage};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::storage;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::constants::{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -61,7 +61,6 @@ The validator binary can be compiled by running the following commands:
|
||||
```
|
||||
git clone https://github.com/nymtech/nyxd.git
|
||||
cd nyxd
|
||||
git checkout release/<nyxd_version>
|
||||
|
||||
# Mainnet
|
||||
make build
|
||||
@@ -78,17 +77,43 @@ At this point, you will have a copy of the `nyxd` binary in your `build/` direct
|
||||
|
||||
You should see help text print out.
|
||||
|
||||
### Linking `nyxd` to `libwasmvm.so`
|
||||
The `nyxd` binary and the `libwasmvm.so` shared object library binary have been compiled. `libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts.
|
||||
|
||||
`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`.
|
||||
```admonish caution title=""
|
||||
If you have compiled these files locally and need to upload both of them to the server on which the validator will run, **or** downloaded a pre-compiled binary from Github, you need to locate and link these files in slightly different ways, outlined below. If you have instead compiled them on the server skip to the step outlining setting `LD_LIBRARY PATH` below.
|
||||
```
|
||||
|
||||
If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page.
|
||||
To locate these files on your system **if you downloaded a pre-compiled binary from Github** run:
|
||||
|
||||
If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location.
|
||||
```
|
||||
WASMVM_SO=$(ldd path/to/nyxd/binary | grep libwasmvm.so | awk '{ print $3 }')
|
||||
ls ${WASMVM_SO}
|
||||
```
|
||||
|
||||
Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`.
|
||||
e.g. if you downloaded your `nyxd` binary to `/root` then you would replace `ldd path/to/nyxd/binary` with `ldd nyxd` in the above command.
|
||||
|
||||
|
||||
To locate these files on your system **if you uploaded your validator after compiling it on a local machine** run:
|
||||
|
||||
```
|
||||
WASMVM_SO=$(ldd build/nyxd | grep libwasmvm.so | awk '{ print $3 }')
|
||||
ls ${WASMVM_SO}
|
||||
```
|
||||
|
||||
The above commands will output something like:
|
||||
|
||||
```
|
||||
'/home/username/go/pkg/mod/github.com/!cosm!wasm/wasmvm@v0.13.0/api/libwasmvm.so'
|
||||
```
|
||||
|
||||
When you upload your `nyxd` binary, you'll need to tell it where `libwasmvm.so` is when you start your validator, or it will not run. If you have compiled them on your server then this is not necessary, as the compiled `nyxd` already has access to `libwasmvm.so`.
|
||||
|
||||
Upload both `nyxd` and `libwasmvm.so` to your validator machine. If `nyxd` can't find `libwasmvm.so` you will see an error like the following:
|
||||
|
||||
```
|
||||
./nyxd: error while loading shared libraries: libwasmvm.so: cannot open shared object file: No such file or directory
|
||||
```
|
||||
|
||||
### Adding `nyxd` to your `$PATH`
|
||||
You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` file, and add that to our path. Replace `/home/youruser/path/to/nym/binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder:
|
||||
|
||||
```
|
||||
@@ -591,12 +616,6 @@ nyxd tx slashing unjail
|
||||
--fees=7000unyxt
|
||||
```
|
||||
|
||||
### Upgrading your validator
|
||||
|
||||
Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process.
|
||||
|
||||
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8).
|
||||
|
||||
#### Common reasons for your validator being jailed
|
||||
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
@@ -47,16 +47,20 @@ The example above involves ephemeral keys - if we want to create and then mainta
|
||||
As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function handles checking for keys in a storage location, loading them if present, or creating them and storing them if not, making client key management very simple.
|
||||
|
||||
### Manually handling storage
|
||||
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_storage.rs`)
|
||||
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_keys_and_config.rs`)
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_storage.rs}}
|
||||
{{#include ../../../../sdk/rust/nym-sdk/examples/manually_handle_keys_and_config.rs}}
|
||||
```
|
||||
|
||||
### Anonymous replies with SURBs
|
||||
Both functions used to send messages through the mixnet (`send_str` and `send_bytes`) send a pre-determined number of SURBs along with their messages by default.
|
||||
|
||||
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/sdk/rust/nym-sdk/src/mixnet/client.rs#L36).
|
||||
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/sdk/rust/nym-sdk/src/mixnet/client.rs#L35):
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../sdk/rust/nym-sdk/src/mixnet/client.rs:30}}
|
||||
```
|
||||
|
||||
You can read more about how SURBs function under the hood [here](../architecture/traffic-flow.md#private-replies-using-surbs).
|
||||
|
||||
|
||||
@@ -5,23 +5,23 @@ The Nym Desktop Wallet lets you interact with your Nym node and to delegate stak
|
||||
|
||||
You can download it for Mac, Windows, or Linux.
|
||||
|
||||
[](https://github.com/nymtech/nym/releases/tag/nym-wallet-v1.2.4)
|
||||
[](https://github.com/nymtech/nym/releases/tag/nym-wallet-{{platform_release_version}})
|
||||
|
||||
### Bypassing security warnings
|
||||
|
||||
On Windows you will see a security warning pop up when you attempt to run the wallet. We are in the process of getting app store keys from Microsoft so that this doesn't happen. See the section below for details on steps to bypass these.
|
||||
On Windows you will see a security warning pop up when you attempt to run the wallet. We are in the process of getting app store keys from Microsoft so that this doesn't happen. See the section below for details on steps to bypass these.
|
||||
|
||||
#### Linux
|
||||
#### Linux
|
||||
|
||||
You will need to `chmod +x` the AppImage in the terminal (or give it execute permission in your file browser) before it will run.
|
||||
You will need to `chmod +x` the AppImage in the terminal (or give it execute permission in your file browser) before it will run.
|
||||
|
||||
#### Windows
|
||||
#### Windows
|
||||
|
||||
_You will still encounter warnings when opening the wallet on Windows. This is because - although the wallet is approved by Microsoft - it has less than 10 thousand downloads at the current time. Once the wallet has passed this threshold, this warning will disappear._
|
||||
|
||||
Follow the steps below to bypass the warnings.
|
||||
Follow the steps below to bypass the warnings.
|
||||
|
||||
* Select more-info after clicking the msi installer app:
|
||||
* Select more-info after clicking the msi installer app:
|
||||
|
||||

|
||||
|
||||
@@ -29,7 +29,7 @@ Follow the steps below to bypass the warnings.
|
||||
|
||||

|
||||
|
||||
* Follow the installer instructions:
|
||||
* Follow the installer instructions:
|
||||
|
||||

|
||||
|
||||
@@ -39,7 +39,7 @@ Follow the steps below to bypass the warnings.
|
||||
|
||||
### For developers
|
||||
|
||||
If you would like to the compile the wallet yourself, follow the instructions below.
|
||||
If you would like to the compile the wallet yourself, follow the instructions below.
|
||||
|
||||
> Please note that the wallet has currently only been built on the operating systems for which there are binaries as listed above. If you find an issue or any additional prerequisties, please create an issue or PR against `develop` on [Github](https://github.com/nymtech/docs).
|
||||
|
||||
@@ -85,22 +85,22 @@ sudo apt install pkg-config build-essential libssl-dev curl jq
|
||||
|
||||
### Removing signing errors when building in development mode
|
||||
|
||||
If you're wanting to build the wallet yourself, you will need to make a few modifications to the file located at `nym-wallet/src-tauri/tauri.conf.json` before doing so. These relate to the wallet being accepted by Mac and Windows app stores, and so aren't relevant to you when building and running the wallet yourself.
|
||||
If you're wanting to build the wallet yourself, you will need to make a few modifications to the file located at `nym-wallet/src-tauri/tauri.conf.json` before doing so. These relate to the wallet being accepted by Mac and Windows app stores, and so aren't relevant to you when building and running the wallet yourself.
|
||||
|
||||
On **all** operating systems:
|
||||
On **all** operating systems:
|
||||
* set the value of line 49 to `false`
|
||||
* remove lines 50 to 54
|
||||
* remove lines 50 to 54
|
||||
|
||||
As well as these modifications for MacOS and Windows users:
|
||||
* MacOS users must also remove line 39
|
||||
* Windows users must remove lines 42 to 46
|
||||
As well as these modifications for MacOS and Windows users:
|
||||
* MacOS users must also remove line 39
|
||||
* Windows users must remove lines 42 to 46
|
||||
|
||||
### Installation
|
||||
Once you have made these modifications to `tauri.conf.json`, inside of the `nym-wallet` folder, run:
|
||||
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
```
|
||||
|
||||
### Running in Development Mode
|
||||
|
||||
@@ -112,7 +112,7 @@ You can run the wallet without having to install it in development mode by runni
|
||||
yarn dev
|
||||
```
|
||||
|
||||
This will then start the Wallet GUI and produce a binary in `nym-wallet/target/debug/` named `nym-wallet`.
|
||||
This will then start the Wallet GUI and produce a binary in `nym-wallet/target/debug/` named `nym-wallet`.
|
||||
|
||||
### Running in Production Mode
|
||||
|
||||
@@ -165,21 +165,25 @@ To import or create a new account, first you need to create a password for your
|
||||
6. Come back to this page to import or create new accounts
|
||||
|
||||
### Importing or creating account(s) when you have signed in with mnemonic but a password already exists on your machine
|
||||
To import or create a new account, you need to log in with your existing password or create a new password.
|
||||
To import or create a new account, you need to log in with your existing password or create a new password.
|
||||
|
||||
> Creating a new password will overwrite any old one stored on your machine. Make sure you have saved any mnemonics associated with the password before creating a new one.
|
||||
|
||||
1. Log out
|
||||
2. Click on “Forgot password”
|
||||
2. Click on “Forgot password”
|
||||
3. On the next screen select “Create new password”
|
||||
4. Follow the instructions and create a new password
|
||||
5. Sign in using your new password
|
||||
|
||||
### CLI tool for wallet encrypted file (password) recovery:
|
||||
The mnemonics that are stored in the local password protected file can also be decrypted and recovered through a simple CLI tool, `nym-wallet-recovery-cli`.
|
||||
The mnemonics that are stored in the local password protected file can also be decrypted and recovered through a simple CLI tool, `nym-wallet-recovery-cli`.
|
||||
|
||||
```
|
||||
nym-wallet-recovery –file saved-wallet.json –password foo
|
||||
```
|
||||
|
||||
The saved wallet file can be found in `$XDG_DATA_HOME` or `$HOME/.local/share` on Linux, `$HOME/Library/Application Support` on Mac, and `C:\Users\username\AppData\Local` on Windows.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.23"
|
||||
version = "1.1.22"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_mixnet_contract_common::{MixId, MixNode};
|
||||
|
||||
+31
-4
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.23"
|
||||
version = "1.1.22"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
@@ -34,16 +34,41 @@ pretty_env_logger = "0.4"
|
||||
rand = "0.7"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "sqlite", "macros", "migrate", ] }
|
||||
sqlx = { version = "0.5", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"] }
|
||||
thiserror = "1"
|
||||
tokio = { version = "1.24.1", features = [ "rt-multi-thread", "net", "signal", "fs", ] }
|
||||
tokio = { version = "1.24.1", features = [
|
||||
"rt-multi-thread",
|
||||
"net",
|
||||
"signal",
|
||||
"fs",
|
||||
] }
|
||||
tokio-stream = { version = "0.1.11", features = ["fs"] }
|
||||
tokio-tungstenite = "0.14"
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
url = { version = "2.2", features = ["serde"] }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# wireguard
|
||||
# Forked it to be able to bump x25519-dalek to rc.3
|
||||
boringtun = { git = "https://github.com/durch/boringtun.git" }
|
||||
base64 = "0.21"
|
||||
x25519-dalek = { version = "=2.0.0-rc.3", features = [
|
||||
"reusable_secrets",
|
||||
"static_secrets",
|
||||
] }
|
||||
etherparse = "0.13.0"
|
||||
pnet = "0.34.0"
|
||||
bytes = "1.4.0"
|
||||
async-recursion = "1.0.4"
|
||||
smoltcp = "0.10.0"
|
||||
tun-tap = "0.1.3"
|
||||
|
||||
# internal
|
||||
nym-api-requests = { path = "../nym-api/nym-api-requests" }
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["output_format"] }
|
||||
@@ -60,7 +85,9 @@ nym-sphinx = { path = "../common/nymsphinx" }
|
||||
nym-statistics-common = { path = "../common/statistics" }
|
||||
nym-task = { path = "../common/task" }
|
||||
nym-types = { path = "../common/types" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client", features = [ "nyxd-client" ] }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client", features = [
|
||||
"nyxd-client",
|
||||
] }
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
gA3NCDl+xOorR3heFVB47FlGunsZgS4RDX2M0IY73lc=
|
||||
@@ -0,0 +1 @@
|
||||
mxV/mw7WZTe+0Msa0kvJHMHERDA/cSskiZWQce+TdEs=
|
||||
@@ -0,0 +1 @@
|
||||
AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=
|
||||
@@ -0,0 +1 @@
|
||||
WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE=
|
||||
@@ -10,6 +10,7 @@ use crate::node::client_handling::websocket::connection_handler::coconut::Coconu
|
||||
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
|
||||
use crate::node::statistics::collector::GatewayStatisticsCollector;
|
||||
use crate::node::storage::Storage;
|
||||
use crate::node::wireguard::wireguard;
|
||||
use log::*;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
@@ -28,6 +29,8 @@ pub(crate) mod client_handling;
|
||||
pub(crate) mod mixnet_handling;
|
||||
pub(crate) mod statistics;
|
||||
pub(crate) mod storage;
|
||||
mod wg;
|
||||
pub(crate) mod wireguard;
|
||||
|
||||
/// Wire up and create Gateway instance
|
||||
pub(crate) async fn create_gateway(config: Config) -> Gateway<PersistentStorage> {
|
||||
@@ -297,6 +300,8 @@ impl<St> Gateway<St> {
|
||||
Arc::new(coconut_verifier),
|
||||
);
|
||||
|
||||
tokio::spawn(wireguard());
|
||||
|
||||
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
|
||||
|
||||
self.wait_for_interrupt(shutdown).await
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
use bytes::Bytes;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
/// Dumb event with no data.
|
||||
Dumb,
|
||||
/// IP packet received from the WireGuard tunnel that should be passed through to the corresponding virtual device/internet.
|
||||
/// Original implementation also has protocol here since it understands it, but we'll have to infer it downstream
|
||||
WgPacket(Bytes),
|
||||
/// IP packet to be sent through the WireGuard tunnel as crafted by the virtual device.
|
||||
IpPacket(Bytes),
|
||||
}
|
||||
|
||||
impl Display for Event {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Event::Dumb => {
|
||||
write!(f, "Dumb{{}}")
|
||||
}
|
||||
Event::WgPacket(data) => {
|
||||
let size = data.len();
|
||||
write!(f, "WgPacket{{ size={} }}", size)
|
||||
}
|
||||
Event::IpPacket(data) => {
|
||||
let size = data.len();
|
||||
write!(f, "IpPacket{{ size={} }}", size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_recursion::async_recursion;
|
||||
use base64::engine::general_purpose;
|
||||
use base64::Engine as _;
|
||||
use boringtun::noise::errors::WireGuardError;
|
||||
use boringtun::noise::{Tunn, TunnResult};
|
||||
use etherparse::{InternetSlice, PacketBuilder, SlicedPacket, TransportSlice};
|
||||
use log::{debug, info, warn};
|
||||
use pnet::packet::ip::IpNextHeaderProtocols;
|
||||
use pnet::packet::ipv4::{Ipv4Packet, MutableIpv4Packet};
|
||||
use pnet::packet::{MutablePacket, Packet, PacketSize};
|
||||
use pnet::transport::{ipv4_packet_iter, transport_channel};
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio::time::{sleep, timeout};
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use crate::error;
|
||||
|
||||
use self::events::Event;
|
||||
|
||||
pub mod events;
|
||||
|
||||
const MAX_PACKET: usize = 65536;
|
||||
|
||||
/// A WireGuard tunnel. Encapsulates and decapsulates IP packets,
|
||||
/// recieves packets from the client on the udp_rx channel,
|
||||
/// and events from the internet on the eth_rx channel,
|
||||
/// sends data through udp socket or datalink sender directly.
|
||||
/// For now all tunnels recieve all events and filter on the source_peer_addr
|
||||
pub struct WireGuardTunnel {
|
||||
source_peer_addr: Arc<RwLock<Option<(Ipv4Addr, u16)>>>,
|
||||
/// `boringtun` peer/tunnel implementation, used for crypto & WG protocol.
|
||||
peer: Arc<Mutex<Tunn>>,
|
||||
udp: Arc<UdpSocket>,
|
||||
peer_endpoint: SocketAddr,
|
||||
bus_rx: tokio::sync::broadcast::Receiver<Event>,
|
||||
bus_tx: tokio::sync::broadcast::Sender<Event>,
|
||||
}
|
||||
|
||||
pub fn handle_l3_packet(data: &[u8], destination_addr: Ipv4Addr) -> Vec<u8> {
|
||||
let (mut tx, mut rx) = transport_channel(
|
||||
65535,
|
||||
pnet::transport::TransportChannelType::Layer3(IpNextHeaderProtocols::Tcp),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut rx_iterator = ipv4_packet_iter(&mut rx);
|
||||
|
||||
let mut must_send = true;
|
||||
let mut cnt = 0;
|
||||
while let Ok((packet, addr)) = rx_iterator.next() {
|
||||
if must_send {
|
||||
let data = data.to_vec();
|
||||
let incoming_packet = Ipv4Packet::new(&data).unwrap();
|
||||
let mut new_packet = vec![0; incoming_packet.packet_size()];
|
||||
let mut outgoing_packet = MutableIpv4Packet::new(&mut new_packet).unwrap();
|
||||
outgoing_packet.clone_from(&incoming_packet);
|
||||
info!(
|
||||
"Sending (ttl={}, proto={} from {} to {}({})",
|
||||
outgoing_packet.get_ttl(),
|
||||
outgoing_packet.get_next_level_protocol(),
|
||||
outgoing_packet.get_source(),
|
||||
outgoing_packet.get_destination(),
|
||||
destination_addr
|
||||
);
|
||||
outgoing_packet.set_source("95.217.227.118".parse().unwrap());
|
||||
let sent = tx
|
||||
.send_to(outgoing_packet, IpAddr::V4(destination_addr))
|
||||
.unwrap();
|
||||
info!("Sent L3 packet ({sent})");
|
||||
must_send = false;
|
||||
continue;
|
||||
}
|
||||
cnt += 1;
|
||||
let source = packet.get_source();
|
||||
let destination = packet.get_destination();
|
||||
info!("Ignoring packet from {source}");
|
||||
|
||||
if source == destination_addr {
|
||||
info!("({addr}){source} -> {destination}");
|
||||
return packet.payload().to_vec();
|
||||
}
|
||||
if cnt >= 10 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
||||
impl WireGuardTunnel {
|
||||
async fn set_source_peer_addr(&self, source_addr: Ipv4Addr, source_port: Option<u16>) {
|
||||
{
|
||||
if self.source_peer_addr.read().await.is_some() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
let mut source_peer_addr = self.source_peer_addr.write().await;
|
||||
*source_peer_addr = Some((source_addr, source_port.unwrap_or(0)))
|
||||
}
|
||||
|
||||
pub async fn spin_off(mut self) {
|
||||
info!("Spun off WG tunnel");
|
||||
// We'll receive both inbound and outbound packages on the same channel, and filter on packet type
|
||||
loop {
|
||||
tokio::select! {
|
||||
packet = self.bus_rx.recv() => {
|
||||
match packet {
|
||||
Ok(p) => {
|
||||
info!("{p}");
|
||||
match p {
|
||||
Event::IpPacket(data) => self.consume_eth(&data).await,
|
||||
Event::WgPacket(data) => self.consume_wg(&data).await,
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
Err(e) => error!("{e}")
|
||||
}
|
||||
},
|
||||
_ = sleep(Duration::from_millis(5))=> {
|
||||
let mut send_buf = [0u8; MAX_PACKET];
|
||||
let tun_result = {
|
||||
let mut tun = timeout(Duration::from_millis(100), self.peer()).await.unwrap();
|
||||
tun.update_timers(&mut send_buf)
|
||||
};
|
||||
self.handle_routine_tun_result(tun_result).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn consume_eth(&self, data: &[u8]) {
|
||||
let parsed_packet = SlicedPacket::from_ethernet(data).unwrap();
|
||||
debug!("{parsed_packet:?}");
|
||||
let (source_addr, destination_addr) = match parsed_packet.ip.unwrap() {
|
||||
InternetSlice::Ipv4(ip, _) => (ip.source_addr(), ip.destination_addr()),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let (source_port, destination_port, icmp_type) = match parsed_packet.transport.as_ref() {
|
||||
Some(TransportSlice::Tcp(tcp)) => {
|
||||
(Some(tcp.source_port()), Some(tcp.destination_port()), None)
|
||||
}
|
||||
Some(TransportSlice::Udp(udp)) => {
|
||||
(Some(udp.source_port()), Some(udp.destination_port()), None)
|
||||
}
|
||||
Some(TransportSlice::Icmpv4(icmp)) => (None, None, Some(icmp.icmp_type())),
|
||||
Some(TransportSlice::Icmpv6(_)) => panic!("ICMPv6"),
|
||||
Some(TransportSlice::Unknown(_)) => panic!("Unknown"),
|
||||
None => panic!("No transport layer"),
|
||||
};
|
||||
debug!(
|
||||
"{:?}:{:?} -> {:?}:{:?} - ({:?})",
|
||||
source_addr, source_port, destination_addr, destination_port, icmp_type
|
||||
);
|
||||
|
||||
if destination_addr == self.source_peer_addr.read().await.unwrap().0 {
|
||||
info!("Sending {} to {}", data.len(), self.peer_endpoint);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
let response_packet_builder =
|
||||
PacketBuilder::ipv4(source_addr.octets(), destination_addr.octets(), 64);
|
||||
|
||||
let mut response_packet =
|
||||
Vec::<u8>::with_capacity(response_packet_builder.size(parsed_packet.payload.len()));
|
||||
|
||||
match parsed_packet.transport.as_ref() {
|
||||
Some(TransportSlice::Udp(udp)) => {
|
||||
debug!("UDP: {}, {}", udp.length(), udp.destination_port());
|
||||
let response_packet_builder =
|
||||
response_packet_builder.udp(source_port.unwrap(), destination_port.unwrap());
|
||||
response_packet_builder
|
||||
.write(&mut response_packet, parsed_packet.payload)
|
||||
.unwrap();
|
||||
}
|
||||
Some(TransportSlice::Tcp(tcp)) => {
|
||||
let response_packet_builder = response_packet_builder.tcp(
|
||||
destination_port.unwrap(),
|
||||
source_port.unwrap(),
|
||||
tcp.sequence_number(),
|
||||
tcp.window_size(),
|
||||
);
|
||||
response_packet_builder
|
||||
.write(&mut response_packet, parsed_packet.payload)
|
||||
.unwrap();
|
||||
}
|
||||
Some(TransportSlice::Icmpv4(icmp)) => {
|
||||
info!("{:?}", icmp.icmp_type());
|
||||
let response_packet_builder = response_packet_builder.icmpv4(icmp.icmp_type());
|
||||
response_packet_builder
|
||||
.write(&mut response_packet, parsed_packet.payload)
|
||||
.unwrap();
|
||||
}
|
||||
None => {}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let encapsulated_response_packet = self.encapsulate_packet(&response_packet).await;
|
||||
// let packet = Tunn::parse_incoming_packet(&response_packet).unwrap();
|
||||
// info!("Sending {packet:?} to {addr}");
|
||||
let sent = self
|
||||
.udp
|
||||
.send_to(&encapsulated_response_packet, self.peer_endpoint)
|
||||
.await
|
||||
.unwrap();
|
||||
info!(
|
||||
"[{}:{} ({sent})-> {}:{}] -> {}",
|
||||
destination_addr,
|
||||
destination_port.unwrap_or(0),
|
||||
source_addr,
|
||||
source_port.unwrap_or(0),
|
||||
self.peer_endpoint
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: extend to work with IPv6
|
||||
pub async fn produce_eth(&self, packet_bytes: &[u8]) -> Vec<u8> {
|
||||
let outgoing_packet = SlicedPacket::from_ip(packet_bytes).unwrap();
|
||||
let (source_addr, destination_addr) = match outgoing_packet.ip.unwrap() {
|
||||
InternetSlice::Ipv4(ip, _) => (ip.source_addr(), ip.destination_addr()),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let (source_port, destination_port, icmp_type) = match outgoing_packet.transport.as_ref() {
|
||||
Some(TransportSlice::Tcp(tcp)) => {
|
||||
(Some(tcp.source_port()), Some(tcp.destination_port()), None)
|
||||
}
|
||||
Some(TransportSlice::Udp(udp)) => {
|
||||
(Some(udp.source_port()), Some(udp.destination_port()), None)
|
||||
}
|
||||
Some(TransportSlice::Icmpv4(icmp)) => (None, None, Some(icmp.icmp_type())),
|
||||
Some(TransportSlice::Icmpv6(_)) => panic!("ICMPv6"),
|
||||
Some(TransportSlice::Unknown(_)) => panic!("Unknown"),
|
||||
None => panic!("No transport layer"),
|
||||
};
|
||||
info!(
|
||||
"{:?}:{:?} -> {:?}:{:?} - ({:?})",
|
||||
source_addr, source_port, destination_addr, destination_port, icmp_type
|
||||
);
|
||||
self.set_source_peer_addr(source_addr, source_port).await;
|
||||
handle_l3_packet(packet_bytes, destination_addr)
|
||||
}
|
||||
|
||||
/// WireGuard consumption task. Receives encrypted packets from the WireGuard peer,
|
||||
/// decapsulates them, and dispatches newly received IP packets.
|
||||
async fn consume_wg(&self, data: &[u8]) {
|
||||
let mut send_buf = [0u8; MAX_PACKET];
|
||||
let mut peer = self.peer().await;
|
||||
match peer.decapsulate(None, data, &mut send_buf) {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
match self.udp.send_to(packet, self.peer_endpoint).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {:?}", e);
|
||||
}
|
||||
};
|
||||
loop {
|
||||
let mut send_buf = [0u8; MAX_PACKET];
|
||||
match peer.decapsulate(None, &[], &mut send_buf) {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
match self.udp.send_to(packet, self.peer_endpoint).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {:?}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TunnResult::WriteToTunnelV4(packet, _) | TunnResult::WriteToTunnelV6(packet, _) => {
|
||||
info!(
|
||||
"WireGuard endpoint sent IP packet of {} bytes",
|
||||
packet.len()
|
||||
);
|
||||
let response = self.produce_eth(packet).await;
|
||||
if !response.is_empty() {
|
||||
self.bus_tx.send(Event::IpPacket(response.into())).unwrap();
|
||||
}
|
||||
}
|
||||
x => warn!("{x:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
async fn encapsulate_packet(&self, payload: &[u8]) -> Vec<u8> {
|
||||
let len = 148.max(payload.len() + 32);
|
||||
let mut dst = vec![0; len];
|
||||
let mut t = self.peer().await;
|
||||
let packet = t.encapsulate(payload, &mut dst);
|
||||
match packet {
|
||||
TunnResult::WriteToNetwork(p) => p.to_vec(),
|
||||
unexpected => {
|
||||
error!("{:?}", unexpected);
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn peer(&self) -> tokio::sync::MutexGuard<'_, Tunn> {
|
||||
self.peer.lock().await
|
||||
}
|
||||
|
||||
pub async fn new(
|
||||
peer_static_public: x25519_dalek::PublicKey,
|
||||
udp: Arc<UdpSocket>,
|
||||
peer_endpoint: SocketAddr,
|
||||
bus_tx: tokio::sync::broadcast::Sender<Event>,
|
||||
) -> Self {
|
||||
let peer = Arc::new(Mutex::new(Self::create_tunnel(peer_static_public)));
|
||||
|
||||
Self {
|
||||
source_peer_addr: Arc::new(RwLock::new(None)),
|
||||
peer,
|
||||
udp,
|
||||
peer_endpoint,
|
||||
bus_rx: bus_tx.subscribe(),
|
||||
bus_tx,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tunnel(peer_static_public: x25519_dalek::PublicKey) -> Tunn {
|
||||
let secret_bytes: [u8; 32] = general_purpose::STANDARD
|
||||
.decode("AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let private_key = StaticSecret::try_from(secret_bytes).unwrap();
|
||||
|
||||
Tunn::new(private_key, peer_static_public, None, None, 0, None).unwrap()
|
||||
}
|
||||
|
||||
/// Encapsulates and sends an IP packet back to the WireGuard client.
|
||||
pub async fn send_ip_packet(&self, packet: &[u8]) -> anyhow::Result<()> {
|
||||
let mut send_buf = [0u8; MAX_PACKET];
|
||||
match self.peer().await.encapsulate(packet, &mut send_buf) {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
self.udp.send_to(packet, self.peer_endpoint).await.unwrap();
|
||||
debug!(
|
||||
"Sent {} bytes to WireGuard endpoint (encrypted IP packet)",
|
||||
packet.len()
|
||||
);
|
||||
}
|
||||
TunnResult::Err(e) => {
|
||||
error!("Failed to encapsulate IP packet: {:?}", e);
|
||||
}
|
||||
TunnResult::Done => {
|
||||
// Ignored
|
||||
}
|
||||
other => {
|
||||
error!(
|
||||
"Unexpected WireGuard state during encapsulation: {:?}",
|
||||
other
|
||||
);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn handle_routine_tun_result<'a: 'async_recursion>(&self, result: TunnResult<'a>) -> () {
|
||||
match result {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
info!(
|
||||
"Sending routine packet of {} bytes to WireGuard endpoint",
|
||||
packet.len()
|
||||
);
|
||||
match self.udp.send_to(packet, self.peer_endpoint).await {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Failed to send routine packet to WireGuard endpoint: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
TunnResult::Err(WireGuardError::ConnectionExpired) => {
|
||||
warn!("Wireguard handshake has expired!");
|
||||
|
||||
let mut buf = vec![0u8; MAX_PACKET];
|
||||
let result = self
|
||||
.peer()
|
||||
.await
|
||||
.format_handshake_initiation(&mut buf[..], false);
|
||||
|
||||
self.handle_routine_tun_result(result).await
|
||||
}
|
||||
TunnResult::Err(e) => {
|
||||
error!(
|
||||
"Failed to prepare routine packet for WireGuard endpoint: {:?}",
|
||||
e
|
||||
);
|
||||
}
|
||||
TunnResult::Done => {
|
||||
// Sleep for a bit
|
||||
// tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
}
|
||||
other => {
|
||||
warn!("Unexpected WireGuard routine task state: {:?}", other);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// fn route_protocol(&self, packet: &[u8]) -> Option<Protocol> {
|
||||
// match IpVersion::of_packet(packet) {
|
||||
// Ok(IpVersion::Ipv4) => Ipv4Packet::new_checked(&packet)
|
||||
// .ok()
|
||||
// // Only care if the packet is destined for this tunnel
|
||||
// .filter(|packet| Ipv4Addr::from(packet.dst_addr()) == self.source_peer_ip)
|
||||
// .and_then(|packet| match packet.next_header() {
|
||||
// IpProtocol::Tcp => Some(Protocol::Tcp),
|
||||
// IpProtocol::Udp => Some(Protocol::Udp),
|
||||
// // Unrecognized protocol, so we cannot determine where to route
|
||||
// _ => None,
|
||||
// }),
|
||||
// Ok(IpVersion::Ipv6) => Ipv6Packet::new_checked(&packet)
|
||||
// .ok()
|
||||
// // Only care if the packet is destined for this tunnel
|
||||
// .filter(|packet| Ipv6Addr::from(packet.dst_addr()) == self.source_peer_ip)
|
||||
// .and_then(|packet| match packet.next_header() {
|
||||
// IpProtocol::Tcp => Some(Protocol::Tcp),
|
||||
// IpProtocol::Udp => Some(Protocol::Udp),
|
||||
// // Unrecognized protocol, so we cannot determine where to route
|
||||
// _ => None,
|
||||
// }),
|
||||
// _ => None,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
use base64::engine::general_purpose;
|
||||
use base64::Engine as _;
|
||||
use log::{error, info};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::broadcast;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use crate::node::wg::events::Event;
|
||||
use crate::node::wg::WireGuardTunnel;
|
||||
|
||||
pub async fn wireguard() {
|
||||
let wg_address = "0.0.0.0:51820";
|
||||
let sock = Arc::new(UdpSocket::bind(wg_address).await.unwrap());
|
||||
info!("wg listening on {wg_address}");
|
||||
|
||||
// Secret key ofthe gateway, we'll need a way to generate this from the IdentityKey, might be enough to do some base58 -> base64 conversion
|
||||
let secret_bytes: [u8; 32] = general_purpose::STANDARD
|
||||
.decode("AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
// Hardcoded peer public key, we'll need a way to register those, private key for that one is `aMUcuAgTiFCHQ/fHqEQRvpLWBxh8sKA7f7lSyWymrGE=`
|
||||
// Wireguard configuration that works with this setup is below, this needs to be put into the wireguard client of choice.
|
||||
// Working in this case means that they go through the handshake, and client
|
||||
// starts sending data packets to the gateway.
|
||||
//
|
||||
// [Interface]
|
||||
// PrivateKey = aMUcuAgTiFCHQ/fHqEQRvpLWBxh8sKA7f7lSyWymrGE=
|
||||
// Address = 10.8.0.0/24
|
||||
// DNS = 1.1.1.1
|
||||
//
|
||||
// [Peer]
|
||||
// PublicKey = y6/iGYraJjON6pw9fcBa5vLRbGsQqprFLfWKyJQnlWs=
|
||||
// AllowedIPs = 0.0.0.0/0
|
||||
// Endpoint = 127.0.0.1:51820
|
||||
let peer_public_bytes: [u8; 32] = general_purpose::STANDARD
|
||||
.decode("mxV/mw7WZTe+0Msa0kvJHMHERDA/cSskiZWQce+TdEs=")
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let peer_public = PublicKey::from(peer_public_bytes);
|
||||
let secret = StaticSecret::try_from(secret_bytes).unwrap();
|
||||
let public = PublicKey::from(&secret);
|
||||
info!(
|
||||
"wg public key: {}",
|
||||
general_purpose::STANDARD.encode(public)
|
||||
);
|
||||
|
||||
let mut buf = [0; 1024];
|
||||
let mut peers = HashSet::new();
|
||||
|
||||
let (bus_tx, _) = broadcast::channel(128);
|
||||
|
||||
while let Ok((len, addr)) = sock.recv_from(&mut buf).await {
|
||||
info!("Received {} bytes from {}", len, addr);
|
||||
if peers.contains(&addr) {
|
||||
bus_tx
|
||||
.send(Event::WgPacket(buf[..len].to_vec().into()))
|
||||
.map_err(|e| error!("{e}"))
|
||||
.unwrap();
|
||||
} else {
|
||||
info!("New peer with endpoint {addr}");
|
||||
let tun =
|
||||
WireGuardTunnel::new(peer_public, Arc::clone(&sock), addr, bus_tx.clone()).await;
|
||||
peers.insert(addr);
|
||||
tokio::spawn(tun.spin_off());
|
||||
bus_tx
|
||||
.send(Event::WgPacket(buf[..len].to_vec().into()))
|
||||
.map_err(|e| error!("{e}"))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
panic!("Not OK");
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.24"
|
||||
version = "1.1.23"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-api"
|
||||
version = "1.1.24"
|
||||
version = "1.1.23"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::node_status_api::models::ErrorResponse;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::Decimal;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::helpers::_get_gateways_detailed;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nym_contract_cache::cache::NymContractCache;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
|
||||
@@ -2,20 +2,6 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.14] (2023-06-27)
|
||||
|
||||
- Nym connect fails to start when encountering an old config version ([#3588])
|
||||
- NC desktop - apps section adjustments + add monero integration ([#2977])
|
||||
- Fix medium toggle in nym-connect ([#3590])
|
||||
- [bugfix] NC: load old gateway configuration if we're not registering ([#3586])
|
||||
- nym-connect: medium speed setting ([#3585])
|
||||
|
||||
[#3588]: https://github.com/nymtech/nym/issues/3588
|
||||
[#2977]: https://github.com/nymtech/nym/issues/2977
|
||||
[#3590]: https://github.com/nymtech/nym/pull/3590
|
||||
[#3586]: https://github.com/nymtech/nym/pull/3586
|
||||
[#3585]: https://github.com/nymtech/nym/pull/3585
|
||||
|
||||
## [v1.1.13] (2023-06-20)
|
||||
|
||||
- NymConnect - add sentry.io reporting ([#3421])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nym/nym-connect",
|
||||
"version": "1.1.14",
|
||||
"version": "1.1.13",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -48,7 +48,7 @@ yaml-rust = "0.4"
|
||||
nym-client-core = { path = "../../../common/client-core" }
|
||||
nym-api-requests = { path = "../../../nym-api/nym-api-requests" }
|
||||
nym-contracts-common = { path = "../../../common/cosmwasm-smart-contracts/contracts-common"}
|
||||
nym-config = { path = "../../../common/config" }
|
||||
nym-config-common = { path = "../../../common/config", package = "nym-config" }
|
||||
nym-crypto = { path = "../../../common/crypto" }
|
||||
nym-credential-storage = { path = "../../../common/credential-storage" }
|
||||
nym-bin-common = { path = "../../../common/bin-common"}
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
|
||||
use crate::config::persistence::NymConnectPaths;
|
||||
use crate::config::template::CONFIG_TEMPLATE;
|
||||
use crate::config::upgrade::try_upgrade_config;
|
||||
use crate::error::{BackendError, Result};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_config::{
|
||||
use nym_config_common::{
|
||||
must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate,
|
||||
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
|
||||
};
|
||||
@@ -20,12 +19,8 @@ use std::path::{Path, PathBuf};
|
||||
use std::{fs, io};
|
||||
use tap::TapFallible;
|
||||
|
||||
mod old_config_v1_1_13;
|
||||
mod old_config_v1_1_20;
|
||||
mod old_config_v1_1_20_2;
|
||||
mod persistence;
|
||||
mod template;
|
||||
mod upgrade;
|
||||
|
||||
static SOCKS5_CONFIG_ID: &str = "nym-connect";
|
||||
|
||||
@@ -143,9 +138,6 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str
|
||||
.map_err(|_| BackendError::UnableToParseGateway)?;
|
||||
|
||||
let already_init = if default_config_filepath(&id).exists() {
|
||||
// in case we're using old config, try to upgrade it
|
||||
// (if we're using the current version, it's a no-op)
|
||||
try_upgrade_config(&id)?;
|
||||
eprintln!("SOCKS5 client \"{id}\" was already initialised before");
|
||||
true
|
||||
} else {
|
||||
@@ -164,8 +156,8 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str
|
||||
log::trace!("Creating config for id: {id}");
|
||||
let mut config = Config::new(&id, &provider_address);
|
||||
|
||||
if let Ok(raw_validators) = std::env::var(nym_config::defaults::var_names::NYM_API) {
|
||||
config.core.base.client.nym_api_urls = nym_config::parse_urls(&raw_validators);
|
||||
if let Ok(raw_validators) = std::env::var(nym_config_common::defaults::var_names::NYM_API) {
|
||||
config.core.base.client.nym_api_urls = nym_config_common::parse_urls(&raw_validators);
|
||||
}
|
||||
|
||||
let gateway_setup = if register_gateway {
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20::{ConfigV1_1_20, Socks5V1_1_20};
|
||||
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use nym_config::must_get_home;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct OldConfigV1_1_13 {
|
||||
#[serde(flatten)]
|
||||
pub base: OldBaseConfigV1_1_13<OldConfigV1_1_13>,
|
||||
|
||||
pub socks5: Socks5V1_1_20,
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for OldConfigV1_1_13 {
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = must_get_home();
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OldConfigV1_1_13> for ConfigV1_1_20 {
|
||||
fn from(value: OldConfigV1_1_13) -> Self {
|
||||
ConfigV1_1_20 {
|
||||
base: value.base.into(),
|
||||
socks5: value.socks5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::old_config_v1_1_20_2::{
|
||||
ConfigV1_1_20_2, CoreConfigV1_1_20_2, SocksClientPathsV1_1_20_2,
|
||||
};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20;
|
||||
use nym_client_core::config::old_config_v1_1_20_2::ClientV1_1_20_2;
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
use nym_config::must_get_home;
|
||||
use nym_socks5_client_core::config::old_config_v1_1_20_2::{
|
||||
BaseClientConfigV1_1_20_2, Socks5DebugV1_1_20_2, Socks5V1_1_20_2,
|
||||
};
|
||||
use nym_socks5_client_core::config::{ProviderInterfaceVersion, Socks5ProtocolVersion};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const DEFAULT_CONNECTION_START_SURBS: u32 = 20;
|
||||
const DEFAULT_PER_REQUEST_SURBS: u32 = 3;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20 {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseConfigV1_1_20<ConfigV1_1_20>,
|
||||
|
||||
pub socks5: Socks5V1_1_20,
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_20> for ConfigV1_1_20_2 {
|
||||
fn from(value: ConfigV1_1_20) -> Self {
|
||||
ConfigV1_1_20_2 {
|
||||
core: CoreConfigV1_1_20_2 {
|
||||
base: BaseClientConfigV1_1_20_2 {
|
||||
client: ClientV1_1_20_2 {
|
||||
version: value.base.client.version,
|
||||
id: value.base.client.id,
|
||||
disabled_credentials_mode: value.base.client.disabled_credentials_mode,
|
||||
nyxd_urls: value.base.client.nyxd_urls,
|
||||
nym_api_urls: value.base.client.nym_api_urls,
|
||||
gateway_endpoint: value.base.client.gateway_endpoint.into(),
|
||||
},
|
||||
debug: value.base.debug.into(),
|
||||
},
|
||||
socks5: value.socks5.into(),
|
||||
},
|
||||
storage_paths: SocksClientPathsV1_1_20_2 {
|
||||
common_paths: CommonClientPathsV1_1_20_2 {
|
||||
keys: ClientKeysPaths {
|
||||
private_identity_key_file: value.base.client.private_identity_key_file,
|
||||
public_identity_key_file: value.base.client.public_identity_key_file,
|
||||
private_encryption_key_file: value.base.client.private_encryption_key_file,
|
||||
public_encryption_key_file: value.base.client.public_encryption_key_file,
|
||||
gateway_shared_key_file: value.base.client.gateway_shared_key_file,
|
||||
ack_key_file: value.base.client.ack_key_file,
|
||||
},
|
||||
credentials_database: value.base.client.database_path,
|
||||
reply_surb_database: value.base.client.reply_surb_database_path,
|
||||
},
|
||||
},
|
||||
logging: LoggingSettings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MigrationNymConfig for ConfigV1_1_20 {
|
||||
fn default_root_directory() -> PathBuf {
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
let base_dir = must_get_home();
|
||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||
let base_dir = PathBuf::from("/tmp");
|
||||
|
||||
base_dir.join(".nym").join("socks5-clients")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5V1_1_20 {
|
||||
pub listening_port: u16,
|
||||
|
||||
pub provider_mix_address: String,
|
||||
|
||||
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
|
||||
pub provider_interface_version: ProviderInterfaceVersion,
|
||||
|
||||
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
|
||||
pub socks5_protocol_version: Socks5ProtocolVersion,
|
||||
|
||||
#[serde(default)]
|
||||
pub send_anonymously: bool,
|
||||
|
||||
#[serde(default)]
|
||||
pub socks5_debug: Socks5DebugV1_1_20,
|
||||
}
|
||||
|
||||
impl From<Socks5V1_1_20> for Socks5V1_1_20_2 {
|
||||
fn from(value: Socks5V1_1_20) -> Self {
|
||||
Socks5V1_1_20_2 {
|
||||
listening_port: value.listening_port,
|
||||
provider_mix_address: value.provider_mix_address,
|
||||
provider_interface_version: value.provider_interface_version,
|
||||
socks5_protocol_version: value.socks5_protocol_version,
|
||||
send_anonymously: value.send_anonymously,
|
||||
socks5_debug: value.socks5_debug.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Socks5DebugV1_1_20 {
|
||||
connection_start_surbs: u32,
|
||||
per_request_surbs: u32,
|
||||
}
|
||||
|
||||
impl From<Socks5DebugV1_1_20> for Socks5DebugV1_1_20_2 {
|
||||
fn from(value: Socks5DebugV1_1_20) -> Self {
|
||||
Socks5DebugV1_1_20_2 {
|
||||
connection_start_surbs: value.connection_start_surbs,
|
||||
per_request_surbs: value.per_request_surbs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Socks5DebugV1_1_20 {
|
||||
fn default() -> Self {
|
||||
Socks5DebugV1_1_20 {
|
||||
connection_start_surbs: DEFAULT_CONNECTION_START_SURBS,
|
||||
per_request_surbs: DEFAULT_PER_REQUEST_SURBS,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::NymConnectPaths;
|
||||
use crate::config::{default_config_filepath, Config};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_config::read_config_from_toml_file;
|
||||
pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct SocksClientPathsV1_1_20_2 {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPathsV1_1_20_2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ConfigV1_1_20_2 {
|
||||
pub core: CoreConfigV1_1_20_2,
|
||||
|
||||
pub storage_paths: SocksClientPathsV1_1_20_2,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
}
|
||||
|
||||
impl ConfigV1_1_20_2 {
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
// in this upgrade, gateway endpoint configuration was moved out of the config file,
|
||||
// so its returned to be stored elsewhere.
|
||||
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
|
||||
let gateway_details = self.core.base.client.gateway_endpoint.clone().into();
|
||||
let config = Config {
|
||||
core: self.core.into(),
|
||||
storage_paths: NymConnectPaths {
|
||||
common_paths: self.storage_paths.common_paths.upgrade_default(),
|
||||
},
|
||||
// logging: self.logging,
|
||||
};
|
||||
|
||||
(config, gateway_details)
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
config::{
|
||||
old_config_v1_1_13::OldConfigV1_1_13, old_config_v1_1_20::ConfigV1_1_20,
|
||||
old_config_v1_1_20_2::ConfigV1_1_20_2, Config,
|
||||
},
|
||||
error::{BackendError, Result},
|
||||
};
|
||||
use log::info;
|
||||
use nym_client_core::{
|
||||
client::{
|
||||
base_client::storage::gateway_details::{OnDiskGatewayDetails, PersistedGatewayDetails},
|
||||
key_manager::persistence::OnDiskKeys,
|
||||
},
|
||||
config::GatewayEndpointConfig,
|
||||
error::ClientCoreError,
|
||||
};
|
||||
|
||||
fn persist_gateway_details(config: &Config, details: GatewayEndpointConfig) -> Result<()> {
|
||||
let details_store =
|
||||
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
|
||||
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
|
||||
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
|
||||
BackendError::ClientCoreError {
|
||||
source: ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
},
|
||||
}
|
||||
})?;
|
||||
let persisted_details = PersistedGatewayDetails::new(details, &shared_keys);
|
||||
details_store
|
||||
.store_to_disk(&persisted_details)
|
||||
.map_err(|source| BackendError::ClientCoreError {
|
||||
source: ClientCoreError::GatewayDetailsStoreError {
|
||||
source: Box::new(source),
|
||||
},
|
||||
})
|
||||
}
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
|
||||
let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.13 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20 = old_config.into();
|
||||
let updated_step2: ConfigV1_1_20_2 = updated_step1.into();
|
||||
let (updated, gateway_config) = updated_step2.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool> {
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_20_2 = old_config.into();
|
||||
let (updated, gateway_config) = updated_step1.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool> {
|
||||
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the client is using <= v1.1.20_2 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let (updated, gateway_config) = old_config.upgrade();
|
||||
persist_gateway_details(&updated, gateway_config)?;
|
||||
|
||||
updated.save_to_default_location()?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn try_upgrade_config(id: &str) -> Result<()> {
|
||||
if try_upgrade_v1_1_13_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_20_2_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use nym_config::defaults::setup_env;
|
||||
use nym_config_common::defaults::setup_env;
|
||||
use tauri::Manager;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
|
||||
@@ -10,58 +10,39 @@ use nym_contracts_common::types::Percent;
|
||||
static SERVICE_PROVIDER_WELLKNOWN_URL: &str =
|
||||
"https://nymtech.net/.wellknown/connect/service-providers.json";
|
||||
|
||||
// List of network-requesters running with medium toggle enabled, for testing
|
||||
static SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM: &str =
|
||||
"https://nymtech.net/.wellknown/connect/service-providers-medium.json";
|
||||
|
||||
static HARBOUR_MASTER_URL: &str = "https://harbourmaster.nymtech.net/v1/services/?size=100";
|
||||
|
||||
static GATEWAYS_DETAILED_URL: &str =
|
||||
"https://validator.nymtech.net/api/v1/status/gateways/detailed";
|
||||
|
||||
fn get_services_url() -> &'static str {
|
||||
std::env::var("NYM_CONNECT_ENABLE_MEDIUM")
|
||||
.is_ok()
|
||||
.then(|| SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM)
|
||||
.unwrap_or(SERVICE_PROVIDER_WELLKNOWN_URL)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_services() -> Result<Vec<DirectoryServiceProvider>> {
|
||||
log::trace!("Fetching services");
|
||||
let all_services = fetch_services().await?;
|
||||
log::trace!("Received: {:#?}", all_services);
|
||||
let services_res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
|
||||
.await?
|
||||
.json::<Vec<DirectoryService>>()
|
||||
.await?;
|
||||
log::trace!("Received: {:#?}", services_res);
|
||||
|
||||
// Early return if we're running with medium toggle enabled
|
||||
if std::env::var("NYM_CONNECT_ENABLE_MEDIUM").is_ok() {
|
||||
return Ok(all_services.into_iter().flat_map(|sp| sp.items).collect());
|
||||
}
|
||||
log::trace!("Fetching gateways");
|
||||
let gateway_res = reqwest::get(GATEWAYS_DETAILED_URL)
|
||||
.await?
|
||||
.json::<Vec<GatewayBondAnnotated>>()
|
||||
.await?;
|
||||
log::trace!("Received: {:#?}", gateway_res);
|
||||
|
||||
// TODO: get paged
|
||||
log::trace!("Fetching active services");
|
||||
let active_services = fetch_active_services().await?;
|
||||
let active_services = reqwest::get(HARBOUR_MASTER_URL)
|
||||
.await?
|
||||
.json::<PagedResult<HarbourMasterService>>()
|
||||
.await?;
|
||||
log::trace!("Active: {:#?}", active_services);
|
||||
|
||||
let filtered_services = filter_out_inactive(all_services, active_services);
|
||||
|
||||
log::trace!("Fetching gateways");
|
||||
let gateway_res = get_gateways_detailed().await?;
|
||||
log::trace!("Received: {:#?}", gateway_res);
|
||||
|
||||
// Use only services that are active AND have a performance of >= 90%
|
||||
let filtered_services_with_good_gateway =
|
||||
filter_out_poor_gateways(filtered_services, gateway_res);
|
||||
|
||||
Ok(filtered_services_with_good_gateway)
|
||||
}
|
||||
|
||||
fn filter_out_inactive(
|
||||
services_res: Vec<DirectoryService>,
|
||||
active_services: PagedResult<HarbourMasterService>,
|
||||
) -> Vec<DirectoryService> {
|
||||
let mut filtered: Vec<DirectoryService> = vec![];
|
||||
for service_type in &services_res {
|
||||
let items = service_type
|
||||
|
||||
for service in &services_res {
|
||||
let items = service
|
||||
.items
|
||||
.clone()
|
||||
.into_iter()
|
||||
@@ -72,48 +53,33 @@ fn filter_out_inactive(
|
||||
.any(|active| active.service_provider_client_id == sp.address)
|
||||
})
|
||||
.collect_vec();
|
||||
log::trace!("service = {} has {} items", service_type.id, items.len());
|
||||
log::trace!("service = {} has {} items", service.id, items.len());
|
||||
filtered.push(DirectoryService {
|
||||
id: service_type.id.clone(),
|
||||
description: service_type.description.clone(),
|
||||
id: service.id.clone(),
|
||||
description: service.description.clone(),
|
||||
items,
|
||||
})
|
||||
}
|
||||
filtered
|
||||
}
|
||||
|
||||
fn filter_out_poor_gateways(
|
||||
services: Vec<DirectoryService>,
|
||||
gateway_res: Vec<GatewayBondAnnotated>,
|
||||
) -> Vec<DirectoryServiceProvider> {
|
||||
let perf_threshold = Percent::from_percentage_value(90).unwrap();
|
||||
services
|
||||
|
||||
// Use only services that are active AND have a performance of >= 90%
|
||||
let services_with_good_performance: Vec<DirectoryServiceProvider> = filtered
|
||||
.iter_mut()
|
||||
.fold(vec![], |mut acc, sp| {
|
||||
acc.append(&mut sp.items);
|
||||
acc
|
||||
})
|
||||
.into_iter()
|
||||
.flat_map(|sp| sp.items)
|
||||
.filter(|sp| {
|
||||
gateway_res.iter().any(|gateway| {
|
||||
gateway.gateway_bond.gateway.identity_key == sp.gateway
|
||||
&& gateway.performance >= perf_threshold
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
.collect();
|
||||
|
||||
async fn fetch_services() -> Result<Vec<DirectoryService>> {
|
||||
let services_url = get_services_url();
|
||||
let services_res = reqwest::get(services_url)
|
||||
.await?
|
||||
.json::<Vec<DirectoryService>>()
|
||||
.await?;
|
||||
Ok(services_res)
|
||||
}
|
||||
|
||||
async fn fetch_active_services() -> Result<PagedResult<HarbourMasterService>> {
|
||||
let active_services = reqwest::get(HARBOUR_MASTER_URL)
|
||||
.await?
|
||||
.json::<PagedResult<HarbourMasterService>>()
|
||||
.await?;
|
||||
Ok(active_services)
|
||||
Ok(services_with_good_performance)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -7,6 +7,7 @@ use nym_socks5_client_core::Socks5ControlMessageSender;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_task::manager::TaskStatus;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tap::TapFallible;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
@@ -43,28 +44,6 @@ pub async fn start_nym_socks5_client(
|
||||
let mut config = Config::read_from_default_path(id)
|
||||
.tap_err(|_| log::warn!("Failed to load configuration file"))?;
|
||||
|
||||
// Disable both the loop cover traffic that runs in the background as well as the Poisson
|
||||
// process that injects cover traffic into the traffic stream.
|
||||
if std::env::var("NYM_CONNECT_DISABLE_COVER").is_ok() {
|
||||
log::warn!("Disabling cover traffic");
|
||||
config.core.base.set_no_cover_traffic_with_keepalive();
|
||||
}
|
||||
|
||||
if std::env::var("NYM_CONNECT_ENABLE_MIXED_SIZE_PACKETS").is_ok() {
|
||||
log::warn!("Enabling mixed size packets");
|
||||
config
|
||||
.core
|
||||
.base
|
||||
.set_secondary_packet_size(Some(PacketSize::ExtendedPacket16));
|
||||
}
|
||||
|
||||
if std::env::var("NYM_CONNECT_DISABLE_PER_HOP_DELAYS").is_ok() {
|
||||
log::warn!("Disabling per-hop delay");
|
||||
config.core.base.set_no_per_hop_delays();
|
||||
}
|
||||
|
||||
log::trace!("Configuration used: {:#?}", config);
|
||||
|
||||
let storage =
|
||||
OnDiskPersistent::from_paths(config.storage_paths.common_paths, &config.core.base.debug)
|
||||
.await?;
|
||||
@@ -76,6 +55,21 @@ pub async fn start_nym_socks5_client(
|
||||
.expect("failed to load gateway details")
|
||||
.into();
|
||||
|
||||
// Disable both the loop cover traffic that runs in the background as well as the Poisson
|
||||
// process that injects cover traffic into the traffic stream.
|
||||
if std::env::var("NYM_CONNECT_DISABLE_COVER").is_ok() {
|
||||
config.core.base.set_no_cover_traffic();
|
||||
}
|
||||
|
||||
if std::env::var("NYM_CONNECT_ENABLE_MIXED_SIZE_PACKETS").is_ok() {
|
||||
config.core.base.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
|
||||
}
|
||||
|
||||
if std::env::var("NYM_CONNECT_DISABLE_PER_HOP_DELAY").is_ok() {
|
||||
config.core.base.debug.traffic.average_packet_delay = Duration::ZERO;
|
||||
config.core.base.debug.acknowledgements.average_ack_delay = Duration::ZERO;
|
||||
}
|
||||
|
||||
log::info!("Starting socks5 client");
|
||||
|
||||
// Channel to send control messages to the socks5 client
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "nym-connect",
|
||||
"version": "1.1.14"
|
||||
"version": "1.1.13"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
@@ -28,7 +28,7 @@
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Copyright © 2021-2023 Nym Technologies SA",
|
||||
"copyright": "Copyright © 2021-2022 Nym Technologies SA",
|
||||
"category": "Business",
|
||||
"shortDescription": "Browse the internet privately using the Nym Mixnet",
|
||||
"longDescription": "",
|
||||
|
||||
@@ -3,31 +3,34 @@ import { Divider, Typography } from '@mui/material';
|
||||
import { Box } from '@mui/system';
|
||||
|
||||
const appsSchema = {
|
||||
messagingApps: ['Matrix', 'Telegram', 'Keybase'],
|
||||
wallets: ['Monero', 'Blockstream', 'Electrum'],
|
||||
messagingApps: ['Telegram', 'Keybase'],
|
||||
wallets: ['Blockstream', 'Electrum'],
|
||||
};
|
||||
|
||||
export const CompatibleApps = () => (
|
||||
<Box>
|
||||
<Typography fontWeight="bold" variant="body2" sx={{ mb: 2 }}>
|
||||
<Typography fontSize="small" color="grey.600" sx={{ mb: 2 }}>
|
||||
Supported apps
|
||||
</Typography>
|
||||
<Typography color="nym.highlight" sx={{ mb: 2 }}>
|
||||
Messaging apps
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ mb: 2 }}>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
<Box sx={{ mb: 4 }}>
|
||||
{appsSchema.messagingApps.map((app) => (
|
||||
<Typography variant="body2" color="grey.400" sx={{ mb: 2 }} key={app}>
|
||||
{app}
|
||||
</Typography>
|
||||
))}
|
||||
</Box>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
<Typography color="nym.highlight" sx={{ mb: 2 }}>
|
||||
Wallets
|
||||
</Typography>
|
||||
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
<Box sx={{ mb: 4 }}>
|
||||
{appsSchema.wallets.map((wallet) => (
|
||||
<Typography variant="body2" color="grey.400" sx={{ mb: 2 }} key={wallet}>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Copyright © 2021-2023 Nym Technologies SA",
|
||||
"copyright": "Copyright © 2021-2022 Nym Technologies SA",
|
||||
"category": "Business",
|
||||
"shortDescription": "Browse the internet privately using the Nym Mixnet",
|
||||
"longDescription": "",
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.2.5] (2023-06-27)
|
||||
|
||||
- Wallet - add "Test my node" in the Node Settings and show its results ([#2314])
|
||||
|
||||
[#2314]: https://github.com/nymtech/nym/issues/2314
|
||||
|
||||
## [v1.2.4] (2023-06-06)
|
||||
|
||||
- Wallet - Bonding page does not load the node info automatically unless you navigate back and forth from it! ([#3478])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_mixnet_contract_common::{EpochId, Interval as ContractInterval, IntervalId};
|
||||
|
||||
@@ -10,30 +10,27 @@ pub(crate) const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6)
|
||||
// -- Contract addresses --
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n10qt8wg0n7z740ssvf3urmvgtjhxpyp74hxqvqt7z226gykuus7eq5u9pvq";
|
||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str =
|
||||
"n1vguuxez2h5ekltfj9gjd62fs5k4rl2zy5hfrncasykzw08rezpfstk9xtk";
|
||||
"n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw";
|
||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
||||
"n19lc9u84cz0yz3fww5283nucc9yvr8gsjmgeul0";
|
||||
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
|
||||
"n1ghd753shjuwexxywmgs4xz7x2q732vcn7ty4yw";
|
||||
pub(crate) const GROUP_CONTRACT_ADDRESS: &str =
|
||||
"n1g4xlpqy29m50j5y69reguae328tc9y83l4299pf2wmjn0xczq5js3704ql";
|
||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str =
|
||||
"n1p54qvfde6mpnqvz3dnpa78x2qyyr5k4sgw9qr97mxjgklc5gze9sv6t964";
|
||||
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str =
|
||||
"n1xqkp8x4gqwjnhemtemc5dqhwll6w6rrgpywvhka7sh8vz8swul9sp3lv3w";
|
||||
pub(crate) const GROUP_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
pub(crate) const COCONUT_DKG_CONTRACT_ADDRESS: &str = "n17p9rzwnnfxcjp32un9ug7yhhzgtkhvl988qccs";
|
||||
pub(crate) const SERVICE_PROVIDER_DIRECTORY_CONTRACT_ADDRESS: &str =
|
||||
"n1nhdr07kmjns2x8dnp53tdk4qxreze8zdxj6xucyvkdj9tta73rjqa96wps";
|
||||
"n1ryt076cufyddallg5x0gz3qjz0pd3wg0m4cwkg9njhmlnp6u88qq6nczgj";
|
||||
pub(crate) const NAME_SERVICE_CONTRACT_ADDRESS: &str =
|
||||
"n1uz24lsnwxvhep8m3gjec7ev86twlhlqrf5rphlgn3rda3zu048ssjqr5w9";
|
||||
"n1cm2u5vfjd3zalfw0p65xyh4tcrw3hjlm0960gzhewga449h4mgas77mjkl";
|
||||
|
||||
// -- Constructor functions --
|
||||
|
||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||
vec![ValidatorDetails::new(
|
||||
"https://qa-validator.qa.nymte.ch/",
|
||||
Some("https://qa-nym-api.qa.nymte.ch/api"),
|
||||
"https://qwerty-validator.qa.nymte.ch/",
|
||||
Some("https://qwerty-validator-api.qa.nymte.ch/api"),
|
||||
)]
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nym-client-wasm": "1.1.1",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -37,7 +37,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
serde_repr = "0.1"
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
tauri = { version = "=1.2.3", features = ["clipboard-all", "shell-open", "updater", "window-maximize", "window-print"] }
|
||||
tauri = { version = "=1.2.3", features = ["clipboard-all", "shell-open", "updater", "window-maximize"] }
|
||||
tendermint-rpc = "0.23.0"
|
||||
time = { version = "0.3.17", features = ["local-offset"] }
|
||||
thiserror = "1.0"
|
||||
|
||||
@@ -14,10 +14,16 @@
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "net.nymtech.wallet",
|
||||
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Copyright © 2021-2023 Nym Technologies SA",
|
||||
"copyright": "Copyright © 2021-2022 Nym Technologies SA",
|
||||
"category": "Business",
|
||||
"shortDescription": "Nym desktop wallet allows you to manage your NYM tokens",
|
||||
"longDescription": "",
|
||||
@@ -39,14 +45,15 @@
|
||||
},
|
||||
"updater": {
|
||||
"active": true,
|
||||
"endpoints": ["https://nymtech.net/.wellknown/wallet/updater.json"],
|
||||
"endpoints": [
|
||||
"https://nymtech.net/.wellknown/wallet/updater.json"
|
||||
],
|
||||
"dialog": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IENCNzQ2M0E5N0VFODE2NApSV1JrZ2U2WE9rYTNETTg1OTBKdE5uWUEra0hML2syOVUvQ2lxZmFZRzZ1T3NWbGM0eVRzUTVhVwo="
|
||||
},
|
||||
"allowlist": {
|
||||
"window": {
|
||||
"maximize": true,
|
||||
"print": true
|
||||
"maximize": true
|
||||
},
|
||||
"clipboard": {
|
||||
"all": true
|
||||
@@ -67,4 +74,4 @@
|
||||
"csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Stack, Typography, Box, useTheme, Grid, LinearProgress, LinearProgressProps, Button } from '@mui/material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Stack, Typography, Box, useTheme, Grid, LinearProgress, LinearProgressProps } from '@mui/material';
|
||||
import { TBondedMixnode } from 'src/context';
|
||||
import { Cell, Pie, PieChart, Legend, ResponsiveContainer } from 'recharts';
|
||||
import { SelectionChance } from '@nymproject/types';
|
||||
@@ -50,7 +49,6 @@ const StatRow = ({
|
||||
export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
|
||||
const { activeSetProbability, routingScore } = mixnode;
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// clamp routing score to [0-100]
|
||||
const score = Math.min(Math.max(routingScore, 0), 100);
|
||||
@@ -74,10 +72,6 @@ export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleGoToTestNode = () => {
|
||||
navigate('/bonding/node-settings', { state: 'test-node' });
|
||||
};
|
||||
|
||||
const renderLegend = () => (
|
||||
<Stack
|
||||
alignItems="center"
|
||||
@@ -97,7 +91,7 @@ export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
|
||||
|
||||
return (
|
||||
<Grid container spacing={4} direction="row" justifyContent="space-between" alignItems="flex-end">
|
||||
<Grid item xs={12} sm={8} md={7} lg={6}>
|
||||
<Grid item xs={12} sm={8} md={7} lg={5}>
|
||||
<NymCard
|
||||
borderless
|
||||
title={
|
||||
@@ -105,11 +99,6 @@ export const NodeStats = ({ mixnode }: { mixnode: TBondedMixnode }) => {
|
||||
Node stats
|
||||
</Typography>
|
||||
}
|
||||
Action={
|
||||
<Button size="small" variant="contained" disableElevation onClick={handleGoToTestNode}>
|
||||
Test node
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Stack justifyContent="center" alignItems="center" mb={2}>
|
||||
<ResponsiveContainer width="100%" height={100}>
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Box, CircularProgress, CircularProgressProps, Stack, Typography } from '@mui/material';
|
||||
import { ResultsCard } from './ResultsCard';
|
||||
|
||||
const getPerformanceDescriptionAndColor = (score: number) => {
|
||||
const res: { description: string; color: CircularProgressProps['color'] } = { description: '', color: 'warning' };
|
||||
|
||||
if (score >= 90) {
|
||||
res.description = 'Reliable node';
|
||||
res.color = 'success';
|
||||
}
|
||||
|
||||
if (score >= 75 && score < 90) {
|
||||
res.description = 'Average node';
|
||||
res.color = 'warning';
|
||||
}
|
||||
|
||||
if (score > 0 && score < 75) {
|
||||
res.description = 'Unreliable node';
|
||||
res.color = 'error';
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const NodeScore = ({ score }: { score: number }) => {
|
||||
const { color } = getPerformanceDescriptionAndColor(score);
|
||||
|
||||
return (
|
||||
<ResultsCard label={<Typography fontWeight="bold">Node score</Typography>} detail="">
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
position: 'relative',
|
||||
width: 250,
|
||||
height: 250,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
mx: 'auto',
|
||||
mt: 4,
|
||||
}}
|
||||
>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
value={100}
|
||||
size={250}
|
||||
sx={{ position: 'absolute', top: 0, left: 0, color: 'grey.200' }}
|
||||
/>
|
||||
<CircularProgress
|
||||
variant="determinate"
|
||||
value={score}
|
||||
size={250}
|
||||
sx={{ position: 'absolute', top: 0, left: 0 }}
|
||||
color={color}
|
||||
/>
|
||||
<Stack alignItems="center" gap={1}>
|
||||
<Typography fontWeight="bold" variant="h4">
|
||||
{Math.round(score)}%
|
||||
</Typography>
|
||||
<Typography>Performance Score</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
</ResultsCard>
|
||||
);
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Box, Button, Stack, Typography } from '@mui/material';
|
||||
import { ResultsCard } from './ResultsCard';
|
||||
|
||||
export const Overview = ({ onStartTest }: { onStartTest: () => void }) => (
|
||||
<ResultsCard
|
||||
label={
|
||||
<Typography variant="h6" fontWeight="bold">
|
||||
Test my node
|
||||
</Typography>
|
||||
}
|
||||
detail=""
|
||||
>
|
||||
<Stack justifyContent="space-between" sx={{ py: 3, height: '100%' }}>
|
||||
<Box>
|
||||
<Typography sx={{ color: 'grey.600', pb: 1 }}>
|
||||
When you click the Test my node button the Nym Wallet creates a path to the Mixnet which uses a gateway and 3
|
||||
nodes. One of the 3 nodes in the path is your node.
|
||||
</Typography>
|
||||
<Typography sx={{ color: 'grey.600', pb: 1 }}>20 test packets are then sent throught the mixnet.</Typography>
|
||||
<Typography sx={{ color: 'grey.600' }}>
|
||||
The test results, including the performance score which is the percentage of packets received back through the
|
||||
network, are then displayed.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box display="flex">
|
||||
<Button variant="contained" disableElevation onClick={onStartTest}>
|
||||
Test my node
|
||||
</Button>
|
||||
</Box>
|
||||
</Stack>
|
||||
</ResultsCard>
|
||||
);
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Divider, Typography } from '@mui/material';
|
||||
import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types';
|
||||
import { ResultsCard, ResultsCardDetail } from './ResultsCard';
|
||||
|
||||
export const Packets = ({
|
||||
sent,
|
||||
received,
|
||||
status,
|
||||
date,
|
||||
}: {
|
||||
sent: number;
|
||||
received: number;
|
||||
status: TestStatus;
|
||||
date: string;
|
||||
}) => (
|
||||
<ResultsCard label={<Typography fontWeight="bold">Status</Typography>} detail="">
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Test date" detail={date} />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Packets sent" detail={sent.toString()} />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Packets received" detail={received.toString()} />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Test status" detail={status} />
|
||||
</ResultsCard>
|
||||
);
|
||||
@@ -1,57 +0,0 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Card, CardContent, CardHeader, Dialog, Divider } from '@mui/material';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { ResultsCardDetail } from './ResultsCard';
|
||||
import { sleep } from 'src/utils/sleep';
|
||||
|
||||
export const PrintResults = ({
|
||||
packetsSent,
|
||||
packetsReceived,
|
||||
score,
|
||||
mixnodeId,
|
||||
mixnodeName,
|
||||
date = '',
|
||||
OnPrintRequestComplete,
|
||||
}: {
|
||||
packetsSent: number;
|
||||
packetsReceived: number;
|
||||
score: number;
|
||||
mixnodeId: string;
|
||||
mixnodeName: string;
|
||||
date?: string;
|
||||
OnPrintRequestComplete: () => void;
|
||||
}) => {
|
||||
const asyncPrint = async () => {
|
||||
await sleep(250);
|
||||
window.print();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
asyncPrint();
|
||||
window.addEventListener('afterprint', OnPrintRequestComplete);
|
||||
|
||||
() => window.removeEventListener('afterprint', OnPrintRequestComplete);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog fullScreen open onClick={OnPrintRequestComplete}>
|
||||
<Card sx={{ width: '100vw', height: '100vh', p: 3 }}>
|
||||
<CardHeader title="Node test results" action={<NymLogo />} sx={{ maxWidth: 800 }} />
|
||||
<CardContent sx={{ maxWidth: 800 }}>
|
||||
<ResultsCardDetail label="Date" detail={date} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Mixnode ID" detail={mixnodeId} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Mixnode name" detail={mixnodeName} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Packets sent" detail={packetsSent.toString()} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Packets received" detail={packetsReceived.toString()} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
<ResultsCardDetail label="Performance score" detail={`${score.toString()}%`} largeText />
|
||||
<Divider sx={{ my: 2 }} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Grid } from '@mui/material';
|
||||
|
||||
import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types';
|
||||
import { Packets } from './Packets';
|
||||
import { NodeScore } from './NodeScore';
|
||||
import { Overview } from './Overview';
|
||||
|
||||
export const Results = ({
|
||||
packetsSent = 0,
|
||||
packetsReceived = 0,
|
||||
score = 0,
|
||||
status,
|
||||
date = '-',
|
||||
onStartTest,
|
||||
}: {
|
||||
packetsSent?: number;
|
||||
packetsReceived?: number;
|
||||
score?: number;
|
||||
status: TestStatus;
|
||||
date?: string;
|
||||
onStartTest: () => void;
|
||||
}) => (
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xl={4} xs={12}>
|
||||
<Overview onStartTest={onStartTest} />
|
||||
</Grid>
|
||||
<Grid item xl={4} xs={6}>
|
||||
<NodeScore score={score} />
|
||||
</Grid>
|
||||
<Grid item xl={4} xs={6}>
|
||||
<Packets sent={packetsSent} received={packetsReceived} status={status} date={date} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
@@ -1,32 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Stack, Typography, Card } from '@mui/material';
|
||||
|
||||
export const ResultsCardDetail = ({
|
||||
label,
|
||||
detail,
|
||||
largeText,
|
||||
}: {
|
||||
label: string | React.ReactNode;
|
||||
detail: string;
|
||||
largeText?: boolean;
|
||||
}) => (
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography variant={largeText ? 'h6' : 'body1'}>{label}</Typography>
|
||||
<Typography variant={largeText ? 'h6' : 'body1'}>{detail}</Typography>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
export const ResultsCard = ({
|
||||
label,
|
||||
detail,
|
||||
children,
|
||||
}: {
|
||||
label: string | React.ReactNode;
|
||||
detail: string;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<Card variant="outlined" sx={{ p: 3, height: '100%' }}>
|
||||
<ResultsCardDetail label={label} detail={detail} />
|
||||
{children}
|
||||
</Card>
|
||||
);
|
||||
@@ -1,5 +0,0 @@
|
||||
const QA_VALIDATOR_URL = 'https://qa-nym-api.qa.nymte.ch/api';
|
||||
const QWERTY_VALIDATOR_URL = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
const MAINNET_VALIDATOR_URL = 'https://validator.nymtech.net/api/';
|
||||
|
||||
export { QA_VALIDATOR_URL, QWERTY_VALIDATOR_URL, MAINNET_VALIDATOR_URL };
|
||||
@@ -17,9 +17,8 @@ import { isMixnode } from 'src/types';
|
||||
import { getIntervalAsDate } from 'src/utils';
|
||||
import { NodeGeneralSettings } from './settings-pages/general-settings';
|
||||
import { NodeUnbondPage } from './settings-pages/NodeUnbondPage';
|
||||
import { NavItems, makeNavItems } from './node-settings.constant';
|
||||
import { makeNavItems } from './node-settings.constant';
|
||||
import { ApyPlayground } from './apy-playground';
|
||||
import { NodeTestPage } from './node-test';
|
||||
|
||||
export const NodeSettings = () => {
|
||||
const theme = useTheme();
|
||||
@@ -29,19 +28,15 @@ export const NodeSettings = () => {
|
||||
const location = useLocation();
|
||||
|
||||
const [confirmationDetails, setConfirmationDetails] = useState<ConfirmationDetailProps | undefined>();
|
||||
const [value, setValue] = React.useState<NavItems>('General');
|
||||
|
||||
const handleChange = (_: React.SyntheticEvent, tab: string) => {
|
||||
setValue(tab as NavItems);
|
||||
const [value, setValue] = React.useState('General');
|
||||
const handleChange = (event: React.SyntheticEvent, tab: string) => {
|
||||
setValue(tab);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (location.state === 'unbond') {
|
||||
setValue('Unbond');
|
||||
}
|
||||
if (location.state === 'test-node') {
|
||||
setValue('Test my node');
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const handleUnbond = async (fee?: FeeDetails) => {
|
||||
@@ -102,7 +97,7 @@ export const NodeSettings = () => {
|
||||
'& button': {
|
||||
p: 0,
|
||||
mr: 4,
|
||||
|
||||
minWidth: 'none',
|
||||
fontSize: 16,
|
||||
},
|
||||
'& button:hover': {
|
||||
@@ -129,7 +124,6 @@ export const NodeSettings = () => {
|
||||
>
|
||||
<Divider />
|
||||
{value === 'General' && bondedNode && <NodeGeneralSettings bondedNode={bondedNode} />}
|
||||
{value === 'Test my node' && <NodeTestPage />}
|
||||
{value === 'Unbond' && bondedNode && (
|
||||
<NodeUnbondPage bondedNode={bondedNode} onConfirm={handleUnbond} onError={handleError} />
|
||||
)}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
export const makeNavItems = (isMixnode: boolean) => {
|
||||
const navItems: NavItems[] = ['General', 'Unbond'];
|
||||
const navItems = ['General', 'Unbond'];
|
||||
|
||||
if (isMixnode) navItems.splice(1, 0, 'Test my node', 'Playground');
|
||||
if (isMixnode) navItems.splice(1, 0, 'Playground');
|
||||
|
||||
return navItems;
|
||||
};
|
||||
|
||||
export type NavItems = 'General' | 'Unbond' | 'Test my node' | 'Playground';
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { WasmGateway, WasmMixNode, WasmNymTopology } from 'nym-client-wasm';
|
||||
|
||||
export const createDummyTopology = () => {
|
||||
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);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user