Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e215646c3 | |||
| a8dc703399 | |||
| e09986e505 | |||
| bb3c015633 | |||
| b21346064e | |||
| fa81b96951 | |||
| 8cccc9ab24 | |||
| b567ac22d3 | |||
| b43a1b8c94 | |||
| d7da6ed1ab | |||
| 4d62dc9c74 | |||
| 2d39f3c722 | |||
| 3d122f45b4 | |||
| cb375f15c2 | |||
| 7406fdd677 | |||
| d7d4c9f09a | |||
| 94d83648c2 | |||
| aa51af7023 | |||
| f45ed78806 | |||
| c0337ec1d4 | |||
| 6fe049d1a2 | |||
| 63ed99d4d6 | |||
| 2061629d1d | |||
| 9b99a19ba0 | |||
| 6a3afb50b8 | |||
| bea64b926f | |||
| 3b83c30558 | |||
| ceeccbba07 | |||
| be55bb61cb | |||
| f2af35fc2e | |||
| b874fc9314 | |||
| 914c586e68 | |||
| 10ba3c2ab9 | |||
| 7e32787ab2 | |||
| 7062f69e45 | |||
| 5e98c14a98 | |||
| f04d1fea56 | |||
| 836e237116 | |||
| 0f9bd648a1 | |||
| 0c2c0bdc54 | |||
| 991cc3fa01 | |||
| 3510ee8df6 | |||
| 6774158e7a | |||
| f98698a121 | |||
| 8e99c17f49 | |||
| ab4cc9b282 | |||
| dbe6a5de7d | |||
| 1948fd8e67 | |||
| c8f38ae785 | |||
| f32ea17de5 | |||
| 4ac25aef4d | |||
| 3ad6a31e1f | |||
| 6cacc53e5a | |||
| 387933a975 | |||
| f6c24412c0 | |||
| 5c753c0794 |
@@ -4,18 +4,18 @@ on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'clients/**'
|
||||
- 'common/**'
|
||||
- 'explorer-api/**'
|
||||
- 'gateway/**'
|
||||
- 'integrations/**'
|
||||
- 'mixnode/**'
|
||||
- 'sdk/rust/nym-sdk/**'
|
||||
- 'service-providers/**'
|
||||
- 'nym-api/**'
|
||||
- 'nym-outfox/**'
|
||||
- 'tools/nym-cli/**'
|
||||
- 'tools/ts-rs-cli/**'
|
||||
- "clients/**"
|
||||
- "common/**"
|
||||
- "explorer-api/**"
|
||||
- "gateway/**"
|
||||
- "integrations/**"
|
||||
- "mixnode/**"
|
||||
- "sdk/rust/nym-sdk/**"
|
||||
- "service-providers/**"
|
||||
- "nym-api/**"
|
||||
- "nym-outfox/**"
|
||||
- "tools/nym-cli/**"
|
||||
- "tools/ts-rs-cli/**"
|
||||
|
||||
jobs:
|
||||
publish-nym:
|
||||
@@ -53,6 +53,16 @@ jobs:
|
||||
command: build
|
||||
args: --workspace --release
|
||||
|
||||
- name: Install cargo-deb
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: cargo-deb
|
||||
|
||||
- name: Build deb packages
|
||||
shell: bash
|
||||
run: make deb
|
||||
|
||||
- name: Prepare build output
|
||||
shell: bash
|
||||
env:
|
||||
@@ -67,6 +77,7 @@ jobs:
|
||||
cp target/release/nym-network-statistics $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/explorer-api $OUTPUT_DIR
|
||||
cp target/debian/*.deb $OUTPUT_DIR
|
||||
|
||||
- name: Deploy branch to CI www
|
||||
continue-on-error: true
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
name: ci-cargo-deny
|
||||
on: [workflow_dispatch]
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -7,10 +10,7 @@ jobs:
|
||||
matrix:
|
||||
checks:
|
||||
# - advisories
|
||||
- licenses
|
||||
- bans sources
|
||||
|
||||
continue-on-error: ${{ matrix.checks == 'licenses' }}
|
||||
- licenses bans sources
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: install yarn in root
|
||||
run: cd ../.. yarn install
|
||||
run: cd ../.. && yarn install
|
||||
|
||||
- name: Install npm
|
||||
run: npm install
|
||||
|
||||
Generated
+90
-43
@@ -187,6 +187,16 @@ dependencies = [
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr"
|
||||
version = "0.15.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a93b8a41dbe230ad5087cc721f8d41611de654542180586b315d9f4cf6b72bef"
|
||||
dependencies = [
|
||||
"psl",
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
@@ -1610,9 +1620,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24"
|
||||
checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
@@ -3987,6 +3997,16 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
@@ -6226,6 +6246,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"si-scale",
|
||||
"sqlx",
|
||||
"tap",
|
||||
"tempfile",
|
||||
@@ -6652,21 +6673,27 @@ name = "nym-ip-packet-router"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bs58 0.4.0",
|
||||
"bytes",
|
||||
"clap 4.4.7",
|
||||
"etherparse",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-crypto",
|
||||
"nym-exit-policy",
|
||||
"nym-ip-packet-requests",
|
||||
"nym-network-defaults",
|
||||
"nym-network-requester",
|
||||
"nym-sdk",
|
||||
"nym-service-providers-common",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-tun",
|
||||
"nym-types",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-types",
|
||||
"rand 0.8.5",
|
||||
@@ -6825,6 +6852,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"dotenvy",
|
||||
"hex-literal",
|
||||
"log",
|
||||
"once_cell",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -6836,6 +6864,7 @@ dependencies = [
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.32"
|
||||
dependencies = [
|
||||
"addr",
|
||||
"anyhow",
|
||||
"async-file-watcher",
|
||||
"async-trait",
|
||||
@@ -7732,9 +7761,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "okapi"
|
||||
version = "0.7.0-rc.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce66b6366e049880a35c378123fddb630b1a1a3c37fa1ca70caaf4a09f6e2893"
|
||||
checksum = "9a64853d7ab065474e87696f7601cee817d200e86c42e04004e005cb3e20c3c5"
|
||||
dependencies = [
|
||||
"log",
|
||||
"schemars",
|
||||
@@ -8063,7 +8092,7 @@ checksum = "61a386cd715229d399604b50d1361683fe687066f42d56f54be995bc6868f71c"
|
||||
dependencies = [
|
||||
"inlinable_string",
|
||||
"pear_codegen",
|
||||
"yansi 1.0.0-rc.1",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8440,7 +8469,7 @@ dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
"version_check",
|
||||
"yansi 1.0.0-rc.1",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8565,14 +8594,28 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "1.5.6"
|
||||
name = "psl"
|
||||
version = "2.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f"
|
||||
checksum = "383703acfc34f7a00724846c14dc5ea4407c59e5aedcbbb18a1c0c1a23fe5013"
|
||||
dependencies = [
|
||||
"idna 0.2.3",
|
||||
"native-tls",
|
||||
"url",
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psl-types"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac"
|
||||
|
||||
[[package]]
|
||||
name = "publicsuffix"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457"
|
||||
dependencies = [
|
||||
"idna 0.3.0",
|
||||
"psl-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9175,9 +9218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.5.0-rc.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58734f7401ae5cfd129685b48f61182331745b357b96f2367f01aebaf1cc9cc9"
|
||||
checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
@@ -9187,8 +9230,7 @@ dependencies = [
|
||||
"either",
|
||||
"figment",
|
||||
"futures",
|
||||
"indexmap 1.9.3",
|
||||
"is-terminal",
|
||||
"indexmap 2.0.2",
|
||||
"log",
|
||||
"memchr",
|
||||
"multer",
|
||||
@@ -9209,30 +9251,33 @@ dependencies = [
|
||||
"tokio-util",
|
||||
"ubyte",
|
||||
"version_check",
|
||||
"yansi 0.5.1",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.5.0-rc.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b"
|
||||
checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c"
|
||||
dependencies = [
|
||||
"devise",
|
||||
"glob",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.0.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rocket_http",
|
||||
"syn 2.0.38",
|
||||
"unicode-xid",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_cors"
|
||||
version = "0.5.2"
|
||||
source = "git+https://github.com/lawliet89/rocket_cors?rev=dfd3662c49e2f6fc37df35091cb94d82f7fb5915#dfd3662c49e2f6fc37df35091cb94d82f7fb5915"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfac3a1df83f8d4fc96aa41dba3b86c786417b7fc0f52ec76295df2ba781aa69"
|
||||
dependencies = [
|
||||
"http",
|
||||
"log",
|
||||
"regex",
|
||||
"rocket",
|
||||
@@ -9245,16 +9290,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.5.0-rc.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4"
|
||||
checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e"
|
||||
dependencies = [
|
||||
"cookie 0.17.0",
|
||||
"cookie 0.18.0",
|
||||
"either",
|
||||
"futures",
|
||||
"http",
|
||||
"hyper",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.0.2",
|
||||
"log",
|
||||
"memchr",
|
||||
"pear",
|
||||
@@ -9272,11 +9317,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_okapi"
|
||||
version = "0.8.0-rc.3"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "742098674565c8f0c35c77444f90344aafedebb71cfee9cdbf0185acc6b9cdb7"
|
||||
checksum = "e059407ecef9ee2f071fc971e10444fcf942149deb028879d6d8ca61a7ce9edc"
|
||||
dependencies = [
|
||||
"either",
|
||||
"log",
|
||||
"okapi",
|
||||
"rocket",
|
||||
@@ -9288,9 +9332,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rocket_okapi_codegen"
|
||||
version = "0.8.0-rc.3"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c43f8edc57d88750a220b0ec1870a36c1106204ec99cc35131b49de3b954a4a"
|
||||
checksum = "cfb96114e69e5d7f80bfa0948cbc0120016e9b460954abe9eed37e9a2ad3f999"
|
||||
dependencies = [
|
||||
"darling 0.13.4",
|
||||
"proc-macro2",
|
||||
@@ -9606,9 +9650,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c"
|
||||
checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"indexmap 1.9.3",
|
||||
@@ -9619,9 +9663,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.15"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c"
|
||||
checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10019,6 +10063,12 @@ dependencies = [
|
||||
"dirs 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "si-scale"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44beb68bf488343b13ddbd74d1d5d5e6559a58b6dfaee74eb8d5ed4f7ed7666f"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
@@ -10378,9 +10428,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
|
||||
checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8"
|
||||
dependencies = [
|
||||
"loom",
|
||||
]
|
||||
@@ -12632,17 +12682,14 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.0-rc.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377"
|
||||
dependencies = [
|
||||
"is-terminal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yasna"
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ default-members = [
|
||||
"nym-validator-rewarder",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles"]
|
||||
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles", "sdk/ffi/cpp"]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
|
||||
@@ -12,7 +12,7 @@ help:
|
||||
@echo " clippy: run clippy for all workspaces"
|
||||
@echo " test: run clippy, unit tests, and formatting."
|
||||
@echo " test-all: like test, but also includes the expensive tests"
|
||||
@echo " ppa: build debian package and generate files required for PPA update"
|
||||
@echo " deb: build debian packages
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Meta targets
|
||||
@@ -176,6 +176,13 @@ run-api-tests:
|
||||
cd nym-api/tests/functional_test && yarn test:qa
|
||||
|
||||
# Build debian package, and update PPA
|
||||
# Requires base64 encode GPG key to be set up in environment PPA_SIGNING_KEY
|
||||
ppa: build-nym-mixnode build-nym-gateway
|
||||
scripts/ppa.sh
|
||||
deb-mixnode: build-nym-mixnode
|
||||
cargo deb -p nym-mixnode
|
||||
|
||||
deb-gateway: build-nym-gateway
|
||||
cargo deb -p nym-gateway
|
||||
|
||||
deb-cli: build-nym-cli
|
||||
cargo deb -p nym-cli
|
||||
|
||||
deb: deb-mixnode deb-gateway deb-cli
|
||||
@@ -51,7 +51,7 @@ impl InitialisableClient for NativeClientInit {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub(crate) struct Init {
|
||||
#[command(flatten)]
|
||||
common_args: CommonClientInitArgs,
|
||||
|
||||
@@ -51,7 +51,7 @@ impl InitialisableClient for Socks5ClientInit {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
#[derive(Args, Clone, Debug)]
|
||||
pub(crate) struct Init {
|
||||
#[command(flatten)]
|
||||
common_args: CommonClientInitArgs,
|
||||
|
||||
@@ -46,6 +46,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
|
||||
nym-task = { path = "../task" }
|
||||
nym-credential-storage = { path = "../credential-storage" }
|
||||
nym-network-defaults = { path = "../network-defaults" }
|
||||
si-scale = "0.2.2"
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.tokio-stream]
|
||||
version = "0.1.11"
|
||||
|
||||
@@ -109,6 +109,8 @@ pub async fn initialise_client<C>(
|
||||
) -> Result<InitResultsWithConfig<C::Config>, C::Error>
|
||||
where
|
||||
C: InitialisableClient,
|
||||
<C as InitialisableClient>::Config: std::fmt::Debug,
|
||||
<C as InitialisableClient>::InitArgs: std::fmt::Debug,
|
||||
{
|
||||
info!("initialising {} client", C::NAME);
|
||||
|
||||
@@ -140,17 +142,32 @@ where
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = common_args.gateway;
|
||||
log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}");
|
||||
|
||||
let selection_spec = GatewaySelectionSpecification::new(
|
||||
user_chosen_gateway_id.map(|id| id.to_base58_string()),
|
||||
Some(common_args.latency_based_selection),
|
||||
false,
|
||||
);
|
||||
log::debug!("Gateway selection specification: {selection_spec:?}");
|
||||
|
||||
// Load and potentially override config
|
||||
log::debug!("Init arguments: {init_args:#?}");
|
||||
let config = C::construct_config(&init_args);
|
||||
log::debug!("Constructed config: {config:#?}");
|
||||
let paths = config.common_paths();
|
||||
let core = config.core_config();
|
||||
|
||||
log::info!(
|
||||
"Using nym-api: {}",
|
||||
core.client
|
||||
.nym_api_urls
|
||||
.iter()
|
||||
.map(|url| url.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(",")
|
||||
);
|
||||
|
||||
// Setup gateway by either registering a new one, or creating a new config from the selected
|
||||
// one but with keys kept, or reusing the gateway configuration.
|
||||
let key_store = OnDiskKeys::new(paths.keys.clone());
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use si_scale::helpers::bibytes2;
|
||||
|
||||
use crate::spawn_future;
|
||||
|
||||
// Time interval between reporting packet statistics
|
||||
const PACKET_REPORT_INTERVAL_SECS: u64 = 2;
|
||||
// Interval for taking snapshots of the packet statistics
|
||||
const SNAPSHOT_INTERVAL_MS: u64 = 500;
|
||||
// When computing rates, we include snapshots that are up to this old. We set it to some odd number
|
||||
// a tad larger than an integer number of snapshot intervals, so that we don't have to worry about
|
||||
// threshold effects.
|
||||
// Also, set it larger than the packet report interval so that we don't miss notable singular events
|
||||
const RECORDING_WINDOW_MS: u64 = 2300;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct PacketStatistics {
|
||||
// Sent
|
||||
real_packets_sent: u64,
|
||||
@@ -80,6 +92,200 @@ impl PacketStatistics {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn summary(&self) -> (String, String) {
|
||||
(
|
||||
format!(
|
||||
"packets sent: {} (real: {}, cover: {}, retransmissions: {})",
|
||||
self.real_packets_sent + self.cover_packets_sent,
|
||||
self.real_packets_sent,
|
||||
self.cover_packets_sent,
|
||||
self.retransmissions_queued,
|
||||
),
|
||||
format!(
|
||||
"packets received: {}, (real: {}, cover: {}, acks: {}, acks for cover: {})",
|
||||
self.real_packets_received + self.cover_packets_received,
|
||||
self.real_packets_received,
|
||||
self.cover_packets_received,
|
||||
self.real_acks_received,
|
||||
self.cover_acks_received,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for PacketStatistics {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
real_packets_sent: self.real_packets_sent - rhs.real_packets_sent,
|
||||
real_packets_sent_size: self.real_packets_sent_size - rhs.real_packets_sent_size,
|
||||
cover_packets_sent: self.cover_packets_sent - rhs.cover_packets_sent,
|
||||
cover_packets_sent_size: self.cover_packets_sent_size - rhs.cover_packets_sent_size,
|
||||
|
||||
real_packets_received: self.real_packets_received - rhs.real_packets_received,
|
||||
real_packets_received_size: self.real_packets_received_size
|
||||
- rhs.real_packets_received_size,
|
||||
cover_packets_received: self.cover_packets_received - rhs.cover_packets_received,
|
||||
cover_packets_received_size: self.cover_packets_received_size
|
||||
- rhs.cover_packets_received_size,
|
||||
|
||||
total_acks_received: self.total_acks_received - rhs.total_acks_received,
|
||||
total_acks_received_size: self.total_acks_received_size - rhs.total_acks_received_size,
|
||||
real_acks_received: self.real_acks_received - rhs.real_acks_received,
|
||||
real_acks_received_size: self.real_acks_received_size - rhs.real_acks_received_size,
|
||||
cover_acks_received: self.cover_acks_received - rhs.cover_acks_received,
|
||||
cover_acks_received_size: self.cover_acks_received_size - rhs.cover_acks_received_size,
|
||||
|
||||
real_packets_queued: self.real_packets_queued - rhs.real_packets_queued,
|
||||
retransmissions_queued: self.retransmissions_queued - rhs.retransmissions_queued,
|
||||
reply_surbs_queued: self.reply_surbs_queued - rhs.reply_surbs_queued,
|
||||
additional_reply_surbs_queued: self.additional_reply_surbs_queued
|
||||
- rhs.additional_reply_surbs_queued,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PacketRates {
|
||||
real_packets_sent: f64,
|
||||
real_packets_sent_size: f64,
|
||||
cover_packets_sent: f64,
|
||||
cover_packets_sent_size: f64,
|
||||
|
||||
real_packets_received: f64,
|
||||
real_packets_received_size: f64,
|
||||
cover_packets_received: f64,
|
||||
cover_packets_received_size: f64,
|
||||
|
||||
total_acks_received: f64,
|
||||
total_acks_received_size: f64,
|
||||
real_acks_received: f64,
|
||||
real_acks_received_size: f64,
|
||||
cover_acks_received: f64,
|
||||
cover_acks_received_size: f64,
|
||||
|
||||
real_packets_queued: f64,
|
||||
retransmissions_queued: f64,
|
||||
reply_surbs_queued: f64,
|
||||
additional_reply_surbs_queued: f64,
|
||||
}
|
||||
|
||||
impl From<PacketStatistics> for PacketRates {
|
||||
fn from(stats: PacketStatistics) -> Self {
|
||||
Self {
|
||||
real_packets_sent: stats.real_packets_sent as f64,
|
||||
real_packets_sent_size: stats.real_packets_sent_size as f64,
|
||||
cover_packets_sent: stats.cover_packets_sent as f64,
|
||||
cover_packets_sent_size: stats.cover_packets_sent_size as f64,
|
||||
|
||||
real_packets_received: stats.real_packets_received as f64,
|
||||
real_packets_received_size: stats.real_packets_received_size as f64,
|
||||
cover_packets_received: stats.cover_packets_received as f64,
|
||||
cover_packets_received_size: stats.cover_packets_received_size as f64,
|
||||
|
||||
total_acks_received: stats.total_acks_received as f64,
|
||||
total_acks_received_size: stats.total_acks_received_size as f64,
|
||||
real_acks_received: stats.real_acks_received as f64,
|
||||
real_acks_received_size: stats.real_acks_received_size as f64,
|
||||
cover_acks_received: stats.cover_acks_received as f64,
|
||||
cover_acks_received_size: stats.cover_acks_received_size as f64,
|
||||
|
||||
real_packets_queued: stats.real_packets_queued as f64,
|
||||
retransmissions_queued: stats.retransmissions_queued as f64,
|
||||
reply_surbs_queued: stats.reply_surbs_queued as f64,
|
||||
additional_reply_surbs_queued: stats.additional_reply_surbs_queued as f64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for PacketRates {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
real_packets_sent: self.real_packets_sent - rhs.real_packets_sent,
|
||||
real_packets_sent_size: self.real_packets_sent_size - rhs.real_packets_sent_size,
|
||||
cover_packets_sent: self.cover_packets_sent - rhs.cover_packets_sent,
|
||||
cover_packets_sent_size: self.cover_packets_sent_size - rhs.cover_packets_sent_size,
|
||||
|
||||
real_packets_received: self.real_packets_received - rhs.real_packets_received,
|
||||
real_packets_received_size: self.real_packets_received_size
|
||||
- rhs.real_packets_received_size,
|
||||
cover_packets_received: self.cover_packets_received - rhs.cover_packets_received,
|
||||
cover_packets_received_size: self.cover_packets_received_size
|
||||
- rhs.cover_packets_received_size,
|
||||
|
||||
total_acks_received: self.total_acks_received - rhs.total_acks_received,
|
||||
total_acks_received_size: self.total_acks_received_size - rhs.total_acks_received_size,
|
||||
real_acks_received: self.real_acks_received - rhs.real_acks_received,
|
||||
real_acks_received_size: self.real_acks_received_size - rhs.real_acks_received_size,
|
||||
cover_acks_received: self.cover_acks_received - rhs.cover_acks_received,
|
||||
cover_acks_received_size: self.cover_acks_received_size - rhs.cover_acks_received_size,
|
||||
|
||||
real_packets_queued: self.real_packets_queued - rhs.real_packets_queued,
|
||||
retransmissions_queued: self.retransmissions_queued - rhs.retransmissions_queued,
|
||||
reply_surbs_queued: self.reply_surbs_queued - rhs.reply_surbs_queued,
|
||||
additional_reply_surbs_queued: self.additional_reply_surbs_queued
|
||||
- rhs.additional_reply_surbs_queued,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Div<f64> for PacketRates {
|
||||
type Output = Self;
|
||||
|
||||
fn div(self, rhs: f64) -> Self::Output {
|
||||
Self {
|
||||
real_packets_sent: self.real_packets_sent / rhs,
|
||||
real_packets_sent_size: self.real_packets_sent_size / rhs,
|
||||
cover_packets_sent: self.cover_packets_sent / rhs,
|
||||
cover_packets_sent_size: self.cover_packets_sent_size / rhs,
|
||||
|
||||
real_packets_received: self.real_packets_received / rhs,
|
||||
real_packets_received_size: self.real_packets_received_size / rhs,
|
||||
cover_packets_received: self.cover_packets_received / rhs,
|
||||
cover_packets_received_size: self.cover_packets_received_size / rhs,
|
||||
|
||||
total_acks_received: self.total_acks_received / rhs,
|
||||
total_acks_received_size: self.total_acks_received_size / rhs,
|
||||
real_acks_received: self.real_acks_received / rhs,
|
||||
real_acks_received_size: self.real_acks_received_size / rhs,
|
||||
cover_acks_received: self.cover_acks_received / rhs,
|
||||
cover_acks_received_size: self.cover_acks_received_size / rhs,
|
||||
|
||||
real_packets_queued: self.real_packets_queued / rhs,
|
||||
retransmissions_queued: self.retransmissions_queued / rhs,
|
||||
reply_surbs_queued: self.reply_surbs_queued / rhs,
|
||||
additional_reply_surbs_queued: self.additional_reply_surbs_queued / rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRates {
|
||||
fn summary(&self) -> String {
|
||||
format!(
|
||||
"rx: {}/s (real: {}/s), tx: {}/s (real: {}/s)",
|
||||
bibytes2(self.real_packets_received_size + self.cover_packets_received_size),
|
||||
bibytes2(self.real_packets_received_size),
|
||||
bibytes2(self.real_packets_sent_size + self.cover_packets_sent_size),
|
||||
bibytes2(self.real_packets_sent_size),
|
||||
)
|
||||
}
|
||||
|
||||
fn detailed_summary(&self) -> String {
|
||||
format!(
|
||||
"RX: {:.1} mixpkt/s, {}/s (real: {}/s, acks: {}/s), TX: {:.1} mixpkt/s, {}/s (real: {}/s)",
|
||||
self.real_packets_received + self.cover_packets_received,
|
||||
bibytes2(self.real_packets_received_size + self.cover_packets_received_size),
|
||||
bibytes2(self.real_packets_received_size),
|
||||
bibytes2(self.total_acks_received_size),
|
||||
self.real_packets_sent + self.cover_packets_sent,
|
||||
bibytes2(self.real_packets_sent_size + self.cover_packets_sent_size),
|
||||
bibytes2(self.real_packets_sent_size),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum PacketStatisticsEvent {
|
||||
@@ -130,45 +336,129 @@ impl PacketStatisticsReporter {
|
||||
pub(crate) struct PacketStatisticsControl {
|
||||
// Incoming packet stats events from other tasks
|
||||
stats_rx: PacketStatisticsReceiver,
|
||||
|
||||
// Keep track of packet statistics over time
|
||||
stats: PacketStatistics,
|
||||
|
||||
// We keep snapshots of the statistics over time so we can compute rates, and also keeping the
|
||||
// full history allows for some more fancy averaging if we want to do that.
|
||||
history: VecDeque<(Instant, PacketStatistics)>,
|
||||
|
||||
// Keep previous rates so that we can detect notable events
|
||||
rates: VecDeque<(Instant, PacketRates)>,
|
||||
}
|
||||
|
||||
impl PacketStatisticsControl {
|
||||
pub(crate) fn new() -> (Self, PacketStatisticsReporter) {
|
||||
let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
(
|
||||
Self {
|
||||
stats_rx,
|
||||
stats: PacketStatistics::default(),
|
||||
history: VecDeque::new(),
|
||||
rates: VecDeque::new(),
|
||||
},
|
||||
PacketStatisticsReporter::new(stats_tx),
|
||||
)
|
||||
}
|
||||
|
||||
fn report_statistics(&self) {
|
||||
// Add the current stats to the history, and remove old ones.
|
||||
fn update_history(&mut self) {
|
||||
// Update latest
|
||||
self.history.push_back((Instant::now(), self.stats.clone()));
|
||||
|
||||
// Filter out old ones
|
||||
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
|
||||
while self
|
||||
.history
|
||||
.front()
|
||||
.map_or(false, |&(t, _)| t < recording_window)
|
||||
{
|
||||
self.history.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_rates(&self) -> Option<PacketRates> {
|
||||
// NOTE: consider changing this to compute rates over the history instead of using current
|
||||
// stats. Currently it should not make much of a difference since we call this just after
|
||||
// updating the history, but it seems like it could be more internally consistent to do it
|
||||
// that way.
|
||||
|
||||
// Do basic averaging over the entire history, which just uses the first and last
|
||||
if let Some((start, start_stats)) = self.history.front() {
|
||||
let duration_secs = Instant::now().duration_since(*start).as_secs_f64();
|
||||
let delta = self.stats.clone() - start_stats.clone();
|
||||
let rates = PacketRates::from(delta) / duration_secs;
|
||||
Some(rates)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn update_rates(&mut self) {
|
||||
// Update latest
|
||||
if let Some(rates) = self.compute_rates() {
|
||||
self.rates.push_back((Instant::now(), rates));
|
||||
}
|
||||
|
||||
// Filter out old ones
|
||||
let recording_window = Instant::now() - Duration::from_millis(RECORDING_WINDOW_MS);
|
||||
while self
|
||||
.rates
|
||||
.front()
|
||||
.map_or(false, |&(t, _)| t < recording_window)
|
||||
{
|
||||
self.rates.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
fn report_rates(&self) {
|
||||
if let Some((_, rates)) = self.rates.back() {
|
||||
log::info!("{}", rates.summary());
|
||||
log::debug!("{}", rates.detailed_summary());
|
||||
}
|
||||
}
|
||||
|
||||
fn report_counters(&self) {
|
||||
log::trace!("packet statistics: {:?}", &self.stats);
|
||||
log::info!(
|
||||
"packets sent: {} (real: {}, cover: {}, retransmissions: {})",
|
||||
self.stats.real_packets_sent + self.stats.cover_packets_sent,
|
||||
self.stats.real_packets_sent,
|
||||
self.stats.cover_packets_sent,
|
||||
self.stats.retransmissions_queued,
|
||||
);
|
||||
log::info!(
|
||||
"packets received: {}, (real: {}, cover: {}, acks: {}, acks for cover: {})",
|
||||
self.stats.real_packets_received + self.stats.cover_packets_received,
|
||||
self.stats.real_packets_received,
|
||||
self.stats.cover_packets_received,
|
||||
self.stats.real_acks_received,
|
||||
self.stats.cover_acks_received,
|
||||
);
|
||||
let (summary_sent, summary_recv) = self.stats.summary();
|
||||
log::debug!("{}", summary_sent);
|
||||
log::debug!("{}", summary_recv);
|
||||
}
|
||||
|
||||
fn check_for_notable_events(&self) {
|
||||
let Some((_, latest_rates)) = self.rates.back() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// If we get a burst of retransmissions
|
||||
// TODO: consider making this the number of retransmissions since last report instead.
|
||||
if latest_rates.retransmissions_queued > 0.0 {
|
||||
log::debug!(
|
||||
"retransmissions: {:.2} pkt/s",
|
||||
latest_rates.retransmissions_queued
|
||||
);
|
||||
|
||||
// Check what the number of retransmissions was during the recording window
|
||||
if let Some((_, start_stats)) = self.history.front() {
|
||||
let delta = self.stats.clone() - start_stats.clone();
|
||||
log::info!("retransmissions: {}", delta.retransmissions_queued,);
|
||||
} else {
|
||||
log::warn!("Unable to check retransmissions during recording window");
|
||||
}
|
||||
}
|
||||
|
||||
// IDEA: if there is a burst of acks, that could indicate tokio task starvation.
|
||||
}
|
||||
|
||||
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
log::debug!("Started PacketStatisticsControl with graceful shutdown support");
|
||||
|
||||
let interval = Duration::from_secs(PACKET_REPORT_INTERVAL_SECS);
|
||||
let mut interval = tokio::time::interval(interval);
|
||||
let report_interval = Duration::from_secs(PACKET_REPORT_INTERVAL_SECS);
|
||||
let mut report_interval = tokio::time::interval(report_interval);
|
||||
let snapshot_interval = Duration::from_millis(SNAPSHOT_INTERVAL_MS);
|
||||
let mut snapshot_interval = tokio::time::interval(snapshot_interval);
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
@@ -182,8 +472,14 @@ impl PacketStatisticsControl {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ = interval.tick() => {
|
||||
self.report_statistics();
|
||||
_ = snapshot_interval.tick() => {
|
||||
self.update_history();
|
||||
self.update_rates();
|
||||
}
|
||||
_ = report_interval.tick() => {
|
||||
self.report_rates();
|
||||
self.check_for_notable_events();
|
||||
self.report_counters();
|
||||
}
|
||||
_ = shutdown.recv_with_delay() => {
|
||||
log::trace!("PacketStatisticsControl: Received shutdown");
|
||||
|
||||
@@ -50,19 +50,26 @@ struct ReceivedMessagesBufferInner<R: MessageReceiver> {
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
|
||||
fn recover_from_fragment(&mut self, fragment_data: &[u8]) -> Option<NymMessage> {
|
||||
fn recover_from_fragment(
|
||||
&mut self,
|
||||
fragment_data: &[u8],
|
||||
fragment_data_size: usize,
|
||||
) -> Option<NymMessage> {
|
||||
if nym_sphinx::cover::is_cover(fragment_data) {
|
||||
trace!("The message was a loop cover message! Skipping it");
|
||||
// NOTE: it's important to note that there is quite a bit of difference in size of
|
||||
// received and sent packets due to the sphinx layers being removed by the exit gateway
|
||||
// before it reaches the mixnet client.
|
||||
self.stats_tx
|
||||
.report(PacketStatisticsEvent::CoverPacketReceived(
|
||||
fragment_data.len(),
|
||||
fragment_data_size,
|
||||
));
|
||||
return None;
|
||||
}
|
||||
|
||||
self.stats_tx
|
||||
.report(PacketStatisticsEvent::RealPacketReceived(
|
||||
fragment_data.len(),
|
||||
fragment_data_size,
|
||||
));
|
||||
|
||||
let fragment = match self.message_receiver.recover_fragment(fragment_data) {
|
||||
@@ -116,15 +123,17 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
|
||||
reply_ciphertext: &mut [u8],
|
||||
reply_key: SurbEncryptionKey,
|
||||
) -> Result<Option<NymMessage>, MessageRecoveryError> {
|
||||
let reply_ciphertext_size = reply_ciphertext.len();
|
||||
// note: this performs decryption IN PLACE without extra allocation
|
||||
self.message_receiver
|
||||
.recover_plaintext_from_reply(reply_ciphertext, reply_key)?;
|
||||
let fragment_data = reply_ciphertext;
|
||||
|
||||
Ok(self.recover_from_fragment(fragment_data))
|
||||
Ok(self.recover_from_fragment(fragment_data, reply_ciphertext_size))
|
||||
}
|
||||
|
||||
fn process_received_regular_packet(&mut self, mut raw_fragment: Vec<u8>) -> Option<NymMessage> {
|
||||
let raw_fragment_size = raw_fragment.len();
|
||||
let fragment_data = match self.message_receiver.recover_plaintext_from_regular_packet(
|
||||
self.local_encryption_keypair.private_key(),
|
||||
&mut raw_fragment,
|
||||
@@ -136,7 +145,7 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
|
||||
Ok(frag_data) => frag_data,
|
||||
};
|
||||
|
||||
self.recover_from_fragment(fragment_data)
|
||||
self.recover_from_fragment(fragment_data, raw_fragment_size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ pub async fn current_gateways<R: Rng>(
|
||||
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
|
||||
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {nym_api}");
|
||||
log::debug!("Fetching list of gateways from: {nym_api}");
|
||||
|
||||
let gateways = client.get_cached_described_gateways().await?;
|
||||
log::debug!("Found {} gateways", gateways.len());
|
||||
|
||||
@@ -178,7 +178,7 @@ impl<T> From<PersistedGatewayDetails<T>> for GatewayDetails<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GatewaySelectionSpecification<T = EmptyCustomDetails> {
|
||||
/// Uniformly choose a random remote gateway.
|
||||
UniformRemote { must_use_tls: bool },
|
||||
|
||||
@@ -354,10 +354,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
msg: Message,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
match self.connection {
|
||||
SocketState::Available(ref mut conn) => {
|
||||
conn.send(msg).await?;
|
||||
Ok(())
|
||||
}
|
||||
SocketState::Available(ref mut conn) => Ok(conn.send(msg).await?),
|
||||
SocketState::PartiallyDelegated(ref mut partially_delegated) => {
|
||||
if let Err(err) = partially_delegated.send_without_response(msg).await {
|
||||
error!("failed to send message without response - {err}...");
|
||||
|
||||
@@ -226,4 +226,8 @@ impl EpochState {
|
||||
pub fn is_final(&self) -> bool {
|
||||
*self == EpochState::InProgress
|
||||
}
|
||||
|
||||
pub fn is_in_progress(&self) -> bool {
|
||||
matches!(self, EpochState::InProgress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ repository.workspace = true
|
||||
cfg-if = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
hex-literal = "0.3.3"
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true, features = ["derive"]}
|
||||
|
||||
@@ -400,11 +400,25 @@ fn fix_deprecated_environmental_variables() {
|
||||
}
|
||||
}
|
||||
|
||||
// Read the variables from the file and log what the corresponding values in the environment are.
|
||||
fn print_env_vars_with_keys_in_file<P: AsRef<Path> + Copy>(config_env_file: P) {
|
||||
let items = dotenvy::from_path_iter(config_env_file)
|
||||
.expect("Invalid path to environment configuration file");
|
||||
for item in items {
|
||||
let (key, val) = item.expect("Invalid item in environment configuration file");
|
||||
log::debug!("{}: {}", key, val);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
|
||||
match std::env::var(var_names::CONFIGURED) {
|
||||
// if the configuration is not already set in the env vars
|
||||
Err(std::env::VarError::NotPresent) => {
|
||||
if let Some(config_env_file) = config_env_file {
|
||||
if let Some(config_env_file) = &config_env_file {
|
||||
log::debug!(
|
||||
"Loading environment variables from {:?}",
|
||||
config_env_file.as_ref()
|
||||
);
|
||||
dotenvy::from_path(config_env_file)
|
||||
.expect("Invalid path to environment configuration file");
|
||||
fix_deprecated_environmental_variables();
|
||||
@@ -412,17 +426,25 @@ pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
|
||||
// if nothing is set, the use mainnet defaults
|
||||
// if the user has not set `CONFIGURED`, then even if they set any of the env variables,
|
||||
// overwrite them
|
||||
log::debug!("Loading mainnet defaults");
|
||||
crate::mainnet::export_to_env();
|
||||
}
|
||||
}
|
||||
Err(_) => crate::mainnet::export_to_env(),
|
||||
Err(_) => {
|
||||
log::debug!("Environment variables already set. Using them");
|
||||
crate::mainnet::export_to_env()
|
||||
}
|
||||
_ => {
|
||||
fix_deprecated_environmental_variables();
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't explicitly defined any of the constants, fallback to defaults
|
||||
crate::mainnet::export_to_env_if_not_set()
|
||||
crate::mainnet::export_to_env_if_not_set();
|
||||
|
||||
if let Some(config_env_file) = &config_env_file {
|
||||
print_env_vars_with_keys_in_file(config_env_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||
|
||||
@@ -239,8 +239,15 @@ impl NymMessage {
|
||||
let (packets_used, space_left) =
|
||||
chunking::number_of_required_fragments(total_required_bytes, plaintext_per_packet);
|
||||
|
||||
let wasted_space = space_left as f32 / (bytes.len() + 1 + space_left) as f32;
|
||||
log::trace!("Padding {self_display}: {} of raw plaintext bytes are required. They're going to be put into {packets_used} sphinx packets with {space_left} bytes of leftover space. {wasted_space}% of packet capacity is going to be wasted.", bytes.len() + 1);
|
||||
let wasted_space_percentage =
|
||||
(space_left as f32 / (bytes.len() + 1 + space_left) as f32) * 100.0;
|
||||
log::trace!(
|
||||
"Padding {self_display}: {} of raw plaintext bytes are required. \
|
||||
They're going to be put into {packets_used} sphinx packets with {space_left} bytes \
|
||||
of leftover space. {wasted_space_percentage:.1}% of packet capacity is going to \
|
||||
be wasted.",
|
||||
bytes.len() + 1
|
||||
);
|
||||
|
||||
bytes
|
||||
.into_iter()
|
||||
|
||||
@@ -4,9 +4,10 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
links = "cpucycles"
|
||||
license = "LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.140"
|
||||
|
||||
[build-dependencies]
|
||||
cfg-if = "1"
|
||||
cfg-if = "1"
|
||||
|
||||
@@ -114,6 +114,7 @@ allow = [
|
||||
"CC0-1.0",
|
||||
"Unicode-DFS-2016",
|
||||
"OpenSSL",
|
||||
"Zlib",
|
||||
]
|
||||
# List of explicitly disallowed licenses
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
|
||||
@@ -52,7 +52,7 @@ minimum_rust_version = "1.66"
|
||||
wallet_release_version = "1.2.8"
|
||||
|
||||
# nym-vpn related variables
|
||||
nym_vpn_latest_binary_url = "https://github.com/nymtech/nym/releases/tag/nym-vpn-alpha-0.0.2"
|
||||
nym_vpn_latest_binary_url = "https://github.com/nymtech/nym/releases/tag/nym-vpn-alpha-0.0.3"
|
||||
nym_vpn_form_url = "https://opnform.com/forms/nymvpn-user-research-at-37c3-yccqko-2"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
|
||||
@@ -9,17 +9,19 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for Debian based Linux
|
||||
2. Open terminal in the same directory and check the the `sha256sum` by running:
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
sha256sum ./nym-vpn-cli_0.1.0_ubuntu-22.04_amd64.zip
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
echo "0e4abb461e86b2c168577e0294112a3bacd3a24bf8565b49783bfebd9b530e23 nym-vpn-cli_0.1.0_ubuntu-22.04_amd64.zip" | shasum -a 256 -c
|
||||
```
|
||||
3. Compare the output with the sha256 hash shared on the [release page]({{nym_vpn_latest_binary_url}})
|
||||
4. Extract files with `unzip` command or manually as you are used to
|
||||
5. Make executable by running:
|
||||
3. Extract files with `unzip` command or manually as you are used to
|
||||
4. Make executable by running:
|
||||
```sh
|
||||
chmod u+x ./nym-vpn-cli
|
||||
```
|
||||
6. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
5. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
```sh
|
||||
curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
```
|
||||
@@ -30,7 +32,7 @@ curl -o sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/env
|
||||
|
||||
Make sure your terminal is open in the same directory as your `nym-vpn-cli` binary.
|
||||
|
||||
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
|
||||
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
|
||||
2. Run it as root with `sudo` - the command will look like this with specified arguments:
|
||||
```sh
|
||||
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
|
||||
@@ -67,7 +69,7 @@ Options:
|
||||
--exit-router-address <EXIT_ROUTER_ADDRESS>
|
||||
Mixnet recipient address
|
||||
--exit-gateway-id <EXIT_GATEWAY_ID>
|
||||
|
||||
|
||||
--exit-router-country <EXIT_ROUTER_COUNTRY>
|
||||
Mixnet recipient address
|
||||
--enable-wireguard
|
||||
@@ -96,7 +98,7 @@ Options:
|
||||
|
||||
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
|
||||
|
||||
**Fundamental commands and arguments**
|
||||
**Fundamental commands and arguments**
|
||||
|
||||
- `-c` is a path to the [Sandbox config](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) file saved as `sandbox.env`
|
||||
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`) from [here](https://nymvpn.com/en/alpha/api/gateways)
|
||||
|
||||
@@ -9,21 +9,19 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
> Any syntax in `<>` brackets is a user's/version unique variable. Exchange with a corresponding name without the `<>` brackets.
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for MacOS
|
||||
2. Open terminal in the same directory and check the the `sha256sum` by running:
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
# x86_64
|
||||
sha256sum ./nym-vpn-cli_0.1.0_macos_x86_64.zip
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# aarch64
|
||||
sha256sum ./nym-vpn-cli_0.1.0_macos_aarch64.zip
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
echo "96623ccc69bc4cc0e4e3e18528b6dae6be69f645d0a592d926a3158ce2d0c269 nym-vpn-cli_0.1.0_macos_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
3. Compare the output with the sha256 hash shared on the [release page]({{nym_vpn_latest_binary_url}})
|
||||
4. Extract files with `unzip` command or manually as you are used to
|
||||
5. Make executable by running:
|
||||
5. Extract files with `unzip` command or manually as you are used to
|
||||
6. Make executable by running:
|
||||
```sh
|
||||
chmod u+x ./nym-vpn-cli
|
||||
```
|
||||
6. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
7. Create Sandbox environment config file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the same directory as your NymVPN binaries by running:
|
||||
```sh
|
||||
curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env" -o sandbox.env
|
||||
```
|
||||
@@ -35,7 +33,7 @@ curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env"
|
||||
Make sure your terminal is open in the same directory as your `nym-vpn-cli` binary.
|
||||
|
||||
|
||||
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
|
||||
1. Go to [nymvpn.com/en/alpha](https://nymvpn.com/en/alpha) to get the entire command with all the needed arguments' values and your wireguard private key for testing purposes
|
||||
2. Run it as root with `sudo` - the command will look like this with specified arguments:
|
||||
```sh
|
||||
sudo ./nym-vpn-cli -c ./sandbox.env --entry-gateway-id <ENTRY_GATEWAY_ID> --exit-router-address <EXIT_ROUTER_ADDRESS> --enable-wireguard --private-key <PRIVATE_KEY> --wg-ip <WIREGUARD_IP>
|
||||
@@ -72,7 +70,7 @@ Options:
|
||||
--exit-router-address <EXIT_ROUTER_ADDRESS>
|
||||
Mixnet recipient address
|
||||
--exit-gateway-id <EXIT_GATEWAY_ID>
|
||||
|
||||
|
||||
--exit-router-country <EXIT_ROUTER_COUNTRY>
|
||||
Mixnet recipient address
|
||||
--enable-wireguard
|
||||
@@ -101,7 +99,7 @@ Options:
|
||||
|
||||
Here is a list of the options and their descriptions. Some are essential, some are more technical and not needed to be adjusted by users.
|
||||
|
||||
**Fundamental commands and arguments**
|
||||
**Fundamental commands and arguments**
|
||||
|
||||
- `-c` is a path to the [Sandbox config](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) file saved as `sandbox.env`
|
||||
- `--entry-gateway-id`: paste one of the values labeled with a key `"identityKey"` (without `" "`) from [here](https://nymvpn.com/en/alpha/api/gateways)
|
||||
|
||||
@@ -12,26 +12,26 @@ Follow the simple [automated script](#automated-script-for-cli-installation) bel
|
||||
|
||||
## Automated Script for CLI Installation
|
||||
|
||||
We wrote a [script](https://gist.github.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/) which does download, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
We wrote a [script](https://gist.github.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af) which does download of the CLI, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
|
||||
1. Download the script and save it as `nym-vpn-client-executor.sh`:
|
||||
1. Open a terminal window in a directory where you want the script and NymVPN CLI binary be downloaded and run
|
||||
```sh
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/99cea8f4d80f2d002802ed1cbedba288bfca4488/execute-nym-vpn-cli-binary.sh
|
||||
curl -o execute-nym-vpn-cli-binary.sh -L https://gist.githubusercontent.com/tommyv1987/87267ded27e1eb7651aa9cc745ddf4af/raw/2a8b703655549f2e515ef1960b5f6dc54adc02fa/execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
|
||||
2. Make the script executable
|
||||
```sh
|
||||
chmod u+x execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
3. Run the script as root, turn of any VPN and run
|
||||
|
||||
3. Start the script as root, turn off any VPN and run
|
||||
```sh
|
||||
sudo ./execute-nym-vpn-cli-binary.sh
|
||||
```
|
||||
4. Verify the `nym-vpn-cli` binary: When prompted to verify `sha256sum` paste your correct one from the [release page]({{nym_vpn_latest_binary_url}}) including the binary name (all as one input with a space in between), for example:
|
||||
```sh
|
||||
# Choose one according to the system you use, this is just an example
|
||||
96623ccc69bc4cc0e4e3e18528b6dae6be69f645d0a592d926a3158ce2d0c269 nym-vpn-cli_0.1.0_macos_x86_64.zip
|
||||
```
|
||||
5. The script will automatically start the client. Follow the instructions:
|
||||
|
||||
4. Follow the prompts in the program
|
||||
|
||||
5. The script will automatically start the client. Make sure to **turn off any other VPNs** and follow the prompts:
|
||||
|
||||
* It prints a JSON view of existing Gateways and prompt you to:
|
||||
- *Make sure to use two different Gateways for entry and exit!*
|
||||
@@ -40,5 +40,7 @@ sudo ./execute-nym-vpn-cli-binary.sh
|
||||
- `do you want five hop or two hop?`: type `five` or `two`
|
||||
- `enable WireGuard? (yes/no):` if you chose yes, find your private key and wireguard IP [here](https://nymvpn.com/en/alpha)
|
||||
|
||||
6. To run `nym-vpn-cli` again, reconnect your wifi and follow the easy steps for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn)
|
||||
To run `nym-vpn-cli` again, reconnect your wifi, move to the directory of your CLI binary `cd ~/nym-vpn-cli-dir` and follow the guide for [Linux](cli-linux.md#run-nymvpn) or [MacOS](cli-mac.md#run-nymvpn). If you find it too difficult, just run this script again - like in step \#3 above.
|
||||
|
||||
In case of errors check out the [troubleshooting](troubleshooting.md) section.
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# NymVPN alpha GUI: Guide for GNU/Linux
|
||||
|
||||
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/908221306?h=404b2bbdc8" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
|
||||
|
||||
```admonish info
|
||||
NymVPN is an experimental software and it's for [testing](./testing.md) purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
|
||||
```
|
||||
@@ -11,38 +13,39 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
### Installation
|
||||
|
||||
1. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for Debian based Linux
|
||||
2. Open terminal in the same directory and check the the `sha256sum` by running:
|
||||
2. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
sha256sum ./nym-vpn-ui_0.0.2_ubuntu-22.04_amd64.zip
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
echo "a5f91f20d587975e30b6a75d3a9e195234cf1269eac278139a5b9c39b039e807 nym-vpn-desktop_0.0.3_ubuntu-22.04_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
3. Compare the output with the sha256 hash shared on the [release page]({{nym_vpn_latest_binary_url}})
|
||||
4. Extract files with `unzip` command or manually as you are used to
|
||||
5. If you prefer to run `.AppImage` make executable by running:
|
||||
3. Extract files with `unzip` command or manually as you are used to
|
||||
4. If you prefer to run `.AppImage` make executable by running:
|
||||
```sh
|
||||
chmod u+x ./appimage/nym-vpn_0.0.2_amd64.AppImage
|
||||
```
|
||||
6. If you prefer to use the `.deb` version for installation (Linux only), open terminal in the same directory and run:
|
||||
5. If you prefer to use the `.deb` version for installation (works on Debian based Linux only), open terminal in the same directory and run:
|
||||
```sh
|
||||
cd deb
|
||||
|
||||
sudo dpkg -i ./nym-vpn_0.0.2_amd64.deb
|
||||
sudo dpkg -i ./nym-vpn_0.0.3_amd64.deb
|
||||
# or
|
||||
sudo apt-get install -f ./nym-vpn_0.0.2_amd64.deb
|
||||
|
||||
sudo apt-get install -f ./nym-vpn_0.0.3_amd64.deb
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
7. Create a NymVPN config directory called `nym-vpn` in your `~/.config`, either manually or by a command:
|
||||
6. Create a NymVPN config directory called `nym-vpn` in your `~/.config`, either manually or by a command:
|
||||
```sh
|
||||
mkdir $HOME/.config/nym-vpn/
|
||||
```
|
||||
8. Create the network config by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the directory `~/.config/nym-vpn/` you just created by running:
|
||||
7. Create the network config by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `sandbox.env` in the directory `~/.config/nym-vpn/` you just created by running:
|
||||
```sh
|
||||
curl -o $HOME/.config/nym-vpn/sandbox.env -L https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env
|
||||
```
|
||||
|
||||
9. Create NymVPN main config file called `config.toml` in the same directory `~/.config/nym-vpn/` with this content:
|
||||
8. Create NymVPN main config file called `config.toml` in the same directory `~/.config/nym-vpn/` with this content:
|
||||
```toml
|
||||
# change <USER> to your username
|
||||
env_config_file = "/home/<USER>/.config/nym-vpn/sandbox.env"
|
||||
@@ -51,7 +54,7 @@ entry_node_location = "DE" # two letters country code
|
||||
# DE, UK, FR, IE
|
||||
```
|
||||
|
||||
## Run NymVPN
|
||||
## Run NymVPN
|
||||
|
||||
**For NymVPN to work, all other VPNs must be switched off!** At this alpha stage of NymVPN, the network connection (wifi) must be reconnected after or in between the testing rounds.
|
||||
|
||||
@@ -68,4 +71,3 @@ sudo -E nym-vpn
|
||||
```
|
||||
|
||||
In case of errors, see [troubleshooting section](troubleshooting.md).
|
||||
|
||||
|
||||
@@ -15,38 +15,35 @@ NymVPN is an experimental software and it's for [testing](./testing.md) purposes
|
||||
mkdir -p "$HOME/nym-vpn-latest"
|
||||
```
|
||||
2. Open Github [releases page]({{nym_vpn_latest_binary_url}}) and download the binary for MacOS
|
||||
3. Open terminal in the same directory and check the the `sha256sum` by running:
|
||||
3. Verify sha hash of your downloaded binary with the one listed on the [releases page]({{nym_vpn_latest_binary_url}}). You can use a simple `shasum` command and compare strings (ie with Python) or run in the same directory the following command, exchanging `<SHA_STRING>` with the one of your binary, like in the example:
|
||||
```sh
|
||||
# aarch64
|
||||
sha256sum ./nym-vpn-ui_0.0.2_macos_aarch64.zip
|
||||
echo "<SHA_STRING>" | shasum -a 256 -c
|
||||
|
||||
# x86_64
|
||||
sha256sum ./nym-vpn-ui_0.0.2_macos_x86_64.zip
|
||||
# choose a correct one according to your binary, this is just an example
|
||||
echo "da4c0bf8e8b52658312d341fa3581954cfcb6efd516d9a448c76d042a454b5df nym-vpn-desktop_0.0.3_macos_x86_64.zip" | shasum -a 256 -c
|
||||
```
|
||||
4. Compare the output with the sha256 hash shared on the [release page]({{nym_vpn_latest_binary_url}})
|
||||
|
||||
5. Extract files with `unzip` command or manually as you are used to
|
||||
6. Move to the application directory and make executable
|
||||
4. Extract files with `unzip` command or manually as you are used to
|
||||
5. Move to the application directory and make executable
|
||||
```sh
|
||||
cd "macos/nym-vpn.app/Contents/MacOS"
|
||||
|
||||
chmod u+x nym-vpn
|
||||
```
|
||||
7. Move `nym-vpn` to your `~/nym-vpn-latest` directory
|
||||
6. Move `nym-vpn` to your `~/nym-vpn-latest` directory
|
||||
```sh
|
||||
mv nym-vpn "$HOME/nym-vpn-latest"
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
8. Create the configuration file by opening a text editor and saving the lines below as `config.toml` in the same directory `~/nym-vpn-latest`
|
||||
7. Create the configuration file by opening a text editor and saving the lines below as `config.toml` in the same directory `~/nym-vpn-latest`
|
||||
```toml
|
||||
env_config_file = ".env"
|
||||
entry_node_location = "DE" # two letters country code
|
||||
# You can choose different entry by entering one of the following two letter country codes:
|
||||
# DE, UK, FR, IE
|
||||
```
|
||||
9. Create testnet configuration file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `.env` in the same directory `~/nym-vpn-latest`
|
||||
8. Create testnet configuration file by saving [this](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) as `.env` in the same directory `~/nym-vpn-latest`
|
||||
```sh
|
||||
curl -L "https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env" -o "$HOME/nym-vpn-latest/.env"
|
||||
```
|
||||
@@ -60,5 +57,3 @@ sudo ./nym-vpn
|
||||
```
|
||||
|
||||
In case of errors check out the [troubleshooting](troubleshooting.html#installing-gui-on-macos-not-working) section.
|
||||
|
||||
|
||||
|
||||
@@ -6,37 +6,35 @@ Our alpha testing round is done with participants at live workshop events. This
|
||||
**If you commit to test NymVPN alpha, please start with the [user research form]({{nym_vpn_form_url}}) where all the steps will be provided**. If you disagree with any of the conditions listed, please leave this page.
|
||||
```
|
||||
|
||||
This is the alpha version of NymVPN application - the GUI. A demo of how the client will look like for majority of day-to-day users. For qualitative testing the [CLI](cli.md) is a necessity but to run the GUI holds the same importance as it provides the user with an experience of the actual app and the developers with a valuable feedback from the users.
|
||||
This is the alpha version of NymVPN application - the GUI. A demo of how the client will look like for majority of day-to-day users. For qualitative testing the [CLI](cli.md) is a necessity but to run the GUI holds the same importance as it provides the user with an experience of the actual app and the developers with a valuable feedback from the users.
|
||||
|
||||
Follow the simple [automated script](#automated-script-for-gui-installation) below to install and run NymVPN GUI. If you prefer to do a manual setup follow the steps in the guide for [Linux](gui-linux.md) or [MacOS](gui-mac.md).
|
||||
|
||||
## Automated Script for GUI Installation
|
||||
|
||||
We wrote a [script](https://gist.github.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19) which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
We wrote a [script](https://gist.github.com/serinko/e0a9f7ff3d79e974ec6f6783caa1137e) which does download of dependencies and the application, sha256 verification, extraction, installation and configuration for Linux and MacOS users automatically following the steps below:
|
||||
|
||||
1. To download the script, open a terminal in a directory where you want to download the script and run:
|
||||
1. Open a terminal window in a directory where you want the script and NymVPN binary be downloaded and run
|
||||
```sh
|
||||
curl -o nym-vpn-client-installer.sh -L https://gist.githubusercontent.com/tommyv1987/7d210d4daa8f7abc61f9a696d0321f19/raw/181968941ce268a3937e82239ddfd293dd96bb60/nym-vpn-client-installer.sh
|
||||
curl -o nym-vpn-desktop-install-run.sh -L https://gist.githubusercontent.com/serinko/e0a9f7ff3d79e974ec6f6783caa1137e/raw/064c0d42af6a187b4f62998a0c2e6a84c319eeef/nym-vpn-desktop-install-run.sh
|
||||
```
|
||||
|
||||
2. Make the script executable
|
||||
```sh
|
||||
chmod u+x nym-vpn-client-installer.sh
|
||||
chmod u+x nym-vpn-desktop-install-run.sh
|
||||
```
|
||||
3. Run the script as root, turn off any VPN and run
|
||||
```sh
|
||||
sudo ./nym-vpn-client-installer.sh
|
||||
```
|
||||
4. Verify the `nym-vpn` binary: When prompted to verify `sha256sum` paste your correct one from the [release page]({{nym_vpn_latest_binary_url}}) including the binary name (all as one input with a space in between), for example:
|
||||
```sh
|
||||
# Choose one according to the system you use, this is just an example
|
||||
06c7c82f032f230187da1002a9a9a88242d3bbf6c5c09dc961a71df151d768d0 nym-vpn-ui_0.0.2_macos_x86_64.zip
|
||||
```
|
||||
5. The script will run the application and it will prompt you for a country code to exit, chose one of the offered options in the same format as listed
|
||||
|
||||
6. To start the application again, reconnect your wifi and run
|
||||
3. Start the script as root, turn off any VPN and run
|
||||
```sh
|
||||
sudo -E ./nym-vpn-desktop-install-run.sh
|
||||
```
|
||||
|
||||
4. Follow the prompts in the program
|
||||
|
||||
To start the application again, reconnect your wifi and run
|
||||
```sh
|
||||
# Linux
|
||||
sudo -E ~/nym-vpn-latest/nym-vpn_0.0.2_amd64.AppImage
|
||||
sudo -E ~/nym-vpn-latest/nym-vpn_0.0.3_amd64.AppImage
|
||||
|
||||
# MacOS
|
||||
sudo $nym_vpn_dir/nym-vpn
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/897010658?h=1f55870fe6&badge=0&autopause=0&player_id=0&app_id=58479" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="NYMVPN alpha demo 37C3"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
|
||||
|
||||
**Nym proudly presents NymVPN Alpha** - a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
|
||||
**Nym proudly presents NymVPN alpha** - a client that uses [Nym Mixnet](https://nymtech.net) to anonymise all of a user's internet traffic through either a 5-hop mixnet (for a full network privacy) or the faster 2-hop decentralised VPN (with some extra features).
|
||||
|
||||
|
||||
**You are invited to take part in the alpha testing** of this new application. The following pages provide a how-to guide, explaining steps to install and run NymVPN [CLI](cli.md) and [GUI](gui.md) on the Sandbox testnet environment as well as provide some scripts for [qualitative testing](testing.md).
|
||||
@@ -17,9 +17,9 @@
|
||||
6. Fill and submit the [form!]({{nym_vpn_form_url}})
|
||||
7. Join the [NymVPN matrix channel](https://matrix.to/#/#NymVPN:nymtech.chat) if you have any questions, comments or blockers
|
||||
|
||||
***NymVPN Alpha testing will last from 15th of January - 15th of February.***
|
||||
***NymVPN alpha testing will last from 15th of January - 15th of February.***
|
||||
|
||||
*NOTE: NymVPN Alpha is experimental software for [testing purposes](testing.md) only.*
|
||||
*NOTE: NymVPN alpha is experimental software for [testing purposes](testing.md) only.*
|
||||
|
||||
|
||||
## NymVPN Overview
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Testing NymVPN alpha
|
||||
|
||||
<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/908640440?h=0f7f6dfa53" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
|
||||
|
||||
```admonish info
|
||||
NymVPN is an experimental software and it's for [testing](./testing.md) purposes only. All users testing the client are expected to sign GDPR Information Sheet and Consent Form (shared at the workshop) so we use their results to improve the client, and submit the form [*NymVPN User research*]({{nym_vpn_form_url}}) with the testing results.
|
||||
```
|
||||
@@ -15,11 +17,11 @@ One of the main aims of NymVPN alpha release is testing; your results will help
|
||||
1. Create a directory called `nym-vpn-tests` and copy your `nym-vpn-cli` binary ([download here]({{nym_vpn_latest_binary_url}})) and [`sandbox.env`](https://raw.githubusercontent.com/nymtech/nym/develop/envs/sandbox.env) to that directory
|
||||
2. Copy the [block below](#testssh) and save it as `tests.sh` to the same folder
|
||||
3. Open terminal in the same directory
|
||||
4. Turn off any existing VPN's (including the NymVPN instances), reconnect your wifi and make the script executable by running
|
||||
4. Turn off any existing VPN's (including the NymVPN instances), reconnect your wifi and make the script executable by running
|
||||
```sh
|
||||
chmod u+x ./tests.sh
|
||||
```
|
||||
5. Run the `tests.sh` script:
|
||||
5. Run the `tests.sh` script:
|
||||
```sh
|
||||
sudo ./tests.sh
|
||||
````
|
||||
|
||||
@@ -58,7 +58,7 @@ When running `sudo sh ./test.sh` you may see an error like: `93: current_time: n
|
||||
|
||||
In case the automatic download of all the Gateways fail (and it shouldn't), you do an easy manual work around:
|
||||
|
||||
1. Open the list of Gateways created by API [here](https://nymvpn.com/en/ccc/api/gateways)
|
||||
1. Open the list of Gateways created by API [here](https://nymvpn.com/en/alpha/api/gateways)
|
||||
2. On top click on `JSON` option (shall be default view) and `Save`
|
||||
3. Save it as `data.json` to the `nym-vpn-tests` folder
|
||||
4. Replace line 3 in the [script `tests.sh`](testing.md#testssh) with:
|
||||
|
||||
@@ -32,10 +32,14 @@
|
||||
# Legal Forum
|
||||
|
||||
- [Exit Gateway](legal/exit-gateway.md)
|
||||
- [Switzerland](legal/swiss.md)
|
||||
- [United States](legal/united-states.md)
|
||||
- [Community Counsel](legal/community-counsel.md)
|
||||
- [Jurisdictions](legal/jurisdictions.md)
|
||||
- [Switzerland](legal/swiss.md)
|
||||
- [United States](legal/united-states.md)
|
||||
- [Landing Pages](legal/landing-pages.md)
|
||||
- [How to Add Info](legal/add-content.md)
|
||||
|
||||
---
|
||||
---
|
||||
# Misc.
|
||||
- [Code of Conduct](coc.md)
|
||||
- [Licensing](licensing.md)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Adding Content to Legal Forum
|
||||
|
||||
Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in, to share solutions to the challenges they encountered when running Exit Gateway, and create a pull request (PR).
|
||||
|
||||
First of all, please join our [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) and post any information or questions there.
|
||||
|
||||
To add your information to this book, you can create a PR directly to our [repository](https://github.com/nymtech/nym/tree/develop/documentation/operators/src/legal).
|
||||
|
||||
**Steps to make a pull request:**
|
||||
|
||||
1. Write down your legal findings, suggestions, communication templates, FAQ in a text editor
|
||||
|
||||
2. Clone `nymtech/nym` repository or pull in case you already have it and switch to `develop` branch
|
||||
|
||||
```sh
|
||||
# clone the repository
|
||||
git clone https://github.com/nymtech/nym
|
||||
|
||||
# go to the directory nym
|
||||
cd nym
|
||||
|
||||
# switch to branch develop
|
||||
git checkout develop
|
||||
|
||||
# update the repository
|
||||
git pull origin develop
|
||||
```
|
||||
|
||||
3. Make your own branch based off `develop` and switch to it
|
||||
|
||||
```sh
|
||||
# choose a descriptive and consise name without using <>
|
||||
git checkout -b operators/legal-forum/<MY_BRANCH_NAME>
|
||||
|
||||
# example: git checkout -b operators/legal-forum/alice-vps-faq-template
|
||||
|
||||
# you can double check that you are on the right branch
|
||||
git branch
|
||||
```
|
||||
|
||||
4. Save your legal findings as `<JURISDICTION_NAME>.md` to `/nym/documentation/operators/src/legal` or add info to an existing page
|
||||
|
||||
5. **Don't change anything in `SUMMARY.md`**, the admins will do it when merging
|
||||
|
||||
6. Add, commit and push your changes
|
||||
|
||||
```sh
|
||||
cd documentation/operators/src/legal
|
||||
git add <FILE_NAME>.md
|
||||
git commit -am "<DESCRIBE YOUR CHANGES>"
|
||||
git push origin operators/legal-forum/<MY_BRANCH_NAME>
|
||||
```
|
||||
7. Open the git generated link in your browser, fill the description and click on `Create a Pull Request` button
|
||||
```sh
|
||||
# the url will look like this
|
||||
https://github.com/nymtech/nym/pull/new/operators/legal-forum/<MY_BRANCH_NAME>
|
||||
```
|
||||
8. Notify others in the [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) about the PR.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Community Counsel
|
||||
|
||||
```admonish info
|
||||
The entire content of this page is under [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/).
|
||||
```
|
||||
|
||||
Running an Exit Gateway is a commitment and as such is exposed to various challenges. Besides different legal regulations typical difficulties may be dealing with VPS or ISP providers. Our strength lies in decentralised community of squads and individuals supporting each other. Sharing examples of [landing pages](landing-pages.md), templates for communication and FAQs is a great way to empower other operators sharing the mission of liberating internet. Below is a simple way how to create a pull request directly to Nym Operator Guide book.
|
||||
|
||||
## How to add content
|
||||
|
||||
Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in as well as solutions to any challenges when running an Exit Gateway and add those through a pull request (PR). Please check out the [steps to make a pull request](add-content.md).
|
||||
@@ -127,67 +127,14 @@ Useful links:
|
||||
- [github.com/coldhakca/abuse-templates/blob/master/dmca.template](https://github.com/coldhakca/abuse-templates/blob/master/dmca.template)
|
||||
|
||||
|
||||
## Legal environment - Findings from our legal team
|
||||
## Legal environment of Nym Exit Gateway
|
||||
|
||||
The Node Operators Legal Forum pages are divided into pages according the region:
|
||||
The Node Operators Legal Forum pages are divided according [jurisdictions](jurisdictions.md). Read below to learn [how to add](add-content.md) findings about your jurisdiction or edit existing info.
|
||||
|
||||
- [Switzerland](./swiss.md)
|
||||
- [United States](./united-states.md)
|
||||
## Community Counsel
|
||||
|
||||
See the next chapter to learn how to edit information or add findings about your jurisdiction.
|
||||
|
||||
## How to edit or add legal information
|
||||
|
||||
Our aim is to establish a strong community network, sharing legal findings with each other. We would like to encourage all the current and future operators to do research about the situation in the jurisdiction they operate and update this page.
|
||||
|
||||
First of all, please join our [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat) and post any information or questions there.
|
||||
|
||||
To add your information to this book, you can create a pull request directly to our [repository](https://github.com/nymtech/nym/tree/develop/documentation/operators/src), than ping the admins in the [Legal Forum chat](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) and we will review it as fast as possible.
|
||||
|
||||
To do so, follow the steps below:
|
||||
|
||||
1. Write your legal findings down in a text editor (Soon we will share a template)
|
||||
2. Clone `nymtech/nym` repository and switch to develop branch
|
||||
|
||||
```sh
|
||||
# Clone the repository
|
||||
git clone https://github.com/nymtech/nym
|
||||
|
||||
# Go to the directory nym
|
||||
cd nym
|
||||
|
||||
# Switch to branch develop
|
||||
git checkout develop
|
||||
|
||||
# Update the repository
|
||||
git pull origin develop
|
||||
```
|
||||
|
||||
3. Make your own branch based off `develop` and switch to it
|
||||
|
||||
```sh
|
||||
git branch operators/legal-forum/<MY_BRANCH_NAME> # choose a descriptive and consiose name without using <>
|
||||
git checkout operators/legal-forum/<MY_BRANCH_NAME>
|
||||
|
||||
# you can double check that you are on the right branch
|
||||
git branch
|
||||
```
|
||||
|
||||
4. Save your legal findings as `<FILE_NAME>.md` to `/nym/documentation/operators/src/legal`
|
||||
5. Don't change anything in `SUMMARY.md`, the admins will do it when merging
|
||||
6. Add, commit and push your changes
|
||||
|
||||
```sh
|
||||
cd documentation/operators/src/legal
|
||||
git add <FILE_NAME>.md
|
||||
git commit -am "<describe your changes>"
|
||||
git push origin operators/legal-forum/<MY_BRANCH_NAME>
|
||||
```
|
||||
7. Open the git generated link in your browser, fill the description and click on `Create a Pull Request` button
|
||||
```sh
|
||||
# The link will look like this
|
||||
https://github.com/nymtech/nym/pull/new/<MY_BRANCH_NAME>
|
||||
```
|
||||
8. Notify others in the [Node Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) (Matrix chat)
|
||||
Nym Node operators are invited to add their legal findings or helpful suggestions directly through [pull requests](add-content.md). This can be done as a new legal information (or entire new country) to the list of [jurisdictions](jurisdictions.md) or in a form of an advice to [Community counsel pages](community-counsel.md), sharing examples of Exit Gateway [landing pages](landing-pages.md), templates etcetra.
|
||||
|
||||
## How to add content
|
||||
|
||||
Our aim is to establish a strong community network, sharing legal findings and other suggestions with each other. We would like to encourage all of the current and future operators to do research about the situation in the jurisdiction they operate in as well as solutions to any challenges when running an Exit Gateway and add those through a pull request (PR). Please check out the [steps to make a pull request](add-content.md).
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Exit Gateway - Jurisdictions
|
||||
|
||||
```admonish info
|
||||
The entire content of this page is under [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/).
|
||||
```
|
||||
|
||||
```admonish warning
|
||||
The following part is for informational purposes only. Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the [Node Operator](https://matrix.to/#/#operators:nymtech.chat) and [Operators Legal Forum](https://matrix.to/#/!YfoUFsJjsXbWmijbPG:nymtech.chat?via=nymtech.chat&via=matrix.org) channels on Element to share best practices and experiences.
|
||||
```
|
||||
|
||||
There is no one silver bullet covering the entire globe. Every jurisdiction has different set of laws and practices regarding internet traffic routing. Therefore the Node Operators Legal Forum pages are divided per region.
|
||||
|
||||
These are some findings from our legal team as an example:
|
||||
|
||||
- [Switzerland](swiss.md)
|
||||
- [United States](united-states.md)
|
||||
|
||||
> Nym Node operators are invited to add their legal findings directly through [pull requests](add-content.md).
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Landing Pages
|
||||
|
||||
```admonish info
|
||||
The entire content of this page is under [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/).
|
||||
```
|
||||
|
||||
> Nym Node operators are invited to add their legal findings and suggestions directly through [pull requests](add-content.md).
|
||||
|
||||
Exit Gateway landing page is a great and transparent way to prevent possible troubles by providing people with basic facts, links to laws and regulations on a given topic as well as operator's contact info. To inspire each other we share some examples how Nym community handled this issue below.
|
||||
@@ -132,7 +132,7 @@ Save, exit and restart your Gateway. Now you are an operator of post-smooshed Ex
|
||||
|
||||
In case you already added Network Requester functionality to your Gateway as described above but haven't enabled the [exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) there is an easy tweak to do so and turn your node into [Nym Exit Gateway](../faq/smoosh-faq.md#what-are-the-changes).
|
||||
|
||||
Open the config file stored at `.nym/gateways/<ID>/config/network_requester_config.tom` and set:
|
||||
Open the config file stored at `.nym/gateways/<ID>/config/network_requester_config.toml` and set:
|
||||
```sh
|
||||
use_deprecated_allow_list = false
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "ephemera"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "ephemera"
|
||||
|
||||
@@ -16,15 +16,15 @@ itertools = "0.10.3"
|
||||
lazy_static = "1.4.0"
|
||||
log = { workspace = true }
|
||||
maxminddb = "0.23.0"
|
||||
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
|
||||
okapi = { version = "0.7.0", features = ["impl_json_schema"] }
|
||||
pretty_env_logger = "0.4.0"
|
||||
rand = "0.8.5"
|
||||
rand_pcg = "0.3.1"
|
||||
rand_seeder = "0.2.3"
|
||||
reqwest = { workspace = true }
|
||||
rocket = { version = "0.5.0-rc.2", features = ["json"] }
|
||||
rocket_cors = { git="https://github.com/lawliet89/rocket_cors", rev="dfd3662c49e2f6fc37df35091cb94d82f7fb5915" }
|
||||
rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger"] }
|
||||
rocket = { version = "0.5.0", features = ["json"] }
|
||||
rocket_cors = { version = "0.6.0" }
|
||||
rocket_okapi = { version = "0.8.0", features = ["swagger"] }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::country_statistics::country_nodes_distribution::CountryNodesDistribution;
|
||||
use crate::state::ExplorerApiStateContext;
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use nym_explorer_api_requests::PrettyDetailedGatewayBond;
|
||||
use rocket::response::status::NotFound;
|
||||
use rocket::serde::json::Json;
|
||||
|
||||
@@ -60,7 +60,7 @@ impl<'r> FromRequest<'r> for Location {
|
||||
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
match find_location(request) {
|
||||
Ok(loc) => Outcome::Success(loc),
|
||||
Err(e) => Outcome::Failure(e),
|
||||
Err(e) => Outcome::Error(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::mix_node::delegations::{
|
||||
get_single_mixnode_delegations, get_single_mixnode_delegations_summed,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::mix_nodes::models::{MixNodeActiveSetSummary, MixNodeSummary};
|
||||
use crate::state::ExplorerApiStateContext;
|
||||
use nym_explorer_api_requests::{MixnodeStatus, PrettyDetailedMixNodeBond};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{Route, State};
|
||||
use rocket_okapi::okapi::openapi3::OpenApi;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use nym_mixnet_contract_common::{MixId, MixNode};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{Route, State};
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::service_providers::models::{
|
||||
DirectoryService, DirectorySpDetailed, HarbourMasterService, PagedResult,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use rocket::response::status::NotFound;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{Route, State};
|
||||
|
||||
+2
-2
@@ -27,8 +27,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
## Install debian
|
||||
|
||||
```bash
|
||||
sudo curl -s --compressed "https://nymtech.github.io/nym/nymtech.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg] https://nymtech.github.io/nym/ /" > nymtech.list
|
||||
sudo curl -s --compressed "http://apt.nymtech.net.s3-website.eu-central-1.amazonaws.com/nymtech.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg] http://apt.nymtech.net.s3-website.eu-central-1.amazonaws.com/ squeeze main" > /etc/apt/sources.list.d/nymtech.list
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install nym-gateway
|
||||
|
||||
@@ -240,6 +240,7 @@ pub(crate) fn override_network_requester_config(
|
||||
)
|
||||
}
|
||||
|
||||
// NOTE: make sure this is in sync with service-providers/ip-packet-router/src/cli/mod.rs::override_config
|
||||
pub(crate) fn override_ip_packet_router_config(
|
||||
mut cfg: nym_ip_packet_router::Config,
|
||||
opts: Option<OverrideIpPacketRouterConfig>,
|
||||
|
||||
@@ -229,26 +229,11 @@ where
|
||||
iv,
|
||||
)?;
|
||||
|
||||
// Get the latest coconut signers and their VK
|
||||
let credential_api_clients = self
|
||||
let aggregated_verification_key = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.all_coconut_api_clients(*credential.epoch_id())
|
||||
.verification_key(*credential.epoch_id())
|
||||
.await?;
|
||||
let current_api_clients = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.all_current_coconut_api_clients()
|
||||
.await?;
|
||||
if credential_api_clients.is_empty() || current_api_clients.is_empty() {
|
||||
return Err(RequestHandlingError::NotEnoughNymAPIs {
|
||||
received: 0,
|
||||
needed: 1,
|
||||
});
|
||||
}
|
||||
|
||||
let aggregated_verification_key =
|
||||
nym_credentials::obtain_aggregate_verification_key(&credential_api_clients).await?;
|
||||
|
||||
if !credential.verify(&aggregated_verification_key) {
|
||||
return Err(RequestHandlingError::InvalidBandwidthCredential(
|
||||
@@ -256,9 +241,15 @@ where
|
||||
));
|
||||
}
|
||||
|
||||
let api_clients = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.api_clients(*credential.epoch_id())
|
||||
.await?;
|
||||
|
||||
self.inner
|
||||
.coconut_verifier
|
||||
.release_funds(current_api_clients, &credential)
|
||||
.release_funds(&api_clients, &credential)
|
||||
.await?;
|
||||
|
||||
let bandwidth = Bandwidth::from(credential);
|
||||
|
||||
@@ -1,57 +1,150 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2022-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use super::authenticated::RequestHandlingError;
|
||||
use log::*;
|
||||
use nym_coconut_interface::Credential;
|
||||
use nym_coconut_interface::{Credential, VerificationKey};
|
||||
use nym_validator_client::coconut::all_coconut_api_clients;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
use nym_validator_client::nyxd::contract_traits::MultisigQueryClient;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use nym_validator_client::{
|
||||
nyxd::{
|
||||
contract_traits::{
|
||||
CoconutBandwidthSigningClient, DkgQueryClient, MultisigQueryClient,
|
||||
MultisigSigningClient,
|
||||
},
|
||||
contract_traits::{CoconutBandwidthSigningClient, DkgQueryClient, MultisigSigningClient},
|
||||
cosmwasm_client::logs::{find_attribute, BANDWIDTH_PROPOSAL_ID},
|
||||
Coin,
|
||||
},
|
||||
CoconutApiClient, DirectSigningHttpRpcNyxdClient,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
pub(crate) struct CoconutVerifier {
|
||||
address: AccountId,
|
||||
nyxd_client: RwLock<DirectSigningHttpRpcNyxdClient>,
|
||||
|
||||
// **CURRENTLY** api client addresses don't change during the epochs
|
||||
api_clients: RwLock<HashMap<EpochId, Vec<CoconutApiClient>>>,
|
||||
|
||||
// keys never change during epochs
|
||||
master_keys: RwLock<HashMap<EpochId, VerificationKey>>,
|
||||
mix_denom_base: String,
|
||||
}
|
||||
|
||||
impl CoconutVerifier {
|
||||
pub async fn new(nyxd_client: DirectSigningHttpRpcNyxdClient) -> Self {
|
||||
pub async fn new(
|
||||
nyxd_client: DirectSigningHttpRpcNyxdClient,
|
||||
) -> Result<Self, RequestHandlingError> {
|
||||
let mix_denom_base = nyxd_client.current_chain_details().mix_denom.base.clone();
|
||||
let address = nyxd_client.address();
|
||||
|
||||
CoconutVerifier {
|
||||
let mut master_keys = HashMap::new();
|
||||
let mut api_clients = HashMap::new();
|
||||
|
||||
// might as well obtain the key for the current epoch, if applicable
|
||||
let current_epoch = nyxd_client.get_current_epoch().await?;
|
||||
if current_epoch.state.is_in_progress() {
|
||||
// note: even though we're constructing clients here, we will NOT be making any network requests
|
||||
let epoch_api_clients =
|
||||
all_coconut_api_clients(&nyxd_client, current_epoch.epoch_id).await?;
|
||||
let threshold = nyxd_client.get_current_epoch_threshold().await?;
|
||||
|
||||
// SAFETY:
|
||||
// if epoch state is in the 'in progress' state, it means the threshold value MUST HAVE
|
||||
// been established. if it wasn't, there's an underlying issue with the DKG contract in which
|
||||
// case we shouldn't continue anyway because here be dragons
|
||||
#[allow(clippy::expect_used)]
|
||||
let threshold = threshold.expect("unavailable threshold value") as usize;
|
||||
if epoch_api_clients.len() < threshold {
|
||||
return Err(RequestHandlingError::NotEnoughNymAPIs {
|
||||
received: epoch_api_clients.len(),
|
||||
needed: threshold,
|
||||
});
|
||||
}
|
||||
let aggregated_verification_key =
|
||||
nym_credentials::obtain_aggregate_verification_key(&epoch_api_clients).await?;
|
||||
|
||||
api_clients.insert(current_epoch.epoch_id, epoch_api_clients);
|
||||
master_keys.insert(current_epoch.epoch_id, aggregated_verification_key);
|
||||
}
|
||||
|
||||
Ok(CoconutVerifier {
|
||||
address,
|
||||
nyxd_client: RwLock::new(nyxd_client),
|
||||
api_clients: RwLock::new(api_clients),
|
||||
master_keys: RwLock::new(master_keys),
|
||||
mix_denom_base,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn all_current_coconut_api_clients(
|
||||
pub async fn api_clients(
|
||||
&self,
|
||||
) -> Result<Vec<CoconutApiClient>, RequestHandlingError> {
|
||||
let epoch_id = self
|
||||
.nyxd_client
|
||||
.read()
|
||||
.await
|
||||
.get_current_epoch()
|
||||
.await?
|
||||
.epoch_id;
|
||||
self.all_coconut_api_clients(epoch_id).await
|
||||
epoch_id: EpochId,
|
||||
) -> Result<RwLockReadGuard<Vec<CoconutApiClient>>, RequestHandlingError> {
|
||||
let guard = self.api_clients.read().await;
|
||||
|
||||
// the key was already in the map
|
||||
if let Ok(mapped) = RwLockReadGuard::try_map(guard, |clients| clients.get(&epoch_id)) {
|
||||
return Ok(mapped);
|
||||
}
|
||||
|
||||
let api_clients = self.query_api_clients(epoch_id).await?;
|
||||
|
||||
// EDGE CASE:
|
||||
// if this epoch is from the past, we can't query for its threshold
|
||||
// we can only hope that enough valid keys were submitted
|
||||
// the best we can do is check if we have at least a api
|
||||
if api_clients.is_empty() {
|
||||
return Err(RequestHandlingError::NotEnoughNymAPIs {
|
||||
received: 0,
|
||||
needed: 1,
|
||||
});
|
||||
}
|
||||
|
||||
let mut guard = self.api_clients.write().await;
|
||||
guard.insert(epoch_id, api_clients);
|
||||
let guard = guard.downgrade();
|
||||
|
||||
// SAFETY:
|
||||
// we just inserted the entry into the map while NEVER dropping the lock (only downgraded it)
|
||||
// so it MUST exist and thus the unwrap is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Ok(RwLockReadGuard::map(guard, |clients| {
|
||||
clients.get(&epoch_id).unwrap()
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn all_coconut_api_clients(
|
||||
pub async fn verification_key(
|
||||
&self,
|
||||
epoch_id: EpochId,
|
||||
) -> Result<RwLockReadGuard<VerificationKey>, RequestHandlingError> {
|
||||
let guard = self.master_keys.read().await;
|
||||
|
||||
// the key was already in the map
|
||||
if let Ok(mapped) = RwLockReadGuard::try_map(guard, |keys| keys.get(&epoch_id)) {
|
||||
return Ok(mapped);
|
||||
}
|
||||
|
||||
let api_clients = self.api_clients(epoch_id).await?;
|
||||
|
||||
let aggregated_verification_key =
|
||||
nym_credentials::obtain_aggregate_verification_key(&api_clients).await?;
|
||||
|
||||
let mut guard = self.master_keys.write().await;
|
||||
guard.insert(epoch_id, aggregated_verification_key);
|
||||
let guard = guard.downgrade();
|
||||
|
||||
// SAFETY:
|
||||
// we just inserted the entry into the map while NEVER dropping the lock (only downgraded it)
|
||||
// so it MUST exist and thus the unwrap is fine
|
||||
#[allow(clippy::unwrap_used)]
|
||||
Ok(RwLockReadGuard::map(guard, |keys| {
|
||||
keys.get(&epoch_id).unwrap()
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn query_api_clients(
|
||||
&self,
|
||||
epoch_id: u64,
|
||||
) -> Result<Vec<CoconutApiClient>, RequestHandlingError> {
|
||||
@@ -60,7 +153,7 @@ impl CoconutVerifier {
|
||||
|
||||
pub async fn release_funds(
|
||||
&self,
|
||||
api_clients: Vec<CoconutApiClient>,
|
||||
api_clients: &[CoconutApiClient],
|
||||
credential: &Credential,
|
||||
) -> Result<(), RequestHandlingError> {
|
||||
let res = self
|
||||
|
||||
@@ -457,7 +457,7 @@ impl<St> Gateway<St> {
|
||||
let coconut_verifier = {
|
||||
let nyxd_client = self.random_nyxd_client()?;
|
||||
CoconutVerifier::new(nyxd_client).await
|
||||
};
|
||||
}?;
|
||||
|
||||
let mix_forwarding_channel =
|
||||
self.start_packet_forwarder(shutdown.subscribe().named("PacketForwarder"));
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "nym-bity-integration"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ By default, the Nym Mixnode will start on port 1789. If desired, you can change
|
||||
## Install debian
|
||||
|
||||
```bash
|
||||
sudo curl -s --compressed "https://nymtech.github.io/nym/nymtech.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg] https://nymtech.github.io/nym/ /" > nymtech.list
|
||||
sudo curl -s --compressed "http://apt.nymtech.net.s3-website.eu-central-1.amazonaws.com/nymtech.gpg" | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg] http://apt.nymtech.net.s3-website.eu-central-1.amazonaws.com/ squeeze main" > /etc/apt/sources.list.d/nymtech.list
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install nym-mixnode
|
||||
|
||||
+4
-4
@@ -32,8 +32,8 @@ pin-project = "1.0"
|
||||
rand = "0.8.5"
|
||||
rand-07 = { package = "rand", version = "0.7.3" } # required for compatibility
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
rocket = { version = "0.5.0-rc.2", features = ["json"] }
|
||||
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "dfd3662c49e2f6fc37df35091cb94d82f7fb5915" }
|
||||
rocket = { version = "0.5.0", features = ["json"] }
|
||||
rocket_cors = { version = "0.6.0" }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tap = "1.0"
|
||||
@@ -60,8 +60,8 @@ sqlx = { workspace = true, features = [
|
||||
"migrate",
|
||||
] }
|
||||
|
||||
okapi = { version = "0.7.0-rc.1", features = ["impl_json_schema"] }
|
||||
rocket_okapi = { version = "0.8.0-rc.2", features = ["swagger"] }
|
||||
okapi = { version = "0.7.0", features = ["impl_json_schema"] }
|
||||
rocket_okapi = { version = "0.8.0", features = ["swagger"] }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
|
||||
use crate::node_status_api::models::ErrorResponse;
|
||||
use nym_api_requests::models::CirculatingSupplyResponse;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::coconut::api_routes::helpers::build_credentials_response;
|
||||
use crate::coconut::error::{CoconutError, Result};
|
||||
use crate::coconut::helpers::{accepted_vote_err, blind_sign};
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::network::models::{ContractInformation, NetworkDetails};
|
||||
use crate::nym_contract_cache::cache::NymContractCache;
|
||||
use nym_contracts_common::ContractBuildInformation;
|
||||
|
||||
@@ -36,7 +36,7 @@ impl<'r> FromRequest<'r> for LocalRequest {
|
||||
"Received a request from {:?} for a local-only route",
|
||||
request.client_ip()
|
||||
);
|
||||
Outcome::Failure((Status::Unauthorized, NonLocalRequestError))
|
||||
Outcome::Error((Status::Unauthorized, NonLocalRequestError))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use super::helpers::_get_gateways_detailed;
|
||||
use super::NodeStatusCache;
|
||||
use crate::node_status_api::helpers::{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::{
|
||||
node_status_api::{
|
||||
helpers::{_get_active_set_detailed, _get_mixnodes_detailed, _get_rewarded_set_detailed},
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// due to the macro expansion of rather old rocket macros...
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use crate::node_describe_cache::DescribedNodes;
|
||||
use crate::nym_contract_cache::cache::NymContractCache;
|
||||
use crate::support::caching::cache::SharedCache;
|
||||
|
||||
@@ -6,7 +6,7 @@ repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license = "GPL-3"
|
||||
license = "GPL-3.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ CREATE TABLE block_signing_reward
|
||||
rewarding_epoch_id INTEGER NOT NULL REFERENCES rewarding_epoch (id),
|
||||
validator_consensus_address TEXT NOT NULL,
|
||||
operator_account TEXT NOT NULL,
|
||||
whitelisted BOOLEAN NOT NULL,
|
||||
amount TEXT NOT NULL,
|
||||
voting_power BIGINT NOT NULL,
|
||||
voting_power_share TEXT NOT NULL,
|
||||
@@ -38,11 +39,11 @@ CREATE TABLE block_signing_reward
|
||||
|
||||
CREATE TABLE epoch_credential_issuance
|
||||
(
|
||||
rewarding_epoch_id INTEGER NOT NULL PRIMARY KEY REFERENCES rewarding_epoch (id),
|
||||
starting_dkg_epoch INTEGER NOT NULL,
|
||||
ending_dkg_epoch INTEGER NOT NULL,
|
||||
rewarding_epoch_id INTEGER NOT NULL PRIMARY KEY REFERENCES rewarding_epoch (id),
|
||||
starting_dkg_epoch INTEGER NOT NULL,
|
||||
ending_dkg_epoch INTEGER NOT NULL,
|
||||
total_issued_partial_credentials INTEGER NOT NULL,
|
||||
budget TEXT NOT NULL
|
||||
budget TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE malformed_credential
|
||||
@@ -56,6 +57,7 @@ CREATE TABLE credential_issuance_reward
|
||||
rewarding_epoch_id INTEGER NOT NULL REFERENCES rewarding_epoch (id),
|
||||
operator_account TEXT NOT NULL,
|
||||
amount TEXT NOT NULL,
|
||||
whitelisted BOOLEAN NOT NULL,
|
||||
api_endpoint TEXT NOT NULL,
|
||||
issued_partial_credentials INTEGER NOT NULL,
|
||||
issued_credentials_share TEXT NOT NULL,
|
||||
|
||||
@@ -53,6 +53,9 @@ pub struct ConfigOverridableArgs {
|
||||
#[clap(long)]
|
||||
pub disable_block_signing_rewarding: bool,
|
||||
|
||||
#[clap(long)]
|
||||
pub block_signing_monitoring_only: bool,
|
||||
|
||||
#[clap(long)]
|
||||
pub disable_credential_issuance_rewarding: bool,
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use nym_config::{
|
||||
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,
|
||||
};
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
use nym_validator_client::nyxd::{AccountId, Coin};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{serde_as, DisplayFromStr};
|
||||
use std::io;
|
||||
@@ -225,7 +225,7 @@ impl Default for RewardingRatios {
|
||||
impl RewardingRatios {
|
||||
pub fn ensure_is_valid(&self) -> Result<(), NymRewarderError> {
|
||||
if self.block_signing + self.credential_verification + self.credential_issuance != 1.0 {
|
||||
todo!()
|
||||
return Err(NymRewarderError::InvalidRewardingRatios { ratios: *self });
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -238,19 +238,30 @@ pub struct NyxdScraper {
|
||||
// TODO: debug with everything that's currently hardcoded in the scraper
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Copy)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct BlockSigning {
|
||||
/// Specifies whether credential issuance for block signing is enabled.
|
||||
/// Specifies whether rewards for block signing is enabled.
|
||||
pub enabled: bool,
|
||||
|
||||
/// Specifies whether to only monitor and not send rewards.
|
||||
pub monitor_only: bool,
|
||||
|
||||
/// List of validators that will receive rewards for block signing.
|
||||
/// If not on the list, the validator will be treated as if it had 0 voting power.
|
||||
pub whitelist: Vec<AccountId>,
|
||||
}
|
||||
|
||||
impl Default for BlockSigning {
|
||||
fn default() -> Self {
|
||||
BlockSigning { enabled: true }
|
||||
BlockSigning {
|
||||
enabled: true,
|
||||
monitor_only: false,
|
||||
whitelist: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Copy)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct IssuanceMonitor {
|
||||
/// Specifies whether credential issuance monitoring (and associated rewards) are enabled.
|
||||
pub enabled: bool,
|
||||
@@ -264,15 +275,20 @@ pub struct IssuanceMonitor {
|
||||
|
||||
/// The sampling rate of the issued credentials
|
||||
pub sampling_rate: f64,
|
||||
|
||||
/// List of validators that will receive rewards for credential issuance.
|
||||
/// If not on the list, the validator will be treated as if it hadn't issued a single credential.
|
||||
pub whitelist: Vec<AccountId>,
|
||||
}
|
||||
|
||||
impl Default for IssuanceMonitor {
|
||||
fn default() -> Self {
|
||||
IssuanceMonitor {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
run_interval: DEFAULT_MONITOR_RUN_INTERVAL,
|
||||
min_validate_per_issuer: DEFAULT_MONITOR_MIN_VALIDATE,
|
||||
sampling_rate: DEFAULT_MONITOR_SAMPLING_RATE,
|
||||
whitelist: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ impl ConfigOverride for ConfigOverridableArgs {
|
||||
config.block_signing.enabled = false
|
||||
}
|
||||
|
||||
if self.block_signing_monitoring_only {
|
||||
config.block_signing.monitor_only = true
|
||||
}
|
||||
|
||||
if self.disable_credential_issuance_rewarding {
|
||||
config.issuance_monitor.enabled = false
|
||||
}
|
||||
|
||||
@@ -38,9 +38,19 @@ credential_verification = {{ rewarding.ratios.credential_verification }}
|
||||
|
||||
|
||||
[block_signing]
|
||||
# Specifies whether credential issuance for block signing is enabled.
|
||||
# Specifies whether rewarding for block signing is enabled.
|
||||
enabled = {{ block_signing.enabled }}
|
||||
|
||||
|
||||
# Specifies whether to only monitor and not send rewards.
|
||||
monitor_only = {{ block_signing.monitor_only }}
|
||||
|
||||
# List of validators that will receive rewards for block signing.
|
||||
# If not on the list, the validator will be treated as if it had 0 voting power.
|
||||
whitelist = [
|
||||
# needs to be manually populated; expects nvalcons1... addresses.
|
||||
# you can get them from, for example, `/cosmos/base/tendermint/v1beta1/validatorsets/latest` endpoint
|
||||
]
|
||||
|
||||
|
||||
[issuance_monitor]
|
||||
# Specifies whether credential issuance monitoring (and associated rewards) are enabled.
|
||||
@@ -54,6 +64,12 @@ min_validate_per_issuer = {{ issuance_monitor.min_validate_per_issuer }}
|
||||
|
||||
# The sampling rate of the issued credentials
|
||||
sampling_rate = {{ issuance_monitor.sampling_rate }}
|
||||
|
||||
# List of validators that will receive rewards for credential issuance.
|
||||
# If not on the list, the validator will be treated as if it hadn't issued a single credential.
|
||||
whitelist = [
|
||||
# needs to be manually populated; expects n1... addresses
|
||||
]
|
||||
|
||||
[nyxd_scraper]
|
||||
# Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::config::RewardingRatios;
|
||||
use nym_coconut::CoconutError;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
use nym_validator_client::nyxd::error::NyxdError;
|
||||
@@ -50,7 +51,7 @@ pub enum NymRewarderError {
|
||||
NyxdFailure(#[from] NyxdError),
|
||||
|
||||
#[error("the provided rewarding ratios don't add up to 1. ratios: {ratios:?}")]
|
||||
InvalidRewardingRatios { ratios: Vec<f32> },
|
||||
InvalidRewardingRatios { ratios: RewardingRatios },
|
||||
|
||||
#[error("chain scraping failure: {source}")]
|
||||
ScraperFailure {
|
||||
@@ -156,6 +157,12 @@ pub enum NymRewarderError {
|
||||
|
||||
#[error("the scraper websocket endpoint hasn't been provided")]
|
||||
UnavailableWebsocketUrl,
|
||||
|
||||
#[error("block signing rewarding is enabled, but the validator whitelist is empty")]
|
||||
EmptyBlockSigningWhitelist,
|
||||
|
||||
#[error("credential issuance rewarding is enabled, but the validator whitelist is empty")]
|
||||
EmptyCredentialIssuanceWhitelist,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#![warn(clippy::expect_used)]
|
||||
#![warn(clippy::unwrap_used)]
|
||||
#![warn(clippy::todo)]
|
||||
#![warn(clippy::dbg_macro)]
|
||||
|
||||
use crate::cli::Cli;
|
||||
use clap::{crate_name, crate_version, Parser};
|
||||
|
||||
@@ -6,18 +6,19 @@ use crate::rewarder::block_signing::types::{EpochSigningResults, RawValidatorRes
|
||||
use crate::rewarder::epoch::Epoch;
|
||||
use crate::rewarder::nyxd_client::NyxdClient;
|
||||
use nym_validator_client::nyxd::module_traits::staking;
|
||||
use nym_validator_client::nyxd::PageRequest;
|
||||
use nym_validator_client::nyxd::{AccountId, PageRequest};
|
||||
use nyxd_scraper::NyxdScraper;
|
||||
use std::cmp::min;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
use tracing::info;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
pub(crate) mod types;
|
||||
|
||||
pub struct EpochSigning {
|
||||
pub(crate) nyxd_client: NyxdClient,
|
||||
pub(crate) nyxd_scraper: NyxdScraper,
|
||||
pub(crate) whitelist: Vec<AccountId>,
|
||||
}
|
||||
|
||||
impl EpochSigning {
|
||||
@@ -116,14 +117,29 @@ impl EpochSigning {
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
total_vp += vp;
|
||||
|
||||
let cons_address = &validator.consensus_address;
|
||||
// if this validator is NOT whitelisted, do not increase the total VP
|
||||
let whitelisted = if let Ok(parsed) = cons_address.parse() {
|
||||
if self.whitelist.contains(&parsed) {
|
||||
debug!("{cons_address} is on the whitelist");
|
||||
total_vp += vp;
|
||||
true
|
||||
} else {
|
||||
warn!("{cons_address} is not a valid consensus address");
|
||||
false
|
||||
}
|
||||
} else {
|
||||
debug!("{cons_address} is not on the whitelist");
|
||||
false
|
||||
};
|
||||
|
||||
let signed = self
|
||||
.nyxd_scraper
|
||||
.storage
|
||||
.get_signed_between_times(&validator.consensus_address, epoch_start, epoch_end)
|
||||
.await?;
|
||||
signed_in_epoch.insert(validator, RawValidatorResult::new(signed, vp));
|
||||
signed_in_epoch.insert(validator, RawValidatorResult::new(signed, vp, whitelisted));
|
||||
}
|
||||
|
||||
let total = self
|
||||
|
||||
@@ -15,6 +15,7 @@ pub struct ValidatorSigning {
|
||||
pub validator: models::Validator,
|
||||
pub staking_details: staking::Validator,
|
||||
pub operator_account: AccountId,
|
||||
pub whitelisted: bool,
|
||||
|
||||
pub voting_power_at_epoch_start: i64,
|
||||
pub voting_power_ratio: Decimal,
|
||||
@@ -33,6 +34,10 @@ impl ValidatorSigning {
|
||||
}
|
||||
|
||||
pub fn reward_amount(&self, signing_budget: &Coin) -> Coin {
|
||||
if !self.whitelisted {
|
||||
return Coin::new(0, &signing_budget.denom);
|
||||
}
|
||||
|
||||
let amount =
|
||||
Uint128::new(signing_budget.amount) * self.ratio_signed * self.voting_power_ratio;
|
||||
|
||||
@@ -51,13 +56,15 @@ pub struct EpochSigningResults {
|
||||
pub struct RawValidatorResult {
|
||||
pub signed_blocks: i32,
|
||||
pub voting_power: i64,
|
||||
pub whitelisted: bool,
|
||||
}
|
||||
|
||||
impl RawValidatorResult {
|
||||
pub fn new(signed_blocks: i32, voting_power: i64) -> Self {
|
||||
pub fn new(signed_blocks: i32, voting_power: i64, whitelisted: bool) -> Self {
|
||||
Self {
|
||||
signed_blocks,
|
||||
voting_power,
|
||||
whitelisted,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +100,11 @@ impl EpochSigningResults {
|
||||
let vp: u64 = raw_results.voting_power.try_into().unwrap_or_default();
|
||||
let signed: u64 = raw_results.signed_blocks.try_into().unwrap_or_default();
|
||||
|
||||
let voting_power_ratio = Decimal::from_ratio(vp, total_vp_u64);
|
||||
let voting_power_ratio = if raw_results.whitelisted {
|
||||
Decimal::from_ratio(vp, total_vp_u64)
|
||||
} else {
|
||||
Decimal::zero()
|
||||
};
|
||||
|
||||
debug_assert!(signed <= blocks_u64);
|
||||
let ratio_signed = Decimal::from_ratio(signed, blocks_u64);
|
||||
@@ -110,6 +121,7 @@ impl EpochSigningResults {
|
||||
validator,
|
||||
staking_details,
|
||||
operator_account,
|
||||
whitelisted: raw_results.whitelisted,
|
||||
voting_power_at_epoch_start: raw_results.voting_power,
|
||||
voting_power_ratio,
|
||||
signed_blocks: raw_results.signed_blocks,
|
||||
@@ -129,10 +141,11 @@ impl EpochSigningResults {
|
||||
.iter()
|
||||
.inspect(|v| {
|
||||
info!(
|
||||
"validator {} will receive {} at address {} for block signing work",
|
||||
"validator {} will receive {} at address {} for block signing work (whitelisted: {})",
|
||||
v.moniker(),
|
||||
v.reward_amount(budget),
|
||||
v.operator_account
|
||||
v.operator_account,
|
||||
v.whitelisted
|
||||
);
|
||||
})
|
||||
.map(|v| (v.operator_account.clone(), vec![v.reward_amount(budget)]))
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::rewarder::credential_issuance::types::{CredentialIssuanceResults, Mon
|
||||
use crate::rewarder::epoch::Epoch;
|
||||
use crate::rewarder::nyxd_client::NyxdClient;
|
||||
use nym_task::TaskClient;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use tracing::info;
|
||||
|
||||
mod monitor;
|
||||
@@ -21,9 +22,11 @@ impl CredentialIssuance {
|
||||
pub(crate) async fn new(
|
||||
epoch: Epoch,
|
||||
nyxd_client: &NyxdClient,
|
||||
whitelist: &[AccountId],
|
||||
) -> Result<Self, NymRewarderError> {
|
||||
Ok(CredentialIssuance {
|
||||
monitoring_results: MonitoringResults::new_initial(epoch, nyxd_client).await?,
|
||||
monitoring_results: MonitoringResults::new_initial(epoch, nyxd_client, whitelist)
|
||||
.await?,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -235,12 +235,15 @@ impl CredentialIssuanceMonitor {
|
||||
let api_client = api_client(&issuer)?;
|
||||
|
||||
let epoch_credentials = api_client.epoch_credentials(epoch_id).await?;
|
||||
let whitelisted = self.config.whitelist.contains(&issuer.operator_account);
|
||||
|
||||
let Some(first_id) = epoch_credentials.first_epoch_credential_id else {
|
||||
// no point in doing anything more - if they haven't issued anything, there's nothing to verify
|
||||
debug!("no credentials issued this epoch",);
|
||||
return Ok(RawOperatorResult::new_empty(
|
||||
issuer.operator_account,
|
||||
issuer.api_runner,
|
||||
whitelisted,
|
||||
));
|
||||
};
|
||||
trace!("issued credentials: {epoch_credentials:?}");
|
||||
@@ -283,6 +286,7 @@ impl CredentialIssuanceMonitor {
|
||||
Ok(RawOperatorResult {
|
||||
operator_account: issuer.operator_account,
|
||||
api_runner: issuer.api_runner,
|
||||
whitelisted,
|
||||
issued_credentials: epoch_credentials.total_issued,
|
||||
validated_credentials: sampled,
|
||||
})
|
||||
|
||||
@@ -25,6 +25,7 @@ impl MonitoringResults {
|
||||
pub(crate) async fn new_initial(
|
||||
initial_epoch: Epoch,
|
||||
nyxd_client: &NyxdClient,
|
||||
whitelist: &[AccountId],
|
||||
) -> Result<Self, NymRewarderError> {
|
||||
let epoch = nyxd_client.dkg_epoch().await?;
|
||||
let issuers = nyxd_client.get_credential_issuers(epoch.epoch_id).await?;
|
||||
@@ -36,6 +37,7 @@ impl MonitoringResults {
|
||||
let mut raw_issuer = RawOperatorIssuing {
|
||||
api_runner: issuer.api_runner.clone(),
|
||||
runner_account: issuer.operator_account.clone(),
|
||||
whitelisted: whitelist.contains(&issuer.operator_account),
|
||||
per_epoch: Default::default(),
|
||||
};
|
||||
|
||||
@@ -132,6 +134,7 @@ impl MonitoringResults {
|
||||
RawOperatorIssuing {
|
||||
api_runner: result.api_runner.clone(),
|
||||
runner_account: result.runner_account.clone(),
|
||||
whitelisted: result.whitelisted,
|
||||
per_epoch: kept_epoch,
|
||||
},
|
||||
);
|
||||
@@ -157,18 +160,20 @@ pub(crate) struct MonitoringResultsInner {
|
||||
|
||||
impl From<MonitoringResultsInner> for CredentialIssuanceResults {
|
||||
fn from(value: MonitoringResultsInner) -> Self {
|
||||
let total_issued = value
|
||||
.operators
|
||||
.values()
|
||||
.map(|o| {
|
||||
let operator_issued: u32 = o
|
||||
let mut total_issued = 0;
|
||||
|
||||
for operator in value.operators.values() {
|
||||
// if this validator is NOT whitelisted, do not increase the total issued credentials
|
||||
if operator.whitelisted {
|
||||
let operator_issued: u32 = operator
|
||||
.per_epoch
|
||||
.values()
|
||||
.map(|e| e.issued_since_monitor_started)
|
||||
.sum();
|
||||
operator_issued
|
||||
})
|
||||
.sum();
|
||||
|
||||
total_issued += operator_issued
|
||||
}
|
||||
}
|
||||
|
||||
CredentialIssuanceResults {
|
||||
total_issued_partial_credentials: total_issued,
|
||||
@@ -177,7 +182,7 @@ impl From<MonitoringResultsInner> for CredentialIssuanceResults {
|
||||
.operators
|
||||
.into_values()
|
||||
.map(|runner| {
|
||||
let issued_ratio = if total_issued == 0 {
|
||||
let issued_ratio = if total_issued == 0 || !runner.whitelisted {
|
||||
Decimal::zero()
|
||||
} else {
|
||||
Decimal::from_ratio(runner.issued_credentials(), total_issued)
|
||||
@@ -187,6 +192,7 @@ impl From<MonitoringResultsInner> for CredentialIssuanceResults {
|
||||
issued_credentials: runner.issued_credentials(),
|
||||
validated_credentials: runner.validated_credentials(),
|
||||
api_runner: runner.api_runner,
|
||||
whitelisted: runner.whitelisted,
|
||||
runner_account: runner.runner_account,
|
||||
}
|
||||
})
|
||||
@@ -212,6 +218,7 @@ impl MonitoringResultsInner {
|
||||
pub(crate) struct RawOperatorResult {
|
||||
pub(crate) operator_account: AccountId,
|
||||
pub(crate) api_runner: String,
|
||||
pub(crate) whitelisted: bool,
|
||||
|
||||
// how many credentials the operator claims to have issued in **TOTAL** in this **DKG** epoch
|
||||
pub(crate) issued_credentials: u32,
|
||||
@@ -219,10 +226,15 @@ pub(crate) struct RawOperatorResult {
|
||||
}
|
||||
|
||||
impl RawOperatorResult {
|
||||
pub(crate) fn new_empty(operator_account: AccountId, api_runner: String) -> RawOperatorResult {
|
||||
pub(crate) fn new_empty(
|
||||
operator_account: AccountId,
|
||||
api_runner: String,
|
||||
whitelisted: bool,
|
||||
) -> RawOperatorResult {
|
||||
RawOperatorResult {
|
||||
operator_account,
|
||||
api_runner,
|
||||
whitelisted,
|
||||
issued_credentials: 0,
|
||||
validated_credentials: Default::default(),
|
||||
}
|
||||
@@ -232,6 +244,7 @@ impl RawOperatorResult {
|
||||
pub struct RawOperatorIssuing {
|
||||
pub api_runner: String,
|
||||
pub runner_account: AccountId,
|
||||
pub whitelisted: bool,
|
||||
|
||||
pub per_epoch: HashMap<u32, IssuedEpochCredentials>,
|
||||
}
|
||||
@@ -243,6 +256,7 @@ impl RawOperatorIssuing {
|
||||
RawOperatorIssuing {
|
||||
api_runner: raw_result.api_runner,
|
||||
runner_account: raw_result.operator_account,
|
||||
whitelisted: raw_result.whitelisted,
|
||||
per_epoch,
|
||||
}
|
||||
}
|
||||
@@ -278,6 +292,7 @@ impl IssuedEpochCredentials {
|
||||
|
||||
pub struct OperatorIssuing {
|
||||
pub api_runner: String,
|
||||
pub whitelisted: bool,
|
||||
pub runner_account: AccountId,
|
||||
|
||||
pub issued_ratio: Decimal,
|
||||
@@ -286,10 +301,14 @@ pub struct OperatorIssuing {
|
||||
}
|
||||
|
||||
impl OperatorIssuing {
|
||||
pub fn reward_amount(&self, signing_budget: &Coin) -> Coin {
|
||||
let amount = Uint128::new(signing_budget.amount) * self.issued_ratio;
|
||||
pub fn reward_amount(&self, issuance_budget: &Coin) -> Coin {
|
||||
if !self.whitelisted {
|
||||
return Coin::new(0, &issuance_budget.denom);
|
||||
}
|
||||
|
||||
Coin::new(amount.u128(), &signing_budget.denom)
|
||||
let amount = Uint128::new(issuance_budget.amount) * self.issued_ratio;
|
||||
|
||||
Coin::new(amount.u128(), &issuance_budget.denom)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,10 +324,11 @@ impl CredentialIssuanceResults {
|
||||
.iter()
|
||||
.inspect(|a| {
|
||||
info!(
|
||||
"operator {} will receive {} at address {} for credential issuance work",
|
||||
"operator {} will receive {} at address {} for credential issuance work (whitelisted: {})",
|
||||
a.api_runner,
|
||||
a.reward_amount(budget),
|
||||
a.runner_account,
|
||||
a.whitelisted
|
||||
);
|
||||
})
|
||||
.map(|v| (v.runner_account.clone(), vec![v.reward_amount(budget)]))
|
||||
|
||||
@@ -24,7 +24,8 @@ impl Epoch {
|
||||
.add(HOUR)
|
||||
.replace_nanosecond(0)?
|
||||
.replace_microsecond(0)?
|
||||
.replace_second(0)?;
|
||||
.replace_second(0)?
|
||||
.replace_minute(0)?;
|
||||
|
||||
Ok(Epoch {
|
||||
id: 0,
|
||||
|
||||
@@ -41,17 +41,19 @@ impl EpochRewards {
|
||||
let mut amounts = Vec::new();
|
||||
|
||||
if let Some(signing) = &self.signing {
|
||||
for signing_amount in signing.rewarding_amounts(&self.signing_budget) {
|
||||
if signing_amount.1[0].amount != 0 {
|
||||
amounts.push(signing_amount)
|
||||
for (account, signing_amount) in signing.rewarding_amounts(&self.signing_budget) {
|
||||
if signing_amount[0].amount != 0 {
|
||||
amounts.push((account, signing_amount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(credentials) = &self.credentials {
|
||||
for credential_amount in credentials.rewarding_amounts(&self.credentials_budget) {
|
||||
if credential_amount.1[0].amount != 0 {
|
||||
amounts.push(credential_amount)
|
||||
for (account, credential_amount) in
|
||||
credentials.rewarding_amounts(&self.credentials_budget)
|
||||
{
|
||||
if credential_amount[0].amount != 0 {
|
||||
amounts.push((account, credential_amount))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,18 +88,29 @@ impl Rewarder {
|
||||
};
|
||||
|
||||
let epoch_signing = if config.block_signing.enabled {
|
||||
let whitelist = config.block_signing.whitelist.clone();
|
||||
if whitelist.is_empty() {
|
||||
return Err(NymRewarderError::EmptyBlockSigningWhitelist);
|
||||
}
|
||||
|
||||
let nyxd_scraper = NyxdScraper::new(config.scraper_config()).await?;
|
||||
|
||||
Some(EpochSigning {
|
||||
nyxd_scraper,
|
||||
nyxd_client: nyxd_client.clone(),
|
||||
whitelist,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let credential_issuance = if config.issuance_monitor.enabled {
|
||||
Some(CredentialIssuance::new(current_epoch, &nyxd_client).await?)
|
||||
let whitelist = &config.issuance_monitor.whitelist;
|
||||
if whitelist.is_empty() {
|
||||
return Err(NymRewarderError::EmptyCredentialIssuanceWhitelist);
|
||||
}
|
||||
|
||||
Some(CredentialIssuance::new(current_epoch, &nyxd_client, whitelist).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -196,6 +209,11 @@ impl Rewarder {
|
||||
&self,
|
||||
amounts: Vec<(AccountId, Vec<Coin>)>,
|
||||
) -> Result<Hash, NymRewarderError> {
|
||||
if self.config.block_signing.monitor_only {
|
||||
info!("skipping sending rewards, monitoring mode only");
|
||||
return Ok(Hash::Sha256([0u8; 32]));
|
||||
}
|
||||
|
||||
info!("sending rewards");
|
||||
self.nyxd_client
|
||||
.send_rewards(self.current_epoch, amounts)
|
||||
@@ -239,7 +257,7 @@ impl Rewarder {
|
||||
|
||||
if let Some(ref credential_issuance) = self.credential_issuance {
|
||||
credential_issuance.start_monitor(
|
||||
self.config.issuance_monitor,
|
||||
self.config.issuance_monitor.clone(),
|
||||
self.nyxd_client.clone(),
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
@@ -74,6 +74,7 @@ impl StorageManager {
|
||||
epoch: i64,
|
||||
consensus_address: String,
|
||||
operator_account: String,
|
||||
whitelisted: bool,
|
||||
amount: String,
|
||||
voting_power: i64,
|
||||
voting_power_share: String,
|
||||
@@ -86,16 +87,18 @@ impl StorageManager {
|
||||
rewarding_epoch_id,
|
||||
validator_consensus_address,
|
||||
operator_account,
|
||||
whitelisted,
|
||||
amount,
|
||||
voting_power,
|
||||
voting_power_share,
|
||||
signed_blocks,
|
||||
signed_blocks_percent
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
epoch,
|
||||
consensus_address,
|
||||
operator_account,
|
||||
whitelisted,
|
||||
amount,
|
||||
voting_power,
|
||||
voting_power_share,
|
||||
@@ -144,6 +147,7 @@ impl StorageManager {
|
||||
&self,
|
||||
epoch: i64,
|
||||
operator_account: String,
|
||||
whitelisted: bool,
|
||||
amount: String,
|
||||
api_endpoint: String,
|
||||
issued_partial_credentials: u32,
|
||||
@@ -155,15 +159,17 @@ impl StorageManager {
|
||||
INSERT INTO credential_issuance_reward (
|
||||
rewarding_epoch_id,
|
||||
operator_account,
|
||||
whitelisted,
|
||||
amount,
|
||||
api_endpoint,
|
||||
issued_partial_credentials,
|
||||
issued_credentials_share,
|
||||
validated_issued_credentials
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
epoch,
|
||||
operator_account,
|
||||
whitelisted,
|
||||
amount,
|
||||
api_endpoint,
|
||||
issued_partial_credentials,
|
||||
|
||||
@@ -104,6 +104,7 @@ impl RewarderStorage {
|
||||
epoch_id,
|
||||
validator.validator.consensus_address,
|
||||
validator.operator_account.to_string(),
|
||||
validator.whitelisted,
|
||||
reward_amount,
|
||||
validator.voting_power_at_epoch_start,
|
||||
validator.voting_power_ratio.to_string(),
|
||||
@@ -152,6 +153,7 @@ impl RewarderStorage {
|
||||
.insert_rewarding_epoch_credential_issuance_reward(
|
||||
epoch_id,
|
||||
api_runner.runner_account.to_string(),
|
||||
api_runner.whitelisted,
|
||||
reward_amount,
|
||||
api_runner.api_runner,
|
||||
api_runner.issued_credentials,
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
Date: Sun, 14 Jan 2024 20:34:14 +0000
|
||||
MD5Sum:
|
||||
f78e894e59a145bf9c44a2747bafc251 6083 Packages
|
||||
eea791395c8b2c200a5b9641aad92ff9 1813 Packages.gz
|
||||
22a6d744604a316b88e048e9aba70861 38 Release
|
||||
SHA1:
|
||||
8dff5ac5fa5b76a7b5e0436ed428adcfaeb6ee46 6083 Packages
|
||||
6ddb3393c2a17b0350a90a8c1f9bcabb0480f008 1813 Packages.gz
|
||||
05ed3399246e80daa379888037674e900d47f826 38 Release
|
||||
SHA256:
|
||||
f22508b4022ad510b77407f277f3963f08a68b9d89e04040e11712d37b250641 6083 Packages
|
||||
f2f36b35214d4a9b0fdf870a997dd5773ee695b02b35466fbda4319cf9d8d1aa 1813 Packages.gz
|
||||
a5f691742934e61dff3fbd6b36d59b290dcb3edc9a54ee45533f374a0de67c7b 38 Release
|
||||
SHA512:
|
||||
6d1cadd20672271e5e9fe9e65c0fd2cb58ab41d87c7750841e284aa5a4023df4f04c3da373a0916a7360511bba61fe8b0a3dfc571f3aba51219b38143cf76a03 6083 Packages
|
||||
5e84c10bce8d608f5fa373211a2bffb95c88a5e9d8823bfb61f9f989db1e76b9b6ef796cb8cede1242e1754f9202d64a23c6f3063ac21c6e6be7dafccbe2adcb 1813 Packages.gz
|
||||
ea4efdb7b497538ac2fa5ae786aeeb72fd867e9933cbe1ca05545a92306d8020506793d65e7f6d5964764c2c5772d92fad6088ed37aedb960069a4156e4bb4a9 38 Release
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJEBAEBCgAuFiEEzWLrAxjj1jSobw5ZgQ9E11+JZgIFAmWkRUYQHG55bUBueW10
|
||||
ZWNoLm5ldAAKCRCBD0TXX4lmAj1ID/99hRCleE06tCD+I0eDTw2iUG/TVU1Qzq/I
|
||||
qh6jhtbS1KexM2VaVyb7qKYtTLphqYyelKHG3eNtQeuTXaGPrjC535Av91/VjC13
|
||||
wIAdy0/CsG5MVboiMnrmp1G3572hmdQbuY9u1VIqeJjKEHJKBQFNYC842LV6CB/A
|
||||
/HWZKTtWpEAXOd/Z68TM7uYmU8mM6Ef/UYaqN4jQ4SNrvI5ssGIfjm8z/YuhXWdm
|
||||
mj5rHiTPMwdzTFhXfrOkFGiwnbKcgOfmeSUBTtfU6s+yGnFCDIaL5tm4jSoBfxKy
|
||||
/swbJv9FBQTRAA+17luOlFJcrxc/DNCax1ZmnZmlWY47S75whjptJZQ5zRZ8oRoO
|
||||
l8sI5vLu6qwRmrMwibh+kjE+o7XOCuCDFrxXhqu3ZrawuUVL4g/IOdpWOgmHvsL7
|
||||
7Mf0cOzf7jWitRtHoK70Y9CGhx08x6NTa/7E5OEEAkFrd5wmAy7AWJp2SFBfGSLP
|
||||
Oni0cvGS67FQmT02YkSSFwaQIRVpb0U8rAIIAP3cn9bW9Zbv/8JAgJ12s8jqAHE8
|
||||
Vj39hv3x6LhzUQ6Y62LRC8DaPZ+RQmpTCjCUsQ61YLJ32Y56sar3sp51bi/BVihu
|
||||
7KYPrpNoIVn9p8EoaMwMm4XWc8TT9DbUKsgKn8CWiuZxCA225mVHVQbzaFWXY5y3
|
||||
4Dkmc1mjiA==
|
||||
=tMQC
|
||||
-----END PGP SIGNATURE-----
|
||||
-214
@@ -1,214 +0,0 @@
|
||||
Package: nym-gateway
|
||||
Version: 1.1.32-1
|
||||
Architecture: amd64
|
||||
Maintainer: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
|
||||
Installed-Size: 30299
|
||||
Depends: curl
|
||||
Filename: ./debian/nym-gateway_1.1.32-1_amd64.deb
|
||||
Size: 7406752
|
||||
MD5sum: 390da86b88bc1061cb01d4529af1b9a0
|
||||
SHA1: d9a733aa65e4f1fbb7be942d67de4d3ecfda6d06
|
||||
SHA256: c23b76a47c0b8ae265ab0d5c87040739c57bd0b55ebe2cb59a05e99bf94f1b2f
|
||||
Priority: optional
|
||||
Description: Implementation of the Nym Mixnet Gateway
|
||||
<!--
|
||||
Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
-->
|
||||
.
|
||||
# Nym Gateway
|
||||
.
|
||||
A Rust gateway implementation.
|
||||
.
|
||||
## License
|
||||
.
|
||||
Copyright (C) 2023 Nym Technologies SA <contact@nymtech.net>
|
||||
.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
.
|
||||
## Install debian
|
||||
.
|
||||
```bash
|
||||
sudo curl -s --compressed "https://nymtech.github.io/nym/nymtech.gpg" | gpg
|
||||
--dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg]
|
||||
https://nymtech.github.io/nym/ /" > nymtech.list
|
||||
.
|
||||
sudo apt-get update
|
||||
sudo apt-get install nym-gateway
|
||||
.
|
||||
# See below for starting and managing the node
|
||||
```
|
||||
.
|
||||
## Systemd support
|
||||
.
|
||||
```bash
|
||||
sudo systemctl enable nym-gateway
|
||||
.
|
||||
# Run
|
||||
sudo systemctl start nym-gateway
|
||||
.
|
||||
# Check status
|
||||
sudo systemctl status nym-mixnode
|
||||
.
|
||||
# Logs
|
||||
journalctl -f -u nym-mixnode
|
||||
.
|
||||
```
|
||||
.
|
||||
## Build debian package
|
||||
.
|
||||
```bash
|
||||
# cargo install cargo-deb
|
||||
.
|
||||
# Build package
|
||||
cargo deb -p nym-mixnode
|
||||
.
|
||||
# Install
|
||||
.
|
||||
# This will init the mixnode to `/etc/nym` as `nym` user, and create a systemd
|
||||
service
|
||||
sudo dpkg -i target/debian/<PACKAGE>
|
||||
```
|
||||
|
||||
Package: nym-mixnode
|
||||
Version: 1.1.33-1
|
||||
Architecture: amd64
|
||||
Maintainer: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
|
||||
Installed-Size: 23794
|
||||
Depends: libc6 (>= 2.34)
|
||||
Filename: ./debian/nym-mixnode_1.1.33-1_amd64.deb
|
||||
Size: 5245732
|
||||
MD5sum: a9377a1aabfda9d95ce3a937fb4f02ed
|
||||
SHA1: 535e76d7c5c0d8dc96b30c34fa1de46fbc9c40dd
|
||||
SHA256: 70874c9d738998b6b671965ee724c47f56a8486d8eb6c73e94498f8c240fa62b
|
||||
Priority: optional
|
||||
Description: Implementation of a Loopix-based Mixnode
|
||||
<!--
|
||||
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
.
|
||||
# Nym Mixnode
|
||||
.
|
||||
A Rust mixnode implementation.
|
||||
.
|
||||
## Usage
|
||||
.
|
||||
* `nym-mixnode` prints a help message showing usage options
|
||||
* `nym-mixnode run --help` prints a help message showing usage options for the
|
||||
run command
|
||||
* `nym-mixnode run --layer 1 --host x.x.x.x` will start the mixnode in layer 1
|
||||
and bind to the specified host IP address. Coordinate with other people in your
|
||||
network to find out which layer needs coverage.
|
||||
.
|
||||
By default, the Nym Mixnode will start on port 1789. If desired, you can change
|
||||
the port using the `--port` option.
|
||||
|
||||
Package: nym-mixnode
|
||||
Version: 1.1.34-1
|
||||
Architecture: amd64
|
||||
Maintainer: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
|
||||
Installed-Size: 24536
|
||||
Depends: libc6 (>= 2.34)
|
||||
Filename: ./debian/nym-mixnode_1.1.34-1_amd64.deb
|
||||
Size: 5526956
|
||||
MD5sum: 0f4a0c65e0d6c3d124b5800e5f517ad8
|
||||
SHA1: b80d46d861f1b90ab5528f7d8c6be078923d7b2b
|
||||
SHA256: c294728949c85260428a736601870b5dc9f82b49ec33fa998e4195f41f83cca0
|
||||
Priority: optional
|
||||
Description: Implementation of a Loopix-based Mixnode
|
||||
<!--
|
||||
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
-->
|
||||
.
|
||||
# Nym Mixnode
|
||||
.
|
||||
A Rust mixnode implementation.
|
||||
.
|
||||
## License
|
||||
.
|
||||
Copyright (C) 2020 Nym Technologies SA <contact@nymtech.net>
|
||||
.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
.
|
||||
## Usage
|
||||
.
|
||||
* `nym-mixnode` prints a help message showing usage options
|
||||
* `nym-mixnode run --help` prints a help message showing usage options for the
|
||||
run command
|
||||
* `nym-mixnode run --layer 1 --host x.x.x.x` will start the mixnode in layer 1
|
||||
and bind to the specified host IP address. Coordinate with other people in your
|
||||
network to find out which layer needs coverage.
|
||||
.
|
||||
By default, the Nym Mixnode will start on port 1789. If desired, you can change
|
||||
the port using the `--port` option.
|
||||
.
|
||||
## Install debian
|
||||
.
|
||||
```bash
|
||||
sudo curl -s --compressed "https://nymtech.github.io/nym/nymtech.gpg" | gpg
|
||||
--dearmor | sudo tee /etc/apt/trusted.gpg.d/nymtech.gpg > /dev/null
|
||||
sudo echo "deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg]
|
||||
https://nymtech.github.io/nym/ /" > nymtech.list
|
||||
.
|
||||
sudo apt-get update
|
||||
sudo apt-get install nym-mixnode
|
||||
.
|
||||
# See below for starting and managing the node
|
||||
```
|
||||
.
|
||||
## Systemd support
|
||||
.
|
||||
```bash
|
||||
sudo systemctl enable nym-mixnode
|
||||
.
|
||||
# Run
|
||||
sudo systemctl start nym-mixnode
|
||||
.
|
||||
# Check status
|
||||
sudo systemctl status nym-mixnode
|
||||
.
|
||||
# Logs
|
||||
journalctl -f -u nym-mixnode
|
||||
.
|
||||
```
|
||||
.
|
||||
## Build debian package
|
||||
.
|
||||
```bash
|
||||
# cargo install cargo-deb
|
||||
.
|
||||
# Build package
|
||||
cargo deb -p nym-mixnode
|
||||
.
|
||||
# Install
|
||||
.
|
||||
# This will init the mixnode to `/etc/nym` as `nym` user, and create a systemd
|
||||
service
|
||||
sudo dpkg -i target/debian/<PACKAGE>
|
||||
```
|
||||
|
||||
Binary file not shown.
-17
@@ -1,17 +0,0 @@
|
||||
Date: Sun, 14 Jan 2024 20:34:14 +0000
|
||||
MD5Sum:
|
||||
f78e894e59a145bf9c44a2747bafc251 6083 Packages
|
||||
eea791395c8b2c200a5b9641aad92ff9 1813 Packages.gz
|
||||
22a6d744604a316b88e048e9aba70861 38 Release
|
||||
SHA1:
|
||||
8dff5ac5fa5b76a7b5e0436ed428adcfaeb6ee46 6083 Packages
|
||||
6ddb3393c2a17b0350a90a8c1f9bcabb0480f008 1813 Packages.gz
|
||||
05ed3399246e80daa379888037674e900d47f826 38 Release
|
||||
SHA256:
|
||||
f22508b4022ad510b77407f277f3963f08a68b9d89e04040e11712d37b250641 6083 Packages
|
||||
f2f36b35214d4a9b0fdf870a997dd5773ee695b02b35466fbda4319cf9d8d1aa 1813 Packages.gz
|
||||
a5f691742934e61dff3fbd6b36d59b290dcb3edc9a54ee45533f374a0de67c7b 38 Release
|
||||
SHA512:
|
||||
6d1cadd20672271e5e9fe9e65c0fd2cb58ab41d87c7750841e284aa5a4023df4f04c3da373a0916a7360511bba61fe8b0a3dfc571f3aba51219b38143cf76a03 6083 Packages
|
||||
5e84c10bce8d608f5fa373211a2bffb95c88a5e9d8823bfb61f9f989db1e76b9b6ef796cb8cede1242e1754f9202d64a23c6f3063ac21c6e6be7dafccbe2adcb 1813 Packages.gz
|
||||
ea4efdb7b497538ac2fa5ae786aeeb72fd867e9933cbe1ca05545a92306d8020506793d65e7f6d5964764c2c5772d92fad6088ed37aedb960069a4156e4bb4a9 38 Release
|
||||
@@ -1,17 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQJEBAABCgAuFiEEzWLrAxjj1jSobw5ZgQ9E11+JZgIFAmWkRUYQHG55bUBueW10
|
||||
ZWNoLm5ldAAKCRCBD0TXX4lmAjSqEACHqQIP8w3mH86nqD0BJi3vZhMuYZsuxr9r
|
||||
nyZS7vhCqDTz+4ahJBEHW3n1GNdf6EI1KuswY82FeWEiBYQaIapDv++ADwH4mOY9
|
||||
splwnHYCITQOMOOL8+mvk1vFe3AGQNDkHW7jhhT/2GUIxl31wc3Y65lX9V1NQ0kf
|
||||
b1nfvZiLxES4Lw4YL5wopRlYw5ws9Qcp+GHuOJNA9423KYS/GeHoyay3wrilW8sJ
|
||||
JeUfS9zEPplaVD4wyaoz45taFC47PsnXPJegTZ3yyTrfyQi3l71qCS8qprza+sFv
|
||||
aCKa2zT+4YAetpTY77NYeeh/Wztai93aKjqlrjW5KEHPs3oWq8Y3afKI0/Ltjp2j
|
||||
kpqbWhyppbVSc20YYf/1rPU5oKYjIcu6yFyypnSBrX5Q0Q2MSqGgi8yAN+hwG/Aj
|
||||
/T+BylTqdKMAZCohV2r3Jp74jnJDydRqpGNtqQEdE4aSa4xfh8L3RbCEKYa6Ugqy
|
||||
KEgnMHGmYD7cNx/FKly9zVLdRsuMD4MV/ndtXVjk3+O+xMU4iNwvowfnHkbzAPcC
|
||||
nV7KyxkcMQ9wmXRbCmhPp71RsmLI4d/wm53/bxwrMtfOOJ8HMhi0PFASnO80mzbJ
|
||||
nT2EWyRy5JkHsX4gVvVTQmpYxB3ilSFIYVNxfVrhQNbX8hfv3epnvLbbWdMWequx
|
||||
knlP3IctJg==
|
||||
=Du2e
|
||||
-----END PGP SIGNATURE-----
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
deb [signed-by=/etc/apt/trusted.gpg.d/nymtech.gpg] https://nymtech.github.io/nym/ /
|
||||
@@ -1,22 +0,0 @@
|
||||
#/bin/bash
|
||||
# Run from repository root
|
||||
# Needs PPA_SIGNING_KEY base64 encoded in env var
|
||||
|
||||
echo ${PPA_SIGNING_KEY} | base64 -d >ppa-signing-key.asc
|
||||
gpg --import ppa-signing-key.asc
|
||||
rm ppa-signing-key.asc
|
||||
|
||||
cargo deb -p nym-mixnode
|
||||
cargo deb -p nym-gateway
|
||||
cargo deb -p nym-cli
|
||||
|
||||
mv target/debian/*.deb ppa/debian
|
||||
|
||||
cd ppa
|
||||
|
||||
dpkg-scanpackages --multiversion . >Packages
|
||||
gzip -k -f Packages
|
||||
|
||||
apt-ftparchive release . >Release
|
||||
gpg --default-key "nym@nymtech.net" -abs -o - Release >Release.gpg
|
||||
gpg --default-key "nym@nymtech.net" --clearsign -o - Release >InRelease
|
||||
@@ -0,0 +1,2 @@
|
||||
src/main
|
||||
target/
|
||||
Generated
+5728
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "nym_cpp_ffi"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "nym_cpp_ffi"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
# Nym clients, addressing, packet format, common tools (logging)
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
# static var macro
|
||||
lazy_static = "1.4.0"
|
||||
# error handling
|
||||
anyhow = "1.0.75"
|
||||
# base58 en/decoding
|
||||
bs58 = "0.5.0"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# C++ FFI
|
||||
> ⚠️ This is an initial version of this library in order to give developers something to experiment with. If you use this code to begin testing out Mixnet integration and run into issues, errors, or have feedback, please feel free to open an issue; feedback from developers trying to use it will help us improve it. If you have questions feel free to reach out via our [Matrix channel]().
|
||||
|
||||
This repo contains:
|
||||
* `lib.rs`: an initial version of bindings for interacting with the Mixnet via the Rust SDK from C++.
|
||||
* `main.cpp`: an example of using this library, relying on `Boost` for threads.
|
||||
|
||||
The example `.cpp` file is a simple example flow of:
|
||||
* setting up Nym client logging
|
||||
* creating an ephemeral Nym client (no key storage / persistent address - this will come in a future iteration)
|
||||
* getting its [Nym address](https://nymtech.net/docs/clients/addressing-system.html)
|
||||
* using that address to send a message to yourself via the Mixnet
|
||||
* listen for and parse the incoming message for the `sender_tag` used for [anonymous replies with SURBs](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs)
|
||||
* send a reply to yourself using SURBs
|
||||
|
||||
## Installation
|
||||
Prerequisites:
|
||||
* Rust
|
||||
* C++
|
||||
* [Boost](https://www.boost.org/) which can be installed with:
|
||||
```
|
||||
# Arch / Manjaro
|
||||
yay -S boost boost-libs
|
||||
|
||||
# Debian / Ubuntu
|
||||
sudo apt install libboost-all-dev
|
||||
```
|
||||
|
||||
## Usage
|
||||
The `build.sh` script in the root of the repository speeds up the task of building and linking the Rust and C++ code.
|
||||
* if want to quickly recompile your code run it as-is with `./build.sh`
|
||||
* if you want to clean build both the Rust and C++ code after removing existing compiled binaries run it with the optional `clean` argument: `./build.sh clean`.
|
||||
|
||||
> Make sure to run the script from the root of the project directory.
|
||||
|
||||
This script will:
|
||||
* (optionally if called with `clean` argument) remove existing Rust and C++ artifacts
|
||||
* build `lib.rs` with the `--release` flag
|
||||
* compile `main.cpp`, linking `lib.rs`
|
||||
* set value of `LD_LIBRARY_PATH` to the Rust code in `target/release/`
|
||||
* run the compiled `main`
|
||||
|
||||
## Error Handling
|
||||
When calling a function across the FFI boundary (e.g.) `reply`, the Rust code is matching the output of an `_internal` function - `Res` or `Err` - to a member of the `StatusCode` enum. This allows for both Rust-style error handling and the ease of returning a `c_int` across the FFI boundary, which can be used by C++ for its own error handling / conditional logic.
|
||||
|
||||
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
C_CODE_NAME="main"
|
||||
PROJECT_NAME="cpp"
|
||||
|
||||
clean_artifacts() {
|
||||
printf "cleaning cargo artifacts \n"
|
||||
cargo clean
|
||||
|
||||
if [ -e "src/${C_CODE_NAME}" ]
|
||||
then
|
||||
printf "cleaning compiled C++ \n"
|
||||
rm src/${C_CODE_NAME}
|
||||
else
|
||||
printf "no compiled C++ to clean \n"
|
||||
fi
|
||||
}
|
||||
|
||||
build_artifacts_and_link() {
|
||||
cargo build --release &&
|
||||
cd src/ &&
|
||||
printf "compiling cpp \n"
|
||||
g++ -std=c++11 -o main main.cpp -ldl -lpthread -L../target/release -lnym_cpp_ffi -lboost_thread &&
|
||||
export LD_LIBRARY_PATH=../target/release:$LD_LIBRARY_PATH
|
||||
# check output for name of rust lib - can be helpful if you've changed e.g. the name of a file and the compilation is failing
|
||||
# printf "ldd main: \n"
|
||||
# ldd main
|
||||
}
|
||||
|
||||
if [ $(pwd | awk -F/ '{print $NF}') != ${PROJECT_NAME} ]
|
||||
then
|
||||
printf "please run from root dir of project"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -eq 0 ];
|
||||
then
|
||||
build_artifacts_and_link;
|
||||
./main;
|
||||
else
|
||||
arg=$1
|
||||
if [ "$arg" == "clean" ]; then
|
||||
clean_artifacts;
|
||||
build_artifacts_and_link;
|
||||
./main;
|
||||
else
|
||||
echo "unknown optional argument - the only available optional argument is 'clean'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use lazy_static::lazy_static;
|
||||
use nym_sdk::mixnet::{MixnetClient, MixnetMessageSender, ReconstructedMessage};
|
||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||
use std::ffi::{c_char, c_int, CStr, CString};
|
||||
use std::mem::forget;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
/*
|
||||
NYM_CLIENT: Static reference (only init-ed once) to:
|
||||
- Arc: share ownership
|
||||
- Mutex: thread-safe way to share data between threads
|
||||
- Option: init-ed or not
|
||||
RUNTIME: Tokio runtime: no need to pass back to C and deal with raw pointers as it was previously
|
||||
*/
|
||||
lazy_static! {
|
||||
static ref NYM_CLIENT: Arc<Mutex<Option<MixnetClient>>> = Arc::new(Mutex::new(None));
|
||||
static ref RUNTIME: Runtime = Runtime::new().unwrap();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StatusCode {
|
||||
NoError = 0,
|
||||
ClientInitError = -1,
|
||||
ClientUninitialisedError = -2,
|
||||
SelfAddrError = -3,
|
||||
SendMsgError = -4,
|
||||
ReplyError = -5,
|
||||
ListenError = -6,
|
||||
}
|
||||
|
||||
// pub type CIntCallback = extern "C" fn(i32);
|
||||
pub type CStringCallback = extern "C" fn(*const c_char);
|
||||
pub type CMessageCallback = extern "C" fn(ReceivedMessage);
|
||||
|
||||
// FFI-sanitised way of sending back a ReconstructedMessage to C
|
||||
#[repr(C)]
|
||||
pub struct ReceivedMessage {
|
||||
message: *const u8,
|
||||
size: usize,
|
||||
sender_tag: *const c_char,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init_logging() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init_ephemeral() -> c_int {
|
||||
match init_ephemeral_internal() {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ClientInitError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn init_ephemeral_internal() -> anyhow::Result<(), anyhow::Error> {
|
||||
if NYM_CLIENT.lock().unwrap().as_ref().is_some() {
|
||||
bail!("client already exists");
|
||||
} else {
|
||||
RUNTIME.block_on(async move {
|
||||
let init_client = MixnetClient::connect_new().await?;
|
||||
let mut client = NYM_CLIENT.try_lock();
|
||||
if let Ok(ref mut client) = client {
|
||||
**client = Some(init_client);
|
||||
} else {
|
||||
anyhow!("couldnt lock NYM_CLIENT");
|
||||
}
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_self_address(callback: CStringCallback) -> c_int {
|
||||
match get_self_address_internal(callback) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::SelfAddrError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_self_address_internal(callback: CStringCallback) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
// get address as cstring
|
||||
let c_string = CString::new(nym_client.nym_address().to_string())?;
|
||||
// as_ptr() keeps ownership in rust unlike into_raw() so no need to free it
|
||||
callback(c_string.as_ptr());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn send_message(recipient: *const c_char, message: *const c_char) -> c_int {
|
||||
match send_message_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::SendMsgError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn send_message_internal(
|
||||
recipient: *const c_char,
|
||||
message: *const c_char,
|
||||
) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
let c_str = unsafe {
|
||||
if recipient.is_null() {
|
||||
bail!("recipient is null");
|
||||
}
|
||||
let c_str = CStr::from_ptr(recipient);
|
||||
c_str
|
||||
};
|
||||
let r_str = c_str.to_str().unwrap();
|
||||
let recipient = r_str.parse().unwrap();
|
||||
let c_str = unsafe {
|
||||
if message.is_null() {
|
||||
bail!("message is null");
|
||||
}
|
||||
let c_str = CStr::from_ptr(message);
|
||||
c_str
|
||||
};
|
||||
let message = c_str.to_str().unwrap();
|
||||
|
||||
// send message
|
||||
RUNTIME.block_on(async move {
|
||||
nym_client.send_plain_message(recipient, message).await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn reply(recipient: *const c_char, message: *const c_char) -> c_int {
|
||||
match reply_internal(recipient, message) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ReplyError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn reply_internal(
|
||||
recipient: *const c_char,
|
||||
message: *const c_char,
|
||||
) -> anyhow::Result<(), anyhow::Error> {
|
||||
let client = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if client.is_none() {
|
||||
bail!("Client is not yet initialised");
|
||||
}
|
||||
let nym_client = client
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
let recipient = unsafe {
|
||||
if recipient.is_null() {
|
||||
bail!("recipient is null");
|
||||
}
|
||||
let r_str = CStr::from_ptr(recipient).to_string_lossy().into_owned();
|
||||
AnonymousSenderTag::try_from_base58_string(r_str)
|
||||
.expect("could not construct AnonymousSenderTag from supplied value")
|
||||
};
|
||||
let message = unsafe {
|
||||
if message.is_null() {
|
||||
bail!("message is null");
|
||||
}
|
||||
let c_str = CStr::from_ptr(message);
|
||||
let r_str = c_str.to_str().unwrap();
|
||||
r_str
|
||||
};
|
||||
RUNTIME.block_on(async move {
|
||||
nym_client.send_reply(recipient, message).await?;
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn listen_for_incoming(callback: CMessageCallback) -> c_int {
|
||||
match listen_for_incoming_internal(callback) {
|
||||
Ok(_) => StatusCode::NoError as c_int,
|
||||
Err(_) => StatusCode::ListenError as c_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn listen_for_incoming_internal(callback: CMessageCallback) -> anyhow::Result<(), anyhow::Error> {
|
||||
let mut binding = NYM_CLIENT.lock().expect("could not lock NYM_CLIENT");
|
||||
if binding.is_none() {
|
||||
bail!("recipient is null");
|
||||
}
|
||||
let client = binding
|
||||
.as_mut()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"))?;
|
||||
|
||||
RUNTIME.block_on(async move {
|
||||
let received = wait_for_non_empty_message(client).await?;
|
||||
let message_ptr = received.message.as_ptr();
|
||||
let message_length = received.message.len();
|
||||
let c_string = CString::new(received.sender_tag.unwrap().to_string())?;
|
||||
let sender_ptr = c_string.as_ptr();
|
||||
// stop deallocation when out of scope as passing raw ptr to it elsewhere
|
||||
forget(received);
|
||||
let rec_for_c = ReceivedMessage {
|
||||
message: message_ptr,
|
||||
size: message_length,
|
||||
sender_tag: sender_ptr,
|
||||
};
|
||||
callback(rec_for_c);
|
||||
Ok::<(), anyhow::Error>(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn wait_for_non_empty_message(
|
||||
client: &mut MixnetClient,
|
||||
) -> anyhow::Result<ReconstructedMessage> {
|
||||
while let Some(mut new_message) = client.wait_for_messages().await {
|
||||
if !new_message.is_empty() {
|
||||
return new_message
|
||||
.pop()
|
||||
.ok_or_else(|| anyhow!("could not get client as_ref()"));
|
||||
}
|
||||
}
|
||||
bail!("(Rust) did not receive any non-empty message")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
//Rust function & type signatures
|
||||
extern "C" {
|
||||
struct ReceivedMessage {
|
||||
const uint8_t* message;
|
||||
size_t size;
|
||||
const char* sender_tag;
|
||||
};
|
||||
|
||||
void* init_logging();
|
||||
char init_ephemeral();
|
||||
char get_self_address(void (*callback)(const char*));
|
||||
char send_message(const char*, const char*);
|
||||
char listen_for_incoming(void (*callback)(ReceivedMessage));
|
||||
char reply(const char*, const char*);
|
||||
}
|
||||
|
||||
//return code for error handling
|
||||
char return_code = 0;
|
||||
// bytes for sender tag
|
||||
char sender_tag[22];
|
||||
// nym address
|
||||
char addr[134];
|
||||
// test messages
|
||||
char message[14] = "Hello World";
|
||||
char reply_message[14] = "Reply World";
|
||||
|
||||
void string_callback_function(const char* c_string) {
|
||||
std::cout << "(c++) callback received: " << c_string << std::endl;
|
||||
strcpy(addr, c_string);
|
||||
}
|
||||
|
||||
void incoming_message_callback(ReceivedMessage received) {
|
||||
// this is where you deal with the incoming message -
|
||||
// in this case we'll just log it and save sender_tag to a pre-allocated
|
||||
// buffer to reply to the message further down in main()
|
||||
std::cout << "(c++) sender tag: " << received.sender_tag << std::endl;
|
||||
std::cout << "(c++) message: " << received.message << std::endl;
|
||||
std::cout << "(c++) message length : " << received.size << std::endl;
|
||||
const char* incoming_sender_tag = received.sender_tag;
|
||||
strcpy(sender_tag, incoming_sender_tag);
|
||||
}
|
||||
|
||||
// an overly simplified example - handle the error however you wish
|
||||
int handle(char return_code) {
|
||||
if (return_code == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// initialise Nym client logging - this is quite verbose but very informative
|
||||
init_logging();
|
||||
|
||||
// blocking thread example with error return code:
|
||||
// - package fn
|
||||
// - obtain as future
|
||||
// - execute
|
||||
// - get() returned val
|
||||
// - handle val
|
||||
boost::packaged_task<char> init(boost::bind(init_ephemeral));
|
||||
boost::unique_future<char> init_future = init.get_future();
|
||||
init();
|
||||
return_code = init_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// get_self_addr is sync so no thread required: this is the only exposed rust fn that isn't async
|
||||
return_code = get_self_address(string_callback_function);
|
||||
handle(return_code);
|
||||
|
||||
// send a message through the mixnet - in this case to ourselves
|
||||
std::cout << "(c++) message to send through mixnet: " << message << std::endl;
|
||||
boost::packaged_task<char> send(boost::bind(send_message, addr, message));
|
||||
boost::unique_future<char> send_future = send.get_future();
|
||||
send();
|
||||
return_code = send_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// listen out for incoming messages: in the future the client can be split into a listening and a sending client,
|
||||
// allowing for this to run as a persistent process in its own thread and not have to block but instead be running
|
||||
// concurrently
|
||||
boost::packaged_task<char> listen(boost::bind(listen_for_incoming, incoming_message_callback));
|
||||
boost::unique_future<char> listen_future = listen.get_future();
|
||||
listen();
|
||||
return_code = listen_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// replying to incoming message (from ourselves) with SURBs- note that sending a message to a recipient and
|
||||
// replying to an incoming are different functions
|
||||
boost::packaged_task<char> reply_fn(boost::bind(reply, sender_tag, reply_message));
|
||||
boost::unique_future<char> reply_future = reply_fn.get_future();
|
||||
reply_fn();
|
||||
return_code = reply_future.get();
|
||||
handle(return_code);
|
||||
|
||||
// sleep so that the nym side logging can catch up - in reality you'd have another process running to keep logging
|
||||
// going, so this is only necessary for this reference implementation
|
||||
std::this_thread::sleep_for(std::chrono::seconds(40));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,21 +10,27 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
bs58 = "0.4.0"
|
||||
bytes = "1.5.0"
|
||||
clap.workspace = true
|
||||
etherparse = "0.13.0"
|
||||
futures = { workspace = true }
|
||||
lazy_static.workspace = true
|
||||
log = { workspace = true }
|
||||
nym-bin-common = { path = "../../common/bin-common" }
|
||||
nym-client-core = { path = "../../common/client-core" }
|
||||
nym-config = { path = "../../common/config" }
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
nym-exit-policy = { path = "../../common/exit-policy" }
|
||||
nym-ip-packet-requests = { path = "../../common/ip-packet-requests" }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-network-requester = { path = "../network-requester" }
|
||||
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
|
||||
nym-service-providers-common = { path = "../common" }
|
||||
nym-sphinx = { path = "../../common/nymsphinx" }
|
||||
nym-task = { path = "../../common/task" }
|
||||
nym-tun = { path = "../../common/tun" }
|
||||
nym-types = { path = "../../common/types" }
|
||||
nym-wireguard = { path = "../../common/wireguard" }
|
||||
nym-wireguard-types = { path = "../../common/wireguard-types" }
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
use clap::Args;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct BuildInfo {
|
||||
#[arg(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
pub(crate) fn execute(args: BuildInfo) {
|
||||
println!("{}", args.output.format(&bin_info_owned!()))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user