Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f766549e8 | |||
| 98131d1277 | |||
| 42c2d4de7a | |||
| 688ffaf59a | |||
| 270d065661 | |||
| 25d66b5241 | |||
| a5d8a5071f | |||
| 6c51696cfd | |||
| f2196366e1 | |||
| ac22a9d4d9 | |||
| d77bcbb241 | |||
| a6f0fbff3d | |||
| 07e6d7750a | |||
| fcce6b435c | |||
| c7a66fc451 | |||
| 6dc7fc92bd | |||
| 215f927f0d | |||
| 7477337807 | |||
| 44db2b8d71 | |||
| 3260ba84fe | |||
| 89cddc62cc | |||
| fe3b47f103 | |||
| 636bbd9d12 | |||
| 2a338458b9 | |||
| ee2026e53d | |||
| 8f2cb95ffa | |||
| 79ef88dd49 | |||
| 216b32811c | |||
| baf7178dc8 | |||
| 00cdc5010a | |||
| 04bf153701 | |||
| e6eb83f350 | |||
| e8eb031fbd | |||
| 0ce5ba2668 | |||
| e8d601df67 | |||
| ca6b09ce8d | |||
| b8e27c67d9 | |||
| 8dbb72296b | |||
| c2893e5ca0 | |||
| 0489e5aa65 | |||
| eda8b6bf85 | |||
| a1aff09b91 | |||
| 5de218bca9 | |||
| 50960e7bf3 | |||
| 723e729f3b | |||
| 3913e3e56b | |||
| 5f3f97f3be | |||
| fb2b7d3480 | |||
| 7577ec9cb2 | |||
| 1e900c32df | |||
| cb4eaddc9f | |||
| 52151c5fb4 | |||
| 24fe628e15 |
@@ -14,7 +14,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [custom-linux, macos-latest, windows10]
|
||||
os: [custom-ubuntu-20.04, macos-latest, windows10]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
platform: [custom-ubuntu-20.04]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
platform: [custom-ubuntu-20.04]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
runs-on: [self-hosted, custom-runner-linux]
|
||||
runs-on: [self-hosted, custom-ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [custom-runner-linux]
|
||||
platform: [custom-ubuntu-20.04]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
outputs:
|
||||
|
||||
@@ -12,7 +12,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Build APK
|
||||
runs-on: custom-runner-linux
|
||||
runs-on: custom-ubuntu-20.04
|
||||
env:
|
||||
ANDROID_HOME: ${{ github.workspace }}/android-sdk
|
||||
NDK_VERSION: 25.2.9519653
|
||||
|
||||
@@ -4,7 +4,7 @@ on:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: [custom-runner-linux]
|
||||
runs-on: [custom-ubuntu-20.04]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
- add client registry to Gateway ([#3955])
|
||||
- add HTTP API to Gateway ([#3955])
|
||||
- add `/client/<pub-key>`, `clients` and `register` routes to the gateway ([#3955])
|
||||
|
||||
## [2023.1-milka] (2023-09-24)
|
||||
|
||||
|
||||
Generated
+254
-82
@@ -766,7 +766,11 @@ dependencies = [
|
||||
"pin-project-lite 0.2.12",
|
||||
"rustversion",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -789,6 +793,18 @@ dependencies = [
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-macros"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.68"
|
||||
@@ -868,7 +884,7 @@ dependencies = [
|
||||
"pbkdf2",
|
||||
"rand_core 0.6.4",
|
||||
"ripemd",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"subtle 2.4.1",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -1076,7 +1092,7 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896"
|
||||
dependencies = [
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1739,7 +1755,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde-json-wasm",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@@ -2095,6 +2111,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"curve25519-dalek-derive",
|
||||
"digest 0.10.7",
|
||||
"fiat-crypto",
|
||||
"platforms",
|
||||
"rustc_version 0.4.0",
|
||||
@@ -2690,6 +2707,20 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-dalek"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"
|
||||
dependencies = [
|
||||
"curve25519-dalek 4.1.0",
|
||||
"ed25519 2.2.2",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"sha2 0.10.8",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ed25519-zebra"
|
||||
version = "3.1.0"
|
||||
@@ -2852,7 +2883,7 @@ dependencies = [
|
||||
"libp2p 0.51.3",
|
||||
"libp2p-identity",
|
||||
"log",
|
||||
"lru 0.10.0",
|
||||
"lru 0.10.1",
|
||||
"nym-config",
|
||||
"nym-ephemera-common",
|
||||
"nym-task",
|
||||
@@ -2975,7 +3006,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "extension-storage"
|
||||
version = "1.2.0"
|
||||
version = "1.2.0-rc.10"
|
||||
dependencies = [
|
||||
"bip39",
|
||||
"console_error_panic_hook",
|
||||
@@ -3831,6 +3862,20 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-api-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"url",
|
||||
"wasmtimer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
@@ -3842,6 +3887,12 @@ dependencies = [
|
||||
"pin-project-lite 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range-header"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
@@ -4093,6 +4144,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4228,7 +4280,7 @@ dependencies = [
|
||||
"socket2 0.4.9",
|
||||
"widestring",
|
||||
"winapi",
|
||||
"winreg",
|
||||
"winreg 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4365,7 +4417,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4378,7 +4430,7 @@ dependencies = [
|
||||
"ecdsa 0.16.8",
|
||||
"elliptic-curve 0.13.5",
|
||||
"once_cell",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"signature 2.1.0",
|
||||
]
|
||||
|
||||
@@ -4594,7 +4646,7 @@ source = "git+https://github.com/ChainSafe/rust-libp2p.git?rev=e3440d25681df380c
|
||||
dependencies = [
|
||||
"asn1_der",
|
||||
"bs58 0.4.0",
|
||||
"ed25519-dalek",
|
||||
"ed25519-dalek 1.0.1",
|
||||
"either",
|
||||
"fnv",
|
||||
"futures",
|
||||
@@ -4612,7 +4664,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rw-stream-sink 0.3.0 (git+https://github.com/ChainSafe/rust-libp2p.git?rev=e3440d25681df380c9f0f8cfdcfd5ecc0a4f2fb6)",
|
||||
"sec1 0.3.0",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"unsigned-varint",
|
||||
@@ -4698,7 +4750,7 @@ dependencies = [
|
||||
"prost-codec",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"unsigned-varint",
|
||||
@@ -4730,7 +4782,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"serde",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"unsigned-varint",
|
||||
@@ -4761,19 +4813,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libp2p-identity"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1"
|
||||
checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce"
|
||||
dependencies = [
|
||||
"bs58 0.4.0",
|
||||
"ed25519-dalek",
|
||||
"ed25519-dalek 2.0.0",
|
||||
"log",
|
||||
"multiaddr 0.17.1",
|
||||
"multihash",
|
||||
"quick-protobuf",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4799,7 +4851,7 @@ dependencies = [
|
||||
"quick-protobuf",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"uint",
|
||||
@@ -4904,7 +4956,7 @@ dependencies = [
|
||||
"prost",
|
||||
"prost-build",
|
||||
"rand 0.8.5",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"snow",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
@@ -4927,7 +4979,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"quick-protobuf",
|
||||
"rand 0.8.5",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"snow",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
@@ -5368,9 +5420,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e"
|
||||
checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670"
|
||||
dependencies = [
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
@@ -5517,15 +5569,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mix-fetch-wasm"
|
||||
version = "1.2.0"
|
||||
version = "1.2.0-rc.10"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
"http-api-client",
|
||||
"js-sys",
|
||||
"nym-ordered-buffer",
|
||||
"nym-service-providers-common",
|
||||
"nym-socks5-requests",
|
||||
"rand 0.7.3",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"thiserror",
|
||||
@@ -5616,7 +5669,7 @@ dependencies = [
|
||||
"multihash-derive",
|
||||
"serde",
|
||||
"serde-big-array",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"unsigned-varint",
|
||||
]
|
||||
|
||||
@@ -5952,6 +6005,7 @@ dependencies = [
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-multisig-contract-common",
|
||||
"nym-name-service-common",
|
||||
"nym-node-requests",
|
||||
"nym-node-tester-utils",
|
||||
"nym-pemstore",
|
||||
"nym-service-provider-directory-common",
|
||||
@@ -5962,7 +6016,6 @@ dependencies = [
|
||||
"nym-vesting-contract-common",
|
||||
"okapi",
|
||||
"pin-project",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
@@ -5996,6 +6049,7 @@ dependencies = [
|
||||
"getset",
|
||||
"nym-coconut-interface",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-node-requests",
|
||||
"schemars",
|
||||
"serde",
|
||||
"ts-rs",
|
||||
@@ -6029,12 +6083,14 @@ dependencies = [
|
||||
"opentelemetry",
|
||||
"opentelemetry-jaeger",
|
||||
"pretty_env_logger",
|
||||
"schemars",
|
||||
"semver 0.11.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
"utoipa",
|
||||
"vergen",
|
||||
]
|
||||
|
||||
@@ -6193,7 +6249,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"sqlx 0.6.3",
|
||||
"tap",
|
||||
"tempfile",
|
||||
@@ -6213,7 +6269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client-wasm"
|
||||
version = "1.2.0"
|
||||
version = "1.2.0-rc.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
@@ -6374,7 +6430,7 @@ dependencies = [
|
||||
"cipher 0.4.4",
|
||||
"ctr 0.9.2",
|
||||
"digest 0.10.7",
|
||||
"ed25519-dalek",
|
||||
"ed25519-dalek 1.0.1",
|
||||
"generic-array 0.14.7",
|
||||
"hkdf 0.12.3",
|
||||
"hmac 0.12.1",
|
||||
@@ -6463,6 +6519,9 @@ dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"atty",
|
||||
"axum",
|
||||
"axum-macros",
|
||||
"base64 0.21.4",
|
||||
"bip39",
|
||||
"bs58 0.4.0",
|
||||
"clap 4.3.21",
|
||||
@@ -6470,8 +6529,11 @@ dependencies = [
|
||||
"dashmap",
|
||||
"dirs 4.0.0",
|
||||
"dotenvy",
|
||||
"fastrand 2.0.0",
|
||||
"futures",
|
||||
"hmac 0.12.1",
|
||||
"humantime-serde",
|
||||
"hyper",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -6485,6 +6547,7 @@ dependencies = [
|
||||
"nym-mixnode-common",
|
||||
"nym-network-defaults",
|
||||
"nym-network-requester",
|
||||
"nym-node",
|
||||
"nym-pemstore",
|
||||
"nym-sphinx",
|
||||
"nym-statistics-common",
|
||||
@@ -6495,8 +6558,10 @@ dependencies = [
|
||||
"once_cell",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"sqlx 0.5.11",
|
||||
"subtle-encoding",
|
||||
"thiserror",
|
||||
@@ -6504,7 +6569,9 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"url",
|
||||
"x25519-dalek 2.0.0",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -6572,21 +6639,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-http-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytecodec",
|
||||
"bytes",
|
||||
"http",
|
||||
"httpcodec",
|
||||
"nym-ordered-buffer",
|
||||
"nym-service-providers-common",
|
||||
"nym-socks5-requests",
|
||||
"thiserror",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-inclusion-probability"
|
||||
version = "0.1.0"
|
||||
@@ -6811,6 +6863,57 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-node"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
"bytes",
|
||||
"colored",
|
||||
"fastrand 2.0.0",
|
||||
"hmac 0.12.1",
|
||||
"hyper",
|
||||
"mime",
|
||||
"nym-config",
|
||||
"nym-crypto",
|
||||
"nym-node-requests",
|
||||
"nym-task",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
"x25519-dalek 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.21.4",
|
||||
"hmac 0.12.1",
|
||||
"http-api-client",
|
||||
"nym-bin-common",
|
||||
"nym-crypto",
|
||||
"rand 0.7.3",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"utoipa",
|
||||
"x25519-dalek 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-tester-utils"
|
||||
version = "0.1.0"
|
||||
@@ -6832,7 +6935,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-node-tester-wasm"
|
||||
version = "1.2.0"
|
||||
version = "1.2.0-rc.10"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
@@ -7300,6 +7403,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"bs58 0.4.0",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
"nym-bin-common",
|
||||
"nym-config",
|
||||
"nym-crypto",
|
||||
@@ -7360,6 +7464,7 @@ dependencies = [
|
||||
"eyre",
|
||||
"flate2",
|
||||
"futures",
|
||||
"http-api-client",
|
||||
"itertools",
|
||||
"log",
|
||||
"nym-api-requests",
|
||||
@@ -7426,7 +7531,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-wasm-sdk"
|
||||
version = "1.2.0"
|
||||
version = "1.2.0-rc.10"
|
||||
dependencies = [
|
||||
"mix-fetch-wasm",
|
||||
"nym-client-wasm",
|
||||
@@ -7444,6 +7549,8 @@ dependencies = [
|
||||
"dashmap",
|
||||
"etherparse",
|
||||
"futures",
|
||||
"ip_network",
|
||||
"ip_network_table",
|
||||
"log",
|
||||
"nym-task",
|
||||
"tap",
|
||||
@@ -7694,7 +7801,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
|
||||
dependencies = [
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7705,7 +7812,7 @@ checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
|
||||
dependencies = [
|
||||
"ecdsa 0.14.8",
|
||||
"elliptic-curve 0.12.3",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7939,7 +8046,7 @@ checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8684,9 +8791,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "refinery"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb0436d0dd7bd8d4fce1e828751fa79742b08e35f27cfea7546f8a322b5ef24"
|
||||
checksum = "529664dbccc0a296947615c997a857912d72d1c44be1fafb7bae54ecfa7a8c24"
|
||||
dependencies = [
|
||||
"refinery-core",
|
||||
"refinery-macros",
|
||||
@@ -8694,9 +8801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "refinery-core"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19206547cd047e8f4dfa6b20c30d3ecaf24be05841b6aa0aa926a47a3d0662bb"
|
||||
checksum = "e895cb870cf06e92318cbbeb701f274d022d5ca87a16fa8244e291cd035ef954"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
@@ -8715,9 +8822,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "refinery-macros"
|
||||
version = "0.8.10"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d94d4b9241859ba19eaa5c04c86e782eb3aa0aae2c5868e0cfa90c856e58a174"
|
||||
checksum = "123e8b80f8010c3ae38330c81e76938fc7adf6cdbfbaad20295bb8c22718b4f1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -8772,9 +8879,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.18"
|
||||
version = "0.11.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||
dependencies = [
|
||||
"base64 0.21.4",
|
||||
"bytes",
|
||||
@@ -8797,6 +8904,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-socks",
|
||||
@@ -8805,7 +8913,7 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
"winreg 0.50.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9075,7 +9183,7 @@ version = "7.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512b0ab6853f7e14e3c8754acb43d6f748bb9ced66aa5915a6553ac8213f7731"
|
||||
dependencies = [
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -9569,6 +9677,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.16"
|
||||
@@ -9601,6 +9719,19 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.8"
|
||||
@@ -9640,9 +9771,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.7"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
@@ -9719,9 +9850,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
checksum = "54ac45299ccbd390721be55b412d41931911f654fa99e2cb8bfb57184b2061fe"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
@@ -9796,7 +9927,7 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
"ring",
|
||||
"rustc_version 0.4.0",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
@@ -9982,7 +10113,7 @@ dependencies = [
|
||||
"paste",
|
||||
"percent-encoding",
|
||||
"rustls 0.19.1",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"sqlformat 0.1.8",
|
||||
"sqlx-rt 0.5.13",
|
||||
@@ -10030,7 +10161,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rustls 0.20.8",
|
||||
"rustls-pemfile",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"smallvec",
|
||||
"sqlformat 0.2.1",
|
||||
"sqlx-rt 0.6.3",
|
||||
@@ -10053,7 +10184,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"sqlx-core 0.5.13",
|
||||
"sqlx-rt 0.5.13",
|
||||
"syn 1.0.109",
|
||||
@@ -10072,7 +10203,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"sqlx-core 0.6.3",
|
||||
"sqlx-rt 0.6.3",
|
||||
"syn 1.0.109",
|
||||
@@ -10374,7 +10505,7 @@ dependencies = [
|
||||
"serde_bytes",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"signature 2.1.0",
|
||||
"subtle 2.4.1",
|
||||
"subtle-encoding",
|
||||
@@ -10477,18 +10608,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.44"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
|
||||
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.44"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
|
||||
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10847,6 +10978,31 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-range-header",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite 0.2.12",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.2"
|
||||
@@ -11278,6 +11434,12 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||
|
||||
[[package]]
|
||||
name = "unsigned-varint"
|
||||
version = "0.7.1"
|
||||
@@ -11357,11 +11519,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "3.3.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ae74ef183fae36d650f063ae7bde1cacbe1cd7e72b617cbe1e985551878b98"
|
||||
checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a"
|
||||
dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"utoipa-gen",
|
||||
@@ -11369,11 +11531,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "3.3.0"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ea8ac818da7e746a63285594cce8a96f5e00ee31994e655bd827569cb8b137b"
|
||||
checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -11383,11 +11544,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "3.1.3"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "062bba5a3568e126ac72049a63254f4cb1da2eb713db0c1ab2a4c76be191db8c"
|
||||
checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"axum",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
@@ -11762,7 +11924,7 @@ dependencies = [
|
||||
"sdp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"stun",
|
||||
"thiserror",
|
||||
"time",
|
||||
@@ -11825,7 +11987,7 @@ dependencies = [
|
||||
"sec1 0.3.0",
|
||||
"serde",
|
||||
"sha1",
|
||||
"sha2 0.10.7",
|
||||
"sha2 0.10.8",
|
||||
"signature 1.6.4",
|
||||
"subtle 2.4.1",
|
||||
"thiserror",
|
||||
@@ -12198,6 +12360,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "with_builtin_macros"
|
||||
version = "0.0.3"
|
||||
|
||||
+12
-3
@@ -46,7 +46,7 @@ members = [
|
||||
"common/crypto",
|
||||
"common/dkg",
|
||||
"common/execute",
|
||||
"common/http-requests",
|
||||
"common/http-api-client",
|
||||
"common/inclusion-probability",
|
||||
"common/ledger",
|
||||
"common/mixnode-common",
|
||||
@@ -93,6 +93,8 @@ members = [
|
||||
"nym-api",
|
||||
"nym-browser-extension/storage",
|
||||
"nym-api/nym-api-requests",
|
||||
"nym-node",
|
||||
"nym-node/nym-node-requests",
|
||||
"nym-outfox",
|
||||
"tools/internal/ssl-inject",
|
||||
"tools/internal/sdk-version-bump",
|
||||
@@ -129,6 +131,8 @@ license = "Apache-2.0"
|
||||
[workspace.dependencies]
|
||||
anyhow = "1.0.71"
|
||||
async-trait = "0.1.68"
|
||||
axum = "0.6.20"
|
||||
base64 = "0.21.4"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
cosmwasm-derive = "=1.3.0"
|
||||
@@ -151,22 +155,27 @@ dotenvy = "0.15.6"
|
||||
futures = "0.3.28"
|
||||
generic-array = "0.14.7"
|
||||
getrandom = "0.2.10"
|
||||
hyper = "0.14.27"
|
||||
k256 = "0.13"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
reqwest = "0.11.18"
|
||||
reqwest = "0.11.22"
|
||||
schemars = "0.8.1"
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
tap = "1.0.1"
|
||||
tendermint-rpc = "0.32" # same version as used by cosmrs
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.48"
|
||||
tokio = "1.24.1"
|
||||
tokio-tungstenite = "0.20.1"
|
||||
tracing = "0.1.37"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
ts-rs = "7.0.0"
|
||||
utoipa = "3.5.0"
|
||||
utoipa-swagger-ui = "3.1.5"
|
||||
url = "2.4"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
bip39 = { workspace = true }
|
||||
rand = "0.7.3"
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
nym-coconut-interface = { path = "../coconut-interface" }
|
||||
|
||||
@@ -15,6 +15,7 @@ clap_complete_fig = "4.0"
|
||||
log = { workspace = true }
|
||||
pretty_env_logger = "0.4.0"
|
||||
semver = "0.11"
|
||||
schemars = { workspace = true, features = ["preserve_order"], optional = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
|
||||
@@ -29,6 +30,7 @@ opentelemetry-jaeger = { version = "0.18.0", optional = true, features = [
|
||||
"isahc_collector_client",
|
||||
] }
|
||||
tracing-opentelemetry = { version = "0.19.0", optional = true }
|
||||
utoipa = { workspace = true, optional = true }
|
||||
opentelemetry = { version = "0.19.0", optional = true, features = ["rt-tokio"] }
|
||||
|
||||
|
||||
@@ -42,7 +44,9 @@ vergen = { version = "=7.4.3", default-features = false, features = [
|
||||
|
||||
[features]
|
||||
default = []
|
||||
openapi = ["utoipa"]
|
||||
output_format = ["serde_json"]
|
||||
bin_info_schema = ["schemars"]
|
||||
tracing = [
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
|
||||
@@ -81,6 +81,8 @@ impl BinaryBuildInformation {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
#[cfg_attr(feature = "bin_info_schema", derive(schemars::JsonSchema))]
|
||||
pub struct BinaryBuildInformationOwned {
|
||||
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
|
||||
pub binary_name: String,
|
||||
|
||||
@@ -69,7 +69,7 @@ impl NymApiTopologyProvider {
|
||||
Ok(mixes) => mixes,
|
||||
};
|
||||
|
||||
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||
let gateways = match self.validator_client.get_cached_described_gateways().await {
|
||||
Err(err) => {
|
||||
error!("failed to get network gateways - {err}");
|
||||
return None;
|
||||
|
||||
@@ -280,29 +280,24 @@ impl GatewayEndpointConfig {
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)
|
||||
}
|
||||
|
||||
pub fn from_node(node: nym_topology::gateway::Node, use_tls: bool) -> Self {
|
||||
// TODO: in the future this shall return a Result and explicit `use_tls` will be removed in favour of the tls info being available on the struct
|
||||
if use_tls {
|
||||
Self::from_topology_node_tls(node)
|
||||
pub fn from_node(
|
||||
node: nym_topology::gateway::Node,
|
||||
must_use_tls: bool,
|
||||
) -> Result<Self, ClientCoreError> {
|
||||
let gateway_listener = if must_use_tls {
|
||||
node.clients_address_tls()
|
||||
.ok_or(ClientCoreError::UnsupportedWssProtocol {
|
||||
gateway: node.identity_key.to_base58_string(),
|
||||
})?
|
||||
} else {
|
||||
Self::from_topology_node_no_tls(node)
|
||||
}
|
||||
}
|
||||
node.clients_address()
|
||||
};
|
||||
|
||||
pub fn from_topology_node_no_tls(node: nym_topology::gateway::Node) -> Self {
|
||||
GatewayEndpointConfig {
|
||||
Ok(GatewayEndpointConfig {
|
||||
gateway_id: node.identity_key.to_base58_string(),
|
||||
gateway_listener: node.clients_address(),
|
||||
gateway_listener,
|
||||
gateway_owner: node.owner,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_topology_node_tls(node: nym_topology::gateway::Node) -> Self {
|
||||
GatewayEndpointConfig {
|
||||
gateway_id: node.identity_key.to_base58_string(),
|
||||
gateway_listener: node.clients_address_tls(),
|
||||
gateway_owner: node.owner,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,12 @@ pub enum ClientCoreError {
|
||||
|
||||
#[error("this client has performed gateway initialisation in another session")]
|
||||
NoInitClientPresent,
|
||||
|
||||
#[error("there are no gateways supporting the wss protocol available")]
|
||||
NoWssGateways,
|
||||
|
||||
#[error("the specified gateway '{gateway}' does not support the wss protocol")]
|
||||
UnsupportedWssProtocol { gateway: String },
|
||||
}
|
||||
|
||||
/// Set of messages that the client can send to listeners via the task manager
|
||||
|
||||
@@ -174,7 +174,10 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
let gateways = filter_by_tls(gateways, must_use_tls)?;
|
||||
|
||||
info!(
|
||||
"choosing gateway by latency, pinging {} gateways ...",
|
||||
gateways.len()
|
||||
@@ -210,28 +213,57 @@ pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
Ok(chosen.gateway.clone())
|
||||
}
|
||||
|
||||
fn filter_by_tls(
|
||||
gateways: &[gateway::Node],
|
||||
must_use_tls: bool,
|
||||
) -> Result<Vec<&gateway::Node>, ClientCoreError> {
|
||||
if must_use_tls {
|
||||
let filtered = gateways
|
||||
.iter()
|
||||
.filter(|g| g.clients_wss_port.is_some())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if filtered.is_empty() {
|
||||
return Err(ClientCoreError::NoWssGateways);
|
||||
}
|
||||
|
||||
Ok(filtered)
|
||||
} else {
|
||||
Ok(gateways.iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn uniformly_random_gateway<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
gateways
|
||||
filter_by_tls(gateways, must_use_tls)?
|
||||
.choose(rng)
|
||||
.ok_or(ClientCoreError::NoGatewaysOnNetwork)
|
||||
.cloned()
|
||||
.map(|&r| r.clone())
|
||||
}
|
||||
|
||||
pub(super) fn get_specified_gateway(
|
||||
gateway_identity: IdentityKeyRef,
|
||||
gateways: &[gateway::Node],
|
||||
must_use_tls: bool,
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
let user_gateway = identity::PublicKey::from_base58_string(gateway_identity)
|
||||
.map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?;
|
||||
|
||||
gateways
|
||||
let gateway = gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key == user_gateway)
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_identity.to_string()))
|
||||
.cloned()
|
||||
.ok_or_else(|| ClientCoreError::NoGatewayWithId(gateway_identity.to_string()))?;
|
||||
|
||||
if must_use_tls && gateway.clients_wss_port.is_none() {
|
||||
return Err(ClientCoreError::UnsupportedWssProtocol {
|
||||
gateway: gateway_identity.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(gateway.clone())
|
||||
}
|
||||
|
||||
pub(super) async fn register_with_gateway(
|
||||
|
||||
@@ -108,19 +108,20 @@ where
|
||||
|
||||
let gateway_details = match selection_specification {
|
||||
GatewaySelectionSpecification::UniformRemote { must_use_tls } => {
|
||||
let gateway = uniformly_random_gateway(&mut rng, &available_gateways)?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
|
||||
let gateway = uniformly_random_gateway(&mut rng, &available_gateways, must_use_tls)?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?)
|
||||
}
|
||||
GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => {
|
||||
let gateway = choose_gateway_by_latency(&mut rng, &available_gateways).await?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
|
||||
let gateway =
|
||||
choose_gateway_by_latency(&mut rng, &available_gateways, must_use_tls).await?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?)
|
||||
}
|
||||
GatewaySelectionSpecification::Specified {
|
||||
must_use_tls,
|
||||
identity,
|
||||
} => {
|
||||
let gateway = get_specified_gateway(&identity, &available_gateways)?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls))
|
||||
let gateway = get_specified_gateway(&identity, &available_gateways, must_use_tls)?;
|
||||
GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?)
|
||||
}
|
||||
GatewaySelectionSpecification::Custom {
|
||||
gateway_identity,
|
||||
|
||||
@@ -24,6 +24,7 @@ nym-service-provider-directory-common = { path = "../../cosmwasm-smart-contracts
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
http-api-client = { path = "../../../common/http-api-client"}
|
||||
thiserror = { workspace = true }
|
||||
log = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
@@ -86,4 +87,5 @@ required-features = ["http-client"]
|
||||
default = ["http-client"]
|
||||
http-client = ["cosmrs/rpc", "openssl"]
|
||||
generate-ts = []
|
||||
contract-testing = ["nym-mixnet-contract-common/contract-testing"]
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::MixNodeBondAnnotated;
|
||||
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
|
||||
use nym_api_requests::models::{
|
||||
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
|
||||
RewardEstimationResponse, StakeSaturationResponse,
|
||||
@@ -19,6 +19,7 @@ use nym_api_requests::models::{
|
||||
use nym_network_defaults::NymNetworkDetails;
|
||||
use url::Url;
|
||||
|
||||
pub use crate::nym_api::NymApiClientExt;
|
||||
pub use nym_mixnet_contract_common::{
|
||||
mixnode::MixNodeDetails, GatewayBond, IdentityKey, IdentityKeyRef, MixId,
|
||||
};
|
||||
@@ -147,7 +148,7 @@ impl Client<ReqwestRpcClient> {
|
||||
|
||||
impl<C> Client<C> {
|
||||
pub fn new_with_rpc_client(config: Config, rpc_client: C) -> Self {
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone(), None);
|
||||
|
||||
Client {
|
||||
nym_api: nym_api_client,
|
||||
@@ -161,7 +162,7 @@ impl<C, S> Client<C, S> {
|
||||
where
|
||||
S: OfflineSigner,
|
||||
{
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone());
|
||||
let nym_api_client = nym_api::Client::new(config.api_url.clone(), None);
|
||||
|
||||
Client {
|
||||
nym_api: nym_api_client,
|
||||
@@ -177,7 +178,7 @@ impl<C, S> Client<C, S> {
|
||||
}
|
||||
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint)
|
||||
self.nym_api.change_base_url(new_endpoint)
|
||||
}
|
||||
|
||||
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
|
||||
@@ -241,7 +242,7 @@ pub struct NymApiClient {
|
||||
|
||||
impl NymApiClient {
|
||||
pub fn new(api_url: Url) -> Self {
|
||||
let nym_api = nym_api::Client::new(api_url);
|
||||
let nym_api = nym_api::Client::new(api_url, None);
|
||||
|
||||
NymApiClient { nym_api }
|
||||
}
|
||||
@@ -251,7 +252,7 @@ impl NymApiClient {
|
||||
}
|
||||
|
||||
pub fn change_nym_api(&mut self, new_endpoint: Url) {
|
||||
self.nym_api.change_url(new_endpoint);
|
||||
self.nym_api.change_base_url(new_endpoint);
|
||||
}
|
||||
|
||||
pub async fn get_cached_active_mixnodes(
|
||||
@@ -274,6 +275,12 @@ impl NymApiClient {
|
||||
Ok(self.nym_api.get_gateways().await?)
|
||||
}
|
||||
|
||||
pub async fn get_cached_described_gateways(
|
||||
&self,
|
||||
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
|
||||
Ok(self.nym_api.get_gateways_described().await?)
|
||||
}
|
||||
|
||||
pub async fn get_gateway_core_status_count(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use http_api_client::HttpClientError;
|
||||
use nym_api_requests::models::RequestError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NymAPIError {
|
||||
#[error("There was an issue with the REST request - {source}")]
|
||||
ReqwestClientError {
|
||||
#[from]
|
||||
source: reqwest::Error,
|
||||
},
|
||||
|
||||
#[error("Not found")]
|
||||
NotFound,
|
||||
|
||||
#[error("Request failed with error message - {0}")]
|
||||
GenericRequestFailure(String),
|
||||
|
||||
#[error("The nym API has failed to resolve our request. It returned status code {status} and additional error message: {}", error.message())]
|
||||
ApiRequestFailure { status: u16, error: RequestError },
|
||||
}
|
||||
pub type NymAPIError = HttpClientError<RequestError>;
|
||||
|
||||
@@ -3,140 +3,38 @@
|
||||
|
||||
use crate::nym_api::error::NymAPIError;
|
||||
use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use async_trait::async_trait;
|
||||
use http_api_client::{ApiClient, NO_PARAMS};
|
||||
use nym_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use nym_api_requests::models::{
|
||||
ComputeRewardEstParam, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
|
||||
GatewayStatusReportResponse, GatewayUptimeHistoryResponse, InclusionProbabilityResponse,
|
||||
MixNodeBondAnnotated, MixnodeCoreStatusResponse, MixnodeStatusReportResponse,
|
||||
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse,
|
||||
MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RewardEstimationResponse,
|
||||
StakeSaturationResponse, UptimeResponse,
|
||||
};
|
||||
use nym_mixnet_contract_common::mixnode::MixNodeDetails;
|
||||
use nym_mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
|
||||
use nym_name_service_common::response::NamesListResponse;
|
||||
use nym_service_provider_directory_common::response::ServicesListResponse;
|
||||
use reqwest::{Response, StatusCode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
pub mod error;
|
||||
pub mod routes;
|
||||
|
||||
type PathSegments<'a> = &'a [&'a str];
|
||||
type Params<'a, K, V> = &'a [(K, V)];
|
||||
pub use http_api_client::Client;
|
||||
|
||||
const NO_PARAMS: Params<'_, &'_ str, &'_ str> = &[];
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
url: Url,
|
||||
reqwest_client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn new(url: Url) -> Self {
|
||||
let reqwest_client = reqwest::Client::new();
|
||||
Self {
|
||||
url,
|
||||
reqwest_client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_url(&mut self, new_url: Url) {
|
||||
self.url = new_url
|
||||
}
|
||||
|
||||
pub fn current_url(&self) -> &Url {
|
||||
&self.url
|
||||
}
|
||||
|
||||
async fn send_get_request<K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<Response, NymAPIError>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let url = create_api_url(&self.url, path, params);
|
||||
Ok(self.reqwest_client.get(url).send().await?)
|
||||
}
|
||||
|
||||
async fn query_nym_api<T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let res = self.send_get_request(path, params).await?;
|
||||
if res.status().is_success() {
|
||||
Ok(res.json().await?)
|
||||
} else if res.status() == StatusCode::NOT_FOUND {
|
||||
Err(NymAPIError::NotFound)
|
||||
} else {
|
||||
Err(NymAPIError::GenericRequestFailure(res.text().await?))
|
||||
}
|
||||
}
|
||||
|
||||
// This works for endpoints returning Result<Json<T>, ErrorResponse>
|
||||
async fn query_nym_api_fallible<T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let res = self.send_get_request(path, params).await?;
|
||||
let status = res.status();
|
||||
if res.status().is_success() {
|
||||
Ok(res.json().await?)
|
||||
} else {
|
||||
let request_error: RequestError = res.json().await?;
|
||||
Err(NymAPIError::ApiRequestFailure {
|
||||
status: status.as_u16(),
|
||||
error: request_error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn post_nym_api<B, T, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, NymAPIError>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let url = create_api_url(&self.url, path, params);
|
||||
let response = self.reqwest_client.post(url).json(json_body).send().await?;
|
||||
if response.status().is_success() {
|
||||
Ok(response.json().await?)
|
||||
} else {
|
||||
Err(NymAPIError::GenericRequestFailure(response.text().await?))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait NymApiClientExt: ApiClient {
|
||||
async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.get_json(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -148,8 +46,8 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
async fn get_gateways_detailed(&self) -> Result<Vec<GatewayBondAnnotated>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -161,10 +59,10 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes_detailed_unfiltered(
|
||||
async fn get_mixnodes_detailed_unfiltered(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -176,23 +74,29 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
|
||||
async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
|
||||
self.get_json(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_active_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
async fn get_active_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -205,19 +109,19 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
|
||||
self.get_json(
|
||||
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_report(
|
||||
async fn get_mixnode_report(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -230,11 +134,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateway_report(
|
||||
async fn get_gateway_report(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<GatewayStatusReportResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -247,11 +151,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_history(
|
||||
async fn get_mixnode_history(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -264,11 +168,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateway_history(
|
||||
async fn get_gateway_history(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
) -> Result<GatewayUptimeHistoryResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -281,10 +185,10 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_rewarded_mixnodes_detailed(
|
||||
async fn get_rewarded_mixnodes_detailed(
|
||||
&self,
|
||||
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS,
|
||||
@@ -297,13 +201,13 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_gateway_core_status_count(
|
||||
async fn get_gateway_core_status_count(
|
||||
&self,
|
||||
identity: IdentityKeyRef<'_>,
|
||||
since: Option<i64>,
|
||||
) -> Result<GatewayCoreStatusResponse, NymAPIError> {
|
||||
if let Some(since) = since {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -315,7 +219,7 @@ impl Client {
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -328,13 +232,13 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_core_status_count(
|
||||
async fn get_mixnode_core_status_count(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
since: Option<i64>,
|
||||
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
|
||||
if let Some(since) = since {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -346,7 +250,7 @@ impl Client {
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -360,11 +264,11 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_status(
|
||||
async fn get_mixnode_status(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<MixnodeStatusResponse, NymAPIError> {
|
||||
self.query_nym_api(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -377,11 +281,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_reward_estimation(
|
||||
async fn get_mixnode_reward_estimation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<RewardEstimationResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -394,12 +298,12 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn compute_mixnode_reward_estimation(
|
||||
async fn compute_mixnode_reward_estimation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
request_body: &ComputeRewardEstParam,
|
||||
) -> Result<RewardEstimationResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -413,11 +317,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_stake_saturation(
|
||||
async fn get_mixnode_stake_saturation(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<StakeSaturationResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -430,11 +334,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_inclusion_probability(
|
||||
async fn get_mixnode_inclusion_probability(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<InclusionProbabilityResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -447,11 +351,8 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_mixnode_avg_uptime(
|
||||
&self,
|
||||
mix_id: MixId,
|
||||
) -> Result<UptimeResponse, NymAPIError> {
|
||||
self.query_nym_api_fallible(
|
||||
async fn get_mixnode_avg_uptime(&self, mix_id: MixId) -> Result<UptimeResponse, NymAPIError> {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::STATUS_ROUTES,
|
||||
@@ -464,11 +365,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn blind_sign(
|
||||
async fn blind_sign(
|
||||
&self,
|
||||
request_body: &BlindSignRequestBody,
|
||||
) -> Result<BlindedSignatureResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
@@ -481,11 +382,11 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn verify_bandwidth_credential(
|
||||
async fn verify_bandwidth_credential(
|
||||
&self,
|
||||
request_body: &VerifyCredentialBody,
|
||||
) -> Result<VerifyCredentialResponse, NymAPIError> {
|
||||
self.post_nym_api(
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
@@ -498,118 +399,20 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_service_providers(&self) -> Result<ServicesListResponse, NymAPIError> {
|
||||
async fn get_service_providers(&self) -> Result<ServicesListResponse, NymAPIError> {
|
||||
log::trace!("Getting service providers");
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::SERVICE_PROVIDERS], NO_PARAMS)
|
||||
self.get_json(&[routes::API_VERSION, routes::SERVICE_PROVIDERS], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
|
||||
//pub async fn get_registered_names(&self) -> Result<Vec<NameEntry>, NymAPIError> {
|
||||
pub async fn get_registered_names(&self) -> Result<NamesListResponse, NymAPIError> {
|
||||
//async fn get_registered_names(&self) -> Result<Vec<NameEntry>, NymAPIError> {
|
||||
async fn get_registered_names(&self) -> Result<NamesListResponse, NymAPIError> {
|
||||
log::trace!("Getting registered names");
|
||||
self.query_nym_api(&[routes::API_VERSION, routes::REGISTERED_NAMES], NO_PARAMS)
|
||||
self.get_json(&[routes::API_VERSION, routes::REGISTERED_NAMES], NO_PARAMS)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
// utility function that should solve the double slash problem in validator API forever.
|
||||
fn create_api_url<K: AsRef<str>, V: AsRef<str>>(
|
||||
base: &Url,
|
||||
segments: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Url {
|
||||
let mut url = base.clone();
|
||||
let mut path_segments = url
|
||||
.path_segments_mut()
|
||||
.expect("provided validator url does not have a base!");
|
||||
for segment in segments {
|
||||
let segment = segment.strip_prefix('/').unwrap_or(segment);
|
||||
let segment = segment.strip_suffix('/').unwrap_or(segment);
|
||||
|
||||
path_segments.push(segment);
|
||||
}
|
||||
// I don't understand why compiler couldn't figure out that it's no longer used
|
||||
// and can be dropped
|
||||
drop(path_segments);
|
||||
|
||||
if !params.is_empty() {
|
||||
url.query_pairs_mut().extend_pairs(params);
|
||||
}
|
||||
|
||||
url
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn creating_api_path() {
|
||||
let base_url: Url = "http://foomp.com".parse().unwrap();
|
||||
|
||||
// works with 1 segment
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
create_api_url(&base_url, &["foo"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with 2 segments
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["foo", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with leading slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
create_api_url(&base_url, &["/foo"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["/foo", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["foo", "/bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with trailing slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
create_api_url(&base_url, &["foo/"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["foo/", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["foo", "bar/"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with both leading and trailing slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
create_api_url(&base_url, &["/foo/"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
create_api_url(&base_url, &["/foo/", "/bar/"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// adds params
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar?foomp=baz",
|
||||
create_api_url(&base_url, &["foo", "bar"], &[("foomp", "baz")]).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar?arg1=val1&arg2=val2",
|
||||
create_api_url(
|
||||
&base_url,
|
||||
&["/foo/", "/bar/"],
|
||||
&[("arg1", "val1"), ("arg2", "val2")]
|
||||
)
|
||||
.as_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl NymApiClientExt for Client {}
|
||||
|
||||
@@ -6,6 +6,7 @@ use nym_network_defaults::NYM_API_VERSION;
|
||||
pub const API_VERSION: &str = NYM_API_VERSION;
|
||||
pub const MIXNODES: &str = "mixnodes";
|
||||
pub const GATEWAYS: &str = "gateways";
|
||||
pub const DESCRIBED: &str = "described";
|
||||
|
||||
pub const DETAILED: &str = "detailed";
|
||||
pub const DETAILED_UNFILTERED: &str = "detailed-unfiltered";
|
||||
|
||||
+5
-4
@@ -683,13 +683,14 @@ pub trait MixnetSigningClient {
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
|
||||
#[cfg(feature = "contract-testing")]
|
||||
async fn testing_resolve_all_pending_events(
|
||||
&self,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<ExecuteResult, NyxdError> {
|
||||
self.execute_mixnet_contract(
|
||||
fee,
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents {},
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents { limit: None },
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
@@ -928,8 +929,8 @@ mod tests {
|
||||
.withdraw_delegator_reward_on_behalf(owner.parse().unwrap(), mix_id, None)
|
||||
.ignore(),
|
||||
|
||||
#[cfg(feature = "nym_mixnet_contract_common/contract-testing")]
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents {} => {
|
||||
#[cfg(feature = "contract-testing")]
|
||||
MixnetExecuteMsg::TestingResolveAllPendingEvents { .. } => {
|
||||
client.testing_resolve_all_pending_events(None).ignore()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,6 +8,6 @@ description = "Crutch library until there is proper SerDe support for coconut st
|
||||
bs58 = "0.4.0"
|
||||
getset = "0.1.1"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = "1"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-coconut = {path = "../nymcoconut" }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
|
||||
use crate::context::QueryClientWithNyxd;
|
||||
use crate::utils::{pretty_cosmwasm_coin, show_error};
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
|
||||
use crate::context::QueryClientWithNyxd;
|
||||
use crate::utils::{pretty_decimal_with_denom, show_error};
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
|
||||
use crate::context::QueryClientWithNyxd;
|
||||
use crate::utils::show_error;
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
|
||||
use crate::context::QueryClientWithNyxd;
|
||||
use crate::utils::show_error;
|
||||
use clap::Parser;
|
||||
use comfy_table::Table;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
use nym_validator_client::nym_api::error::NymAPIError;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
|
||||
@@ -18,7 +18,7 @@ serde_repr = "0.1"
|
||||
|
||||
# we still have to preserve that import for `JsonSchema` for `Layer` type (since we can't use cw_serde macro due to custom serde impl)
|
||||
schemars = "0.8"
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" }
|
||||
serde-json-wasm = { workspace = true }
|
||||
humantime-serde = "1.1.1"
|
||||
|
||||
@@ -14,4 +14,4 @@ cosmwasm-schema = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -14,7 +14,7 @@ cw2 = { workspace = true, optional = true }
|
||||
mixnet-contract-common = { path = "../mixnet-contract", package = "nym-mixnet-contract-common", version = "0.6.0" }
|
||||
contracts-common = { path = "../contracts-common", package = "nym-contracts-common", version = "0.5.0" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
ts-rs = { workspace = true, optional = true}
|
||||
|
||||
[features]
|
||||
|
||||
@@ -9,7 +9,7 @@ edition = "2021"
|
||||
async-trait = { workspace = true }
|
||||
|
||||
log = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
tokio = { version = "1.24.1", features = ["sync"]}
|
||||
|
||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx]
|
||||
|
||||
@@ -23,7 +23,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
|
||||
serde_bytes = { version = "0.11.6", optional = true }
|
||||
serde_crate = { version = "1.0", optional = true, default_features = false, features = ["derive"], package = "serde" }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
zeroize = { workspace = true, optional = true, features = ["zeroize_derive"] }
|
||||
|
||||
# internal
|
||||
|
||||
@@ -145,8 +145,12 @@ impl PublicKey {
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
|
||||
self.0.verify(message, &signature.0)
|
||||
pub fn verify<M: AsRef<[u8]>>(
|
||||
&self,
|
||||
message: M,
|
||||
signature: &Signature,
|
||||
) -> Result<(), SignatureError> {
|
||||
self.0.verify(message.as_ref(), &signature.0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,16 +243,16 @@ impl PrivateKey {
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn sign(&self, message: &[u8]) -> Signature {
|
||||
pub fn sign<M: AsRef<[u8]>>(&self, message: M) -> Signature {
|
||||
let expanded_secret_key = ed25519_dalek::ExpandedSecretKey::from(&self.0);
|
||||
let public_key: PublicKey = self.into();
|
||||
let sig = expanded_secret_key.sign(message, &public_key.0);
|
||||
let sig = expanded_secret_key.sign(message.as_ref(), &public_key.0);
|
||||
Signature(sig)
|
||||
}
|
||||
|
||||
/// Signs text with the provided Ed25519 private key, returning a base58 signature
|
||||
pub fn sign_text(&self, text: &str) -> String {
|
||||
let signature_bytes = self.sign(text.as_ref()).to_bytes();
|
||||
let signature_bytes = self.sign(text).to_bytes();
|
||||
bs58::encode(signature_bytes).into_string()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ rand = { version = "0.8.5", default-features = false}
|
||||
rand_chacha = "0.3"
|
||||
rand_core = "0.6.3"
|
||||
sha2 = "0.9"
|
||||
serde = "1.0"
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0"
|
||||
thiserror = "1.0"
|
||||
zeroize = { version = "1.4", features = ["zeroize_derive"] }
|
||||
thiserror = { workspace = true }
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
|
||||
nym-pemstore = { path = "../pemstore" }
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "http-api-client"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
url = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
# for request timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
|
||||
[target."cfg(target_arch = \"wasm32\")".dependencies.wasmtimer]
|
||||
workspace = true
|
||||
features = ["tokio"]
|
||||
@@ -0,0 +1,512 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use async_trait::async_trait;
|
||||
use reqwest::{IntoUrl, Response, StatusCode};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use tracing::warn;
|
||||
use url::Url;
|
||||
|
||||
pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(3);
|
||||
|
||||
pub type PathSegments<'a> = &'a [&'a str];
|
||||
pub type Params<'a, K, V> = &'a [(K, V)];
|
||||
|
||||
pub const NO_PARAMS: Params<'_, &'_ str, &'_ str> = &[];
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum HttpClientError<E: Display = String> {
|
||||
#[error("there was an issue with the REST request: {source}")]
|
||||
ReqwestClientError {
|
||||
#[from]
|
||||
source: reqwest::Error,
|
||||
},
|
||||
|
||||
#[error("provided url is malformed: {source}")]
|
||||
MalformedUrl {
|
||||
#[from]
|
||||
source: url::ParseError,
|
||||
},
|
||||
|
||||
#[error("the requested resource could not be found")]
|
||||
NotFound,
|
||||
|
||||
#[error("request failed with error message: {0}")]
|
||||
GenericRequestFailure(String),
|
||||
|
||||
#[error("the request failed with status '{status}'. no additional error message provided")]
|
||||
RequestFailure { status: StatusCode },
|
||||
|
||||
#[error("the returned response was empty. status: '{status}'")]
|
||||
EmptyResponse { status: StatusCode },
|
||||
|
||||
#[error("failed to resolve request. status: '{status}', additional error message: {error}")]
|
||||
EndpointFailure { status: StatusCode, error: E },
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[error("the request has timed out")]
|
||||
RequestTimeout,
|
||||
}
|
||||
|
||||
/// A simple extendable client wrapper for http request with extra url sanitization.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Client {
|
||||
base_url: Url,
|
||||
reqwest_client: reqwest::Client,
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
request_timeout: Duration,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
// no timeout until https://github.com/seanmonstar/reqwest/issues/1135 is fixed
|
||||
pub fn new(base_url: Url, timeout: Option<Duration>) -> Self {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let reqwest_client = reqwest::Client::new();
|
||||
|
||||
// TODO: we should probably be propagating the error rather than panicking,
|
||||
// but that'd break bunch of things due to type changes
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let reqwest_client = reqwest::ClientBuilder::new()
|
||||
.timeout(timeout.unwrap_or(DEFAULT_TIMEOUT))
|
||||
.user_agent(format!("nym-http-api-client/{}", env!("CARGO_PKG_VERSION")))
|
||||
.build()
|
||||
.expect("Client::new()");
|
||||
|
||||
Client {
|
||||
base_url,
|
||||
reqwest_client,
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
request_timeout: timeout.unwrap_or(DEFAULT_TIMEOUT),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_url<U, E>(url: U, timeout: Option<Duration>) -> Result<Self, HttpClientError<E>>
|
||||
where
|
||||
U: IntoUrl,
|
||||
E: Display,
|
||||
{
|
||||
// a naive check: if the provided URL does not start with http(s), add that scheme
|
||||
let str_url = url.as_str();
|
||||
|
||||
if !str_url.starts_with("http") {
|
||||
let alt = format!("http://{str_url}");
|
||||
warn!("the provided url ('{str_url}') does not contain scheme information. Changing it to '{alt}' ...");
|
||||
// TODO: or should we maybe default to https?
|
||||
Self::new_url(alt, timeout)
|
||||
} else {
|
||||
Ok(Self::new(url.into_url()?, timeout))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_base_url(&mut self, new_url: Url) {
|
||||
self.base_url = new_url
|
||||
}
|
||||
|
||||
pub fn current_url(&self) -> &Url {
|
||||
&self.base_url
|
||||
}
|
||||
|
||||
async fn send_get_request<K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<Response, HttpClientError<E>>
|
||||
where
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
Ok(
|
||||
wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client.get(url).send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
Ok(self.reqwest_client.get(url).send().await?)
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_post_request<B, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<Response, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
Ok(wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client.post(url).json(json_body).send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
Ok(self.reqwest_client.post(url).json(json_body).send().await?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
let res = self.send_get_request(path, params).await?;
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn post_json<B, T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
let res = self.send_post_request(path, params, json_body).await?;
|
||||
parse_response(res, true).await
|
||||
}
|
||||
|
||||
pub async fn get_json_endpoint<T, S, E>(&self, endpoint: S) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let res = {
|
||||
wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client
|
||||
.get(self.base_url.join(endpoint.as_ref())?)
|
||||
.send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let res = {
|
||||
self.reqwest_client
|
||||
.get(self.base_url.join(endpoint.as_ref())?)
|
||||
.send()
|
||||
.await?
|
||||
};
|
||||
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn post_json_endpoint<B, T, S, E>(
|
||||
&self,
|
||||
endpoint: S,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let res = {
|
||||
wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client
|
||||
.post(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let res = {
|
||||
self.reqwest_client
|
||||
.post(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send()
|
||||
.await?
|
||||
};
|
||||
|
||||
parse_response(res, true).await
|
||||
}
|
||||
}
|
||||
|
||||
// define those methods on the trait for nicer extensions (and not having to type the thing twice)
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait ApiClient {
|
||||
/// 'get' json data from the segment-defined path, i.e. for example `["api", "v1", "mixnodes"]`,
|
||||
/// with tuple defined key-value parameters, i.e. for example `[("since", "12345")]`
|
||||
async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
V: AsRef<str> + Sync,
|
||||
E: Display + DeserializeOwned;
|
||||
|
||||
async fn post_json<B, T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized + Sync,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
V: AsRef<str> + Sync,
|
||||
E: Display + DeserializeOwned;
|
||||
|
||||
/// `get` json data from the provided absolute endpoint, i.e. for example `"/api/v1/mixnodes?since=12345"`
|
||||
async fn get_json_from<T, S, E>(&self, endpoint: S) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str> + Sync + Send;
|
||||
|
||||
async fn post_json_data_to<B, T, S, E>(
|
||||
&self,
|
||||
endpoint: S,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized + Sync,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str> + Sync + Send;
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl ApiClient for Client {
|
||||
async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
V: AsRef<str> + Sync,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
self.get_json(path, params).await
|
||||
}
|
||||
|
||||
async fn post_json<B, T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized + Sync,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str> + Sync,
|
||||
V: AsRef<str> + Sync,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
self.post_json(path, params, json_body).await
|
||||
}
|
||||
|
||||
async fn get_json_from<T, S, E>(&self, endpoint: S) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str> + Sync + Send,
|
||||
{
|
||||
self.get_json_endpoint(endpoint).await
|
||||
}
|
||||
|
||||
async fn post_json_data_to<B, T, S, E>(
|
||||
&self,
|
||||
endpoint: S,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized + Sync,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str> + Sync + Send,
|
||||
{
|
||||
self.post_json_endpoint(endpoint, json_body).await
|
||||
}
|
||||
}
|
||||
|
||||
// utility function that should solve the double slash problem in API urls forever.
|
||||
pub fn sanitize_url<K: AsRef<str>, V: AsRef<str>>(
|
||||
base: &Url,
|
||||
segments: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
) -> Url {
|
||||
let mut url = base.clone();
|
||||
let mut path_segments = url
|
||||
.path_segments_mut()
|
||||
.expect("provided validator url does not have a base!");
|
||||
for segment in segments {
|
||||
let segment = segment.strip_prefix('/').unwrap_or(segment);
|
||||
let segment = segment.strip_suffix('/').unwrap_or(segment);
|
||||
|
||||
path_segments.push(segment);
|
||||
}
|
||||
// I don't understand why compiler couldn't figure out that it's no longer used
|
||||
// and can be dropped
|
||||
drop(path_segments);
|
||||
|
||||
if !params.is_empty() {
|
||||
url.query_pairs_mut().extend_pairs(params);
|
||||
}
|
||||
|
||||
url
|
||||
}
|
||||
|
||||
async fn parse_response<T, E>(res: Response, allow_empty: bool) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
E: DeserializeOwned + Display,
|
||||
{
|
||||
let status = res.status();
|
||||
|
||||
if !allow_empty {
|
||||
if let Some(0) = res.content_length() {
|
||||
return Err(HttpClientError::EmptyResponse { status });
|
||||
}
|
||||
}
|
||||
|
||||
if res.status().is_success() {
|
||||
Ok(res.json().await?)
|
||||
} else if res.status() == StatusCode::NOT_FOUND {
|
||||
Err(HttpClientError::NotFound)
|
||||
} else {
|
||||
let Ok(plaintext) = res.text().await else {
|
||||
return Err(HttpClientError::RequestFailure { status });
|
||||
};
|
||||
|
||||
if let Ok(request_error) = serde_json::from_str(&plaintext) {
|
||||
Err(HttpClientError::EndpointFailure {
|
||||
status,
|
||||
error: request_error,
|
||||
})
|
||||
} else {
|
||||
Err(HttpClientError::GenericRequestFailure(plaintext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn sanitizing_urls() {
|
||||
let base_url: Url = "http://foomp.com".parse().unwrap();
|
||||
|
||||
// works with 1 segment
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
sanitize_url(&base_url, &["foo"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with 2 segments
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["foo", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with leading slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
sanitize_url(&base_url, &["/foo"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["/foo", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["foo", "/bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with trailing slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
sanitize_url(&base_url, &["foo/"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["foo/", "bar"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["foo", "bar/"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// works with both leading and trailing slash
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo",
|
||||
sanitize_url(&base_url, &["/foo/"], NO_PARAMS).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar",
|
||||
sanitize_url(&base_url, &["/foo/", "/bar/"], NO_PARAMS).as_str()
|
||||
);
|
||||
|
||||
// adds params
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar?foomp=baz",
|
||||
sanitize_url(&base_url, &["foo", "bar"], &[("foomp", "baz")]).as_str()
|
||||
);
|
||||
assert_eq!(
|
||||
"http://foomp.com/foo/bar?arg1=val1&arg2=val2",
|
||||
sanitize_url(
|
||||
&base_url,
|
||||
&["/foo/", "/bar/"],
|
||||
&[("arg1", "val1"), ("arg2", "val2")]
|
||||
)
|
||||
.as_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
[package]
|
||||
name = "nym-http-requests"
|
||||
version = "0.1.0"
|
||||
description = "Helper library for sending HTTP requesters over the Nym mixnet"
|
||||
edition = { workspace = true }
|
||||
authors = { workspace = true }
|
||||
license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
nym-socks5-requests = { path = "../socks5/requests" }
|
||||
nym-ordered-buffer = { path = "../socks5/ordered-buffer" }
|
||||
nym-service-providers-common = { path = "../../service-providers/common" }
|
||||
bytecodec = "0.4.15"
|
||||
httpcodec = "0.2.3"
|
||||
bytes = "1"
|
||||
http = "0.2.9"
|
||||
thiserror = "1"
|
||||
url = "2"
|
||||
@@ -1,23 +0,0 @@
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MixHttpRequestError {
|
||||
#[error("invalid Socks5 response")]
|
||||
InvalidSocks5Response,
|
||||
|
||||
#[error("the received Socks5 response was empty")]
|
||||
EmptySocks5Response,
|
||||
|
||||
#[error("bytecodec Error: {0}")]
|
||||
ByteCodecError(#[from] bytecodec::Error),
|
||||
|
||||
#[error("Url parse error: {0}")]
|
||||
UrlParseError(#[from] url::ParseError),
|
||||
|
||||
#[error("could not resolve socket address from the provided URL")]
|
||||
SocketAddrResolveError {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use bytecodec::bytes::BytesEncoder;
|
||||
use bytecodec::io::IoEncodeExt;
|
||||
use bytecodec::Encode;
|
||||
use httpcodec::{BodyEncoder, Request, RequestEncoder};
|
||||
|
||||
pub mod error;
|
||||
pub mod socks;
|
||||
|
||||
pub fn encode_http_request_as_string(
|
||||
request: Request<Vec<u8>>,
|
||||
) -> Result<String, error::MixHttpRequestError> {
|
||||
// Encode HTTP request as bytes
|
||||
let mut encoder = RequestEncoder::new(BodyEncoder::new(BytesEncoder::new()));
|
||||
encoder.start_encoding(request)?;
|
||||
let mut buf = Vec::new();
|
||||
encoder.encode_all(&mut buf)?;
|
||||
|
||||
Ok(String::from_utf8_lossy(&buf).to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod http_requests_tests {
|
||||
use super::*;
|
||||
use httpcodec::{HeaderField, HttpVersion, Method, RequestTarget};
|
||||
|
||||
fn create_http_get_request() -> Request<Vec<u8>> {
|
||||
let mut request = Request::new(
|
||||
Method::new("GET").unwrap(),
|
||||
RequestTarget::new("/.wellknown/wallet/validators.json").unwrap(),
|
||||
HttpVersion::V1_1,
|
||||
b"".to_vec(),
|
||||
);
|
||||
let mut headers = request.header_mut();
|
||||
headers.add_field(HeaderField::new("Host", "nymtech.net").unwrap());
|
||||
|
||||
request
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn http_request_ok() {
|
||||
// Encode HTTP request as bytes
|
||||
let request = create_http_get_request();
|
||||
let mut encoder = RequestEncoder::new(BodyEncoder::new(BytesEncoder::new()));
|
||||
encoder.start_encoding(request).unwrap();
|
||||
let mut buf = Vec::new();
|
||||
encoder.encode_all(&mut buf).unwrap();
|
||||
|
||||
let body_as_string = String::from_utf8(buf).unwrap();
|
||||
|
||||
// replace newlines with \r\n
|
||||
let expected = r"GET /.wellknown/wallet/validators.json HTTP/1.1
|
||||
Host: nymtech.net
|
||||
Content-Length: 0
|
||||
|
||||
"
|
||||
.replace('\n', "\r\n");
|
||||
|
||||
assert_eq!(expected, body_as_string);
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error;
|
||||
use bytecodec::bytes::BytesEncoder;
|
||||
use bytecodec::bytes::RemainingBytesDecoder;
|
||||
use bytecodec::io::IoEncodeExt;
|
||||
use bytecodec::{DecodeExt, Encode};
|
||||
use httpcodec::{BodyDecoder, ResponseDecoder};
|
||||
use httpcodec::{BodyEncoder, Request, RequestEncoder};
|
||||
use nym_service_providers_common::interface::ProviderInterfaceVersion;
|
||||
use nym_socks5_requests::{SocketData, Socks5ProtocolVersion, Socks5ProviderRequest};
|
||||
|
||||
pub fn encode_http_request_as_socks_send_request(
|
||||
provider_interface: ProviderInterfaceVersion,
|
||||
socks5_protocol: Socks5ProtocolVersion,
|
||||
conn_id: u64,
|
||||
request: Request<Vec<u8>>,
|
||||
seq: Option<u64>,
|
||||
local_closed: bool,
|
||||
) -> Result<nym_socks5_requests::Socks5ProviderRequest, error::MixHttpRequestError> {
|
||||
// Encode HTTP request as bytes
|
||||
let mut encoder = RequestEncoder::new(BodyEncoder::new(BytesEncoder::new()));
|
||||
encoder.start_encoding(request)?;
|
||||
let mut buf = Vec::new();
|
||||
encoder.encode_all(&mut buf)?;
|
||||
|
||||
// Wrap it as SOCKS send request
|
||||
let request_content = nym_socks5_requests::request::Socks5Request::new_send(
|
||||
socks5_protocol,
|
||||
SocketData::new(seq.unwrap_or_default(), conn_id, local_closed, buf),
|
||||
);
|
||||
|
||||
// and wrap it in provider request
|
||||
Ok(Socks5ProviderRequest::new_provider_data(
|
||||
provider_interface,
|
||||
request_content,
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MixHttpResponse {
|
||||
// pub connection_id: u64,
|
||||
// #[deprecated]
|
||||
// pub is_closed: bool,
|
||||
pub http_response: httpcodec::Response<Vec<u8>>,
|
||||
// #[deprecated]
|
||||
// pub seq: u64,
|
||||
}
|
||||
|
||||
impl MixHttpResponse {
|
||||
pub fn try_from_bytes(b: &[u8]) -> Result<MixHttpResponse, error::MixHttpRequestError> {
|
||||
if b.is_empty() {
|
||||
Err(error::MixHttpRequestError::EmptySocks5Response)
|
||||
} else {
|
||||
let mut decoder = ResponseDecoder::<BodyDecoder<RemainingBytesDecoder>>::default();
|
||||
let http_response = decoder.decode_from_bytes(b)?;
|
||||
|
||||
Ok(MixHttpResponse { http_response })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl TryFrom<Socks5Response> for MixHttpResponse {
|
||||
// type Error = error::MixHttpRequestError;
|
||||
//
|
||||
// fn try_from(value: Socks5Response) -> Result<Self, Self::Error> {
|
||||
// if let Socks5ResponseContent::NetworkData { content } = value.content {
|
||||
// content.try_into()
|
||||
// } else {
|
||||
// Err(error::MixHttpRequestError::InvalidSocks5Response)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl TryFrom<SocketData> for MixHttpResponse {
|
||||
// type Error = error::MixHttpRequestError;
|
||||
//
|
||||
// fn try_from(value: SocketData) -> Result<Self, Self::Error> {
|
||||
// if value.data.is_empty() {
|
||||
// Err(error::MixHttpRequestError::EmptySocks5Response)
|
||||
// } else {
|
||||
// let mut decoder = ResponseDecoder::<BodyDecoder<RemainingBytesDecoder>>::default();
|
||||
// let http_response = decoder.decode_from_bytes(value.data.as_ref())?;
|
||||
//
|
||||
// Ok(MixHttpResponse {
|
||||
// connection_id: value.header.connection_id,
|
||||
// is_closed: value.header.local_socket_closed,
|
||||
// http_response,
|
||||
// seq: value.header.seq,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn decode_socks_response_as_http_response(
|
||||
// socks5_response: Socks5Response,
|
||||
// ) -> Result<MixHttpResponse, error::MixHttpRequestError> {
|
||||
// socks5_response.try_into()
|
||||
// }
|
||||
//
|
||||
// #[cfg(test)]
|
||||
// mod http_requests_tests {
|
||||
// use super::*;
|
||||
// use httpcodec::{HeaderField, HttpVersion, Method, RequestTarget};
|
||||
// use nym_service_providers_common::interface::Serializable;
|
||||
// use nym_socks5_requests::Socks5Response;
|
||||
//
|
||||
// fn create_http_get_request() -> Request<Vec<u8>> {
|
||||
// let mut request = Request::new(
|
||||
// Method::new("GET").unwrap(),
|
||||
// RequestTarget::new("/.wellknown/wallet/validators.json").unwrap(),
|
||||
// HttpVersion::V1_1,
|
||||
// b"".to_vec(),
|
||||
// );
|
||||
// let mut headers = request.header_mut();
|
||||
// headers.add_field(HeaderField::new("Host", "nymtech.net").unwrap());
|
||||
//
|
||||
// request
|
||||
// }
|
||||
//
|
||||
// fn create_socks5_request_buffer() -> Vec<u8> {
|
||||
// let request = create_http_get_request();
|
||||
// let socks5_request = encode_http_request_as_socks_send_request(
|
||||
// ProviderInterfaceVersion::new_current(),
|
||||
// Socks5ProtocolVersion::new_current(),
|
||||
// 99u64,
|
||||
// request,
|
||||
// Some(42u64),
|
||||
// true,
|
||||
// )
|
||||
// .unwrap();
|
||||
// socks5_request.into_bytes()
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn request_http_request_content_ok() {
|
||||
// let buffer = create_socks5_request_buffer();
|
||||
//
|
||||
// // HTTP request string content is as expected
|
||||
// assert_eq!(
|
||||
// [71u8, 69u8, 84u8, 32u8, 47u8, 46u8, 119u8, 101u8],
|
||||
// buffer[19..27]
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// /// This test will fail if the framing of the request buffer changes, e.g. when OrderedMessage
|
||||
// /// changes to have the `index` value as a field, instead of packed with the `data`
|
||||
// #[test]
|
||||
// fn request_size_as_expected_ok() {
|
||||
// let buffer = create_socks5_request_buffer();
|
||||
// // println!("{:?}", buffer) // uncomment and run `cargo test -- --nocapture` to view
|
||||
//
|
||||
// assert_eq!(108, buffer.len()); // version set to SOCKS5
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn request_socks5_headers_ok() {
|
||||
// let buffer = create_socks5_request_buffer();
|
||||
//
|
||||
// assert_eq!(5u8, buffer[0]); // version set to SOCKS5
|
||||
// assert_eq!(1u8, buffer[1]); // type is SEND
|
||||
// assert_eq!(99u8, buffer[9]); // ConnectionId is correct
|
||||
// assert_eq!(1u8, buffer[10]); // local_closed is true
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn request_ordered_message_ok() {
|
||||
// let buffer = create_socks5_request_buffer();
|
||||
//
|
||||
// // OrderedMessage index is correct
|
||||
// assert_eq!(42u8, buffer[18]);
|
||||
// }
|
||||
//
|
||||
// fn create_socks_response() -> Socks5Response {
|
||||
// // HTTP response is just a string
|
||||
// let http_response_string = "HTTP/1.1 200 OK\r\nServer: foo/0.0.1\r\n\r\n";
|
||||
//
|
||||
// let data = http_response_string.as_bytes().to_vec();
|
||||
//
|
||||
// // wrap in `NetworkData`, then Socks5Response
|
||||
// Socks5Response::new(
|
||||
// Socks5ProtocolVersion::new_current(),
|
||||
// Socks5ResponseContent::NetworkData {
|
||||
// content: SocketData::new(42, 99u64, false, data),
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// /// This test will fail is anything in the framing of the socks5_response byte
|
||||
// /// representation changes
|
||||
// #[test]
|
||||
// fn response_byte_size_is_as_expected() {
|
||||
// let socks5_response = create_socks_response();
|
||||
// let buf = socks5_response.into_bytes();
|
||||
//
|
||||
// assert_eq!(57, buf.len());
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn response_parses() {
|
||||
// unimplemented!()
|
||||
// // let socks5_response = create_socks_response();
|
||||
// // let response = decode_socks_response_as_http_response(socks5_response).unwrap();
|
||||
// //
|
||||
// // assert_eq!(42u64, response.seq); // OrderedMessage index as expected
|
||||
// // assert_eq!(HttpVersion::V1_1, response.http_response.http_version());
|
||||
// // assert_eq!(200u16, response.http_response.status_code().as_u16());
|
||||
// // assert_eq!(
|
||||
// // "foo/0.0.1",
|
||||
// // response.http_response.header().get_field("Server").unwrap()
|
||||
// // );
|
||||
// }
|
||||
// }
|
||||
@@ -10,4 +10,4 @@ bip32 = "0.5.1"
|
||||
k256 = { workspace = true }
|
||||
ledger-transport = "0.10.0"
|
||||
ledger-transport-hid = "0.10.0"
|
||||
thiserror = "1"
|
||||
thiserror = { workspace = true }
|
||||
@@ -23,7 +23,7 @@ impl EchoPacket {
|
||||
.chain(keys.public_key().to_bytes().iter().cloned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let signature = keys.private_key().sign(&bytes_to_sign);
|
||||
let signature = keys.private_key().sign(bytes_to_sign);
|
||||
|
||||
EchoPacket {
|
||||
sequence_number,
|
||||
@@ -67,7 +67,7 @@ impl EchoPacket {
|
||||
|
||||
pub(crate) fn construct_reply(self, private_key: &identity::PrivateKey) -> ReplyPacket {
|
||||
let bytes = self.to_bytes();
|
||||
let signature = private_key.sign(&bytes);
|
||||
let signature = private_key.sign(bytes);
|
||||
ReplyPacket {
|
||||
base_packet: self,
|
||||
signature,
|
||||
|
||||
@@ -7,5 +7,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ cfg-if = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
hex-literal = "0.3.3"
|
||||
once_cell = { workspace = true }
|
||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true, features = ["derive"]}
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
|
||||
@@ -462,6 +462,9 @@ pub const DEFAULT_NYM_API_PORT: u16 = 8080;
|
||||
|
||||
pub const NYM_API_VERSION: &str = "v1";
|
||||
|
||||
// NYM-NODE
|
||||
pub const DEFAULT_NYM_NODE_HTTP_PORT: u16 = 8080;
|
||||
|
||||
// REWARDING
|
||||
|
||||
/// We'll be assuming a few more things, profit margin and cost function. Since we don't have reliable package measurement, we'll be using uptime. We'll also set the value of 1 Nym to 1 $, to be able to translate interval costs to Nyms. We'll also assume a cost of 40$ per interval(month), converting that to Nym at our 1$ rate translates to 40_000_000 uNyms
|
||||
|
||||
@@ -11,8 +11,8 @@ bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch ="gt-seriali
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
thiserror = "1.0"
|
||||
serde = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_derive = "1.0"
|
||||
bs58 = "0.4.0"
|
||||
sha2 = "0.9"
|
||||
|
||||
@@ -11,7 +11,7 @@ repository = { workspace = true }
|
||||
nym-crypto = { path = "../../crypto", features = ["asymmetric"] } # all addresses are expressed in terms on their crypto keys
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx"] } # we need to be able to refer to some types defined inside sphinx crate
|
||||
serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient`
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.7"
|
||||
|
||||
@@ -10,8 +10,8 @@ repository = { workspace = true }
|
||||
[dependencies]
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
bs58 = "0.4"
|
||||
serde = "1.0"
|
||||
thiserror = "1"
|
||||
serde = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["symmetric", "rand"] }
|
||||
nym-sphinx-addressing = { path = "../addressing" }
|
||||
|
||||
@@ -12,7 +12,7 @@ repository = { workspace = true }
|
||||
[dependencies]
|
||||
log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-sphinx-addressing = { path = "../addressing" }
|
||||
nym-sphinx-params = { path = "../params" }
|
||||
|
||||
@@ -9,7 +9,7 @@ repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../../crypto" }
|
||||
nym-sphinx-acknowledgements = { path = "../acknowledgements" }
|
||||
|
||||
@@ -12,4 +12,4 @@ nym-sphinx-addressing = { path = "../addressing" }
|
||||
nym-sphinx-params = { path = "../params" }
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] }
|
||||
nym-outfox = { path = "../../../nym-outfox" }
|
||||
thiserror = "1"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -10,7 +10,7 @@ repository = { workspace = true }
|
||||
[dependencies]
|
||||
bytes = "1.0"
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-sphinx-types = { path = "../types", features = ["sphinx", "outfox"] }
|
||||
nym-sphinx-params = { path = "../params", features = ["sphinx", "outfox"] }
|
||||
|
||||
@@ -8,7 +8,7 @@ license = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
nym-crypto = { path = "../../crypto", features = ["hashing", "symmetric"] }
|
||||
|
||||
@@ -294,7 +294,8 @@ mod message_receiver {
|
||||
owner: "foomp4".to_string(),
|
||||
host: "1.2.3.4".parse().unwrap(),
|
||||
mix_host: "1.2.3.4:1789".parse().unwrap(),
|
||||
clients_port: 9000,
|
||||
clients_ws_port: 9000,
|
||||
clients_wss_port: None,
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
"FioFa8nMmPpQnYi7JyojoTuwGLeyNS8BF4ChPr29zUML",
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ repository = { workspace = true }
|
||||
[dependencies]
|
||||
sphinx-packet = { version = "0.1.0", optional = true }
|
||||
nym-outfox = { path = "../../../nym-outfox", optional = true }
|
||||
thiserror = "1"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["sphinx"]
|
||||
|
||||
@@ -51,7 +51,11 @@ where
|
||||
if T::pem_type() != key_pem.tag {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unexpected key pem tag",
|
||||
format!(
|
||||
"unexpected key pem tag. Got '{}', expected: '{}'",
|
||||
key_pem.tag,
|
||||
T::pem_type()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ log = { workspace = true }
|
||||
pin-project = "1.0"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
reqwest = { workspace = true }
|
||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true, features = ["derive"] } # for config serialization/deserialization
|
||||
tap = "1.0.1"
|
||||
thiserror = "1.0.34"
|
||||
thiserror = { workspace = true }
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] }
|
||||
url = { workspace = true }
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log = { workspace = true }
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -15,5 +15,5 @@ reqwest = { workspace = true, features = ["json"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
|
||||
thiserror = "1"
|
||||
thiserror = { workspace = true }
|
||||
tokio = { version = "1.24.1", features = [ "time" ] }
|
||||
|
||||
@@ -15,7 +15,7 @@ documentation = { workspace = true }
|
||||
bs58 = "0.4"
|
||||
log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
async-trait = { workspace = true, optional = true }
|
||||
semver = "0.11"
|
||||
|
||||
@@ -35,6 +35,10 @@ nym-sphinx-types = { path = "../nymsphinx/types", features = ["sphinx", "outfox"
|
||||
nym-sphinx-routing = { path = "../nymsphinx/routing" }
|
||||
nym-bin-common = { path = "../bin-common" }
|
||||
|
||||
# I'm not sure how to feel about pulling in this dependency here...
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
|
||||
|
||||
# 'serializable' feature
|
||||
nym-config = { path = "../config", optional = true }
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{filter, NetworkAddress, NodeVersion};
|
||||
use nym_api_requests::models::DescribedGateway;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_mixnet_contract_common::GatewayBond;
|
||||
use nym_sphinx_addressing::nodes::{NodeIdentity, NymNodeRoutingAddress};
|
||||
@@ -10,6 +11,7 @@ use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use std::io;
|
||||
use std::net::AddrParseError;
|
||||
use std::net::SocketAddr;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -27,6 +29,17 @@ pub enum GatewayConversionError {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
|
||||
#[error("'{gateway}' has not provided any valid ip addresses")]
|
||||
NoIpAddressesProvided { gateway: String },
|
||||
|
||||
#[error("'{gateway}' has provided a malformed ip address: {err}")]
|
||||
MalformedIpAddress {
|
||||
gateway: String,
|
||||
|
||||
#[source]
|
||||
err: AddrParseError,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -36,7 +49,13 @@ pub struct Node {
|
||||
// we're keeping this as separate resolved field since we do not want to be resolving the potential
|
||||
// hostname every time we want to construct a path via this node
|
||||
pub mix_host: SocketAddr,
|
||||
pub clients_port: u16,
|
||||
|
||||
// #[serde(alias = "clients_port")]
|
||||
pub clients_ws_port: u16,
|
||||
|
||||
// #[serde(default)]
|
||||
pub clients_wss_port: Option<u16>,
|
||||
|
||||
pub identity_key: identity::PublicKey,
|
||||
pub sphinx_key: encryption::PublicKey, // TODO: or nymsphinx::PublicKey? both are x25519
|
||||
pub version: NodeVersion,
|
||||
@@ -48,7 +67,8 @@ impl std::fmt::Debug for Node {
|
||||
.field("host", &self.host)
|
||||
.field("owner", &self.owner)
|
||||
.field("mix_host", &self.mix_host)
|
||||
.field("clients_port", &self.clients_port)
|
||||
.field("clients_ws_port", &self.clients_ws_port)
|
||||
.field("clients_wss_port", &self.clients_wss_port)
|
||||
.field("identity_key", &self.identity_key.to_base58_string())
|
||||
.field("sphinx_key", &self.sphinx_key.to_base58_string())
|
||||
.field("version", &self.version)
|
||||
@@ -82,11 +102,17 @@ impl Node {
|
||||
}
|
||||
|
||||
pub fn clients_address(&self) -> String {
|
||||
format!("ws://{}:{}", self.host, self.clients_port)
|
||||
self.clients_address_tls()
|
||||
.unwrap_or_else(|| self.clients_address_no_tls())
|
||||
}
|
||||
|
||||
pub fn clients_address_tls(&self) -> String {
|
||||
format!("wss://{}:443", self.host)
|
||||
pub fn clients_address_no_tls(&self) -> String {
|
||||
format!("ws://{}:{}", self.host, self.clients_ws_port)
|
||||
}
|
||||
|
||||
pub fn clients_address_tls(&self) -> Option<String> {
|
||||
self.clients_wss_port
|
||||
.map(|p| format!("wss://{}:{p}", self.host))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +157,8 @@ impl<'a> TryFrom<&'a GatewayBond> for Node {
|
||||
owner: bond.owner.as_str().to_owned(),
|
||||
host,
|
||||
mix_host,
|
||||
clients_port: bond.gateway.clients_port,
|
||||
clients_ws_port: bond.gateway.clients_port,
|
||||
clients_wss_port: None,
|
||||
identity_key: identity::PublicKey::from_base58_string(&bond.gateway.identity_key)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(&bond.gateway.sphinx_key)?,
|
||||
version: bond.gateway.version.as_str().into(),
|
||||
@@ -146,3 +173,56 @@ impl TryFrom<GatewayBond> for Node {
|
||||
Node::try_from(&bond)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a DescribedGateway> for Node {
|
||||
type Error = GatewayConversionError;
|
||||
|
||||
fn try_from(value: &'a DescribedGateway) -> Result<Self, Self::Error> {
|
||||
let Some(ref self_described) = value.self_described else {
|
||||
return (&value.bond).try_into();
|
||||
};
|
||||
|
||||
let ips = &self_described.host_information.ip_address;
|
||||
if ips.is_empty() {
|
||||
return Err(GatewayConversionError::NoIpAddressesProvided {
|
||||
gateway: value.bond.gateway.identity_key.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
let host = match &self_described.host_information.hostname {
|
||||
None => NetworkAddress::IpAddr(ips[0]),
|
||||
Some(hostname) => NetworkAddress::Hostname(hostname.clone()),
|
||||
};
|
||||
|
||||
// get ip from the self-reported values so we wouldn't need to do any hostname resolution
|
||||
// (which doesn't really work in wasm)
|
||||
let mix_host = SocketAddr::new(ips[0], value.bond.gateway.mix_port);
|
||||
|
||||
Ok(Node {
|
||||
owner: value.bond.owner.as_str().to_owned(),
|
||||
host,
|
||||
mix_host,
|
||||
clients_ws_port: self_described.mixnet_websockets.ws_port,
|
||||
clients_wss_port: self_described.mixnet_websockets.wss_port,
|
||||
identity_key: identity::PublicKey::from_base58_string(
|
||||
&self_described.host_information.keys.ed25519,
|
||||
)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(
|
||||
&self_described.host_information.keys.x25519,
|
||||
)?,
|
||||
version: self_described
|
||||
.build_information
|
||||
.build_version
|
||||
.as_str()
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<DescribedGateway> for Node {
|
||||
type Error = GatewayConversionError;
|
||||
|
||||
fn try_from(value: DescribedGateway) -> Result<Self, Self::Error> {
|
||||
Node::try_from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use std::str::FromStr;
|
||||
|
||||
#[cfg(feature = "serializable")]
|
||||
use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use nym_api_requests::models::DescribedGateway;
|
||||
|
||||
pub mod error;
|
||||
pub mod filter;
|
||||
@@ -403,10 +404,33 @@ impl<'de> Deserialize<'de> for NymTopology {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nym_topology_from_detailed(
|
||||
pub trait IntoGatewayNode: TryInto<gateway::Node>
|
||||
where
|
||||
<Self as TryInto<gateway::Node>>::Error: Display,
|
||||
{
|
||||
fn identity(&self) -> IdentityKeyRef;
|
||||
}
|
||||
|
||||
impl IntoGatewayNode for GatewayBond {
|
||||
fn identity(&self) -> IdentityKeyRef {
|
||||
&self.gateway.identity_key
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoGatewayNode for DescribedGateway {
|
||||
fn identity(&self) -> IdentityKeyRef {
|
||||
&self.bond.gateway.identity_key
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nym_topology_from_detailed<G>(
|
||||
mix_details: Vec<MixNodeDetails>,
|
||||
gateway_bonds: Vec<GatewayBond>,
|
||||
) -> NymTopology {
|
||||
gateway_bonds: Vec<G>,
|
||||
) -> NymTopology
|
||||
where
|
||||
G: IntoGatewayNode,
|
||||
<G as TryInto<gateway::Node>>::Error: Display,
|
||||
{
|
||||
let mut mixes = BTreeMap::new();
|
||||
for bond in mix_details
|
||||
.into_iter()
|
||||
@@ -435,7 +459,7 @@ pub fn nym_topology_from_detailed(
|
||||
|
||||
let mut gateways = Vec::with_capacity(gateway_bonds.len());
|
||||
for bond in gateway_bonds.into_iter() {
|
||||
let gate_id = bond.gateway.identity_key.clone();
|
||||
let gate_id = bond.identity().to_owned();
|
||||
match bond.try_into() {
|
||||
Ok(gate) => gateways.push(gate),
|
||||
Err(err) => {
|
||||
|
||||
@@ -190,7 +190,12 @@ pub struct SerializableGateway {
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "clients_port")]
|
||||
pub clients_port: Option<u16>,
|
||||
#[serde(alias = "clients_ws_port")]
|
||||
pub clients_ws_port: Option<u16>,
|
||||
|
||||
#[cfg_attr(feature = "wasm-serde-types", tsify(optional))]
|
||||
#[serde(alias = "clients_wss_port")]
|
||||
pub clients_wss_port: Option<u16>,
|
||||
|
||||
#[serde(alias = "identity_key")]
|
||||
pub identity_key: String,
|
||||
@@ -209,7 +214,9 @@ impl TryFrom<SerializableGateway> for gateway::Node {
|
||||
let host = gateway::Node::parse_host(&value.host)?;
|
||||
|
||||
let mix_port = value.mix_port.unwrap_or(DEFAULT_MIX_LISTENING_PORT);
|
||||
let clients_port = value.clients_port.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT);
|
||||
let clients_ws_port = value
|
||||
.clients_ws_port
|
||||
.unwrap_or(DEFAULT_CLIENT_LISTENING_PORT);
|
||||
let version = value.version.map(|v| v.as_str().into()).unwrap_or_default();
|
||||
|
||||
// try to completely resolve the host in the mix situation to avoid doing it every
|
||||
@@ -224,7 +231,8 @@ impl TryFrom<SerializableGateway> for gateway::Node {
|
||||
owner: value.owner,
|
||||
host,
|
||||
mix_host,
|
||||
clients_port,
|
||||
clients_ws_port,
|
||||
clients_wss_port: value.clients_wss_port,
|
||||
identity_key: identity::PublicKey::from_base58_string(&value.identity_key)
|
||||
.map_err(GatewayConversionError::from)?,
|
||||
sphinx_key: encryption::PublicKey::from_base58_string(&value.sphinx_key)
|
||||
@@ -241,7 +249,8 @@ impl<'a> From<&'a gateway::Node> for SerializableGateway {
|
||||
host: value.host.to_string(),
|
||||
explicit_ip: Some(value.mix_host.ip()),
|
||||
mix_port: Some(value.mix_host.port()),
|
||||
clients_port: Some(value.clients_port),
|
||||
clients_ws_port: Some(value.clients_ws_port),
|
||||
clients_wss_port: value.clients_wss_port,
|
||||
identity_key: value.identity_key.to_base58_string(),
|
||||
sphinx_key: value.sphinx_key.to_base58_string(),
|
||||
version: Some(value.version.to_string()),
|
||||
|
||||
@@ -14,7 +14,7 @@ js-sys = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde-wasm-bindgen = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tsify = { workspace = true, features = ["js"] }
|
||||
url = { workspace = true }
|
||||
wasm-bindgen = { workspace = true }
|
||||
|
||||
@@ -22,6 +22,8 @@ bytes = "1.5.0"
|
||||
dashmap = "5.5.3"
|
||||
etherparse = "0.13.0"
|
||||
futures = "0.3.28"
|
||||
ip_network = "0.4.1"
|
||||
ip_network_table = "0.2.0"
|
||||
log.workspace = true
|
||||
nym-task = { path = "../task" }
|
||||
tap.workspace = true
|
||||
|
||||
+18
-10
@@ -1,40 +1,48 @@
|
||||
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
|
||||
|
||||
use nym_task::TaskClient;
|
||||
|
||||
mod error;
|
||||
mod event;
|
||||
mod network_table;
|
||||
mod platform;
|
||||
mod setup;
|
||||
mod tun;
|
||||
mod udp_listener;
|
||||
mod wg_tunnel;
|
||||
|
||||
// Currently the module related to setting up the virtual network device is platform specific.
|
||||
#[cfg(target_os = "linux")]
|
||||
use platform::linux::tun_device;
|
||||
|
||||
type ActivePeers =
|
||||
dashmap::DashMap<std::net::SocketAddr, tokio::sync::mpsc::UnboundedSender<crate::event::Event>>;
|
||||
#[derive(Clone)]
|
||||
struct TunTaskTx(tokio::sync::mpsc::UnboundedSender<Vec<u8>>);
|
||||
|
||||
impl TunTaskTx {
|
||||
fn send(&self, packet: Vec<u8>) -> Result<(), tokio::sync::mpsc::error::SendError<Vec<u8>>> {
|
||||
self.0.send(packet)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn start_wireguard(
|
||||
task_client: TaskClient,
|
||||
task_client: nym_task::TaskClient,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
use std::sync::Arc;
|
||||
|
||||
// The set of active tunnels indexed by the peer's address
|
||||
let active_peers = std::sync::Arc::new(ActivePeers::new());
|
||||
let active_peers = Arc::new(udp_listener::ActivePeers::new());
|
||||
let peers_by_ip = Arc::new(std::sync::Mutex::new(network_table::NetworkTable::new()));
|
||||
|
||||
// Start the tun device that is used to relay traffic outbound
|
||||
let tun_task_tx = tun_device::start_tun_device(active_peers.clone());
|
||||
let tun_task_tx = tun_device::start_tun_device(peers_by_ip.clone());
|
||||
|
||||
// Start the UDP listener that clients connect to
|
||||
udp_listener::start_udp_listener(tun_task_tx, active_peers, task_client).await?;
|
||||
udp_listener::start_udp_listener(tun_task_tx, active_peers, peers_by_ip, task_client).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub async fn start_wireguard(
|
||||
_task_client: TaskClient,
|
||||
_task_client: nym_task::TaskClient,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
todo!("WireGuard is currently only supported on Linux")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use ip_network::IpNetwork;
|
||||
use ip_network_table::IpNetworkTable;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct NetworkTable<T> {
|
||||
ips: IpNetworkTable<T>,
|
||||
}
|
||||
|
||||
impl<T> NetworkTable<T> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
ips: IpNetworkTable::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert<N: Into<IpNetwork>>(&mut self, network: N, data: T) -> Option<T> {
|
||||
self.ips.insert(network, data)
|
||||
}
|
||||
|
||||
pub fn longest_match<I: Into<IpAddr>>(&self, ip: I) -> Option<(IpNetwork, &T)> {
|
||||
self.ips.longest_match(ip)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
use std::{net::Ipv4Addr, sync::Arc};
|
||||
|
||||
use etherparse::{InternetSlice, SlicedPacket};
|
||||
use tap::TapFallible;
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
sync::mpsc::{self, UnboundedSender},
|
||||
sync::mpsc::{self},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
event::Event,
|
||||
setup::{TUN_BASE_NAME, TUN_DEVICE_ADDRESS, TUN_DEVICE_NETMASK},
|
||||
ActivePeers,
|
||||
udp_listener::PeersByIp,
|
||||
TunTaskTx,
|
||||
};
|
||||
|
||||
fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> tokio_tun::Tun {
|
||||
@@ -25,7 +28,7 @@ fn setup_tokio_tun_device(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> t
|
||||
.expect("Failed to setup tun device, do you have permission?")
|
||||
}
|
||||
|
||||
pub fn start_tun_device(_active_peers: Arc<ActivePeers>) -> UnboundedSender<Vec<u8>> {
|
||||
pub(crate) fn start_tun_device(peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>) -> TunTaskTx {
|
||||
let tun = setup_tokio_tun_device(
|
||||
format!("{}%d", TUN_BASE_NAME).as_str(),
|
||||
TUN_DEVICE_ADDRESS.parse().unwrap(),
|
||||
@@ -37,6 +40,7 @@ pub fn start_tun_device(_active_peers: Arc<ActivePeers>) -> UnboundedSender<Vec<
|
||||
|
||||
// Channels to communicate with the other tasks
|
||||
let (tun_task_tx, mut tun_task_rx) = mpsc::unbounded_channel::<Vec<u8>>();
|
||||
let tun_task_tx = TunTaskTx(tun_task_tx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mut buf = [0u8; 1024];
|
||||
@@ -55,8 +59,16 @@ pub fn start_tun_device(_active_peers: Arc<ActivePeers>) -> UnboundedSender<Vec<
|
||||
};
|
||||
log::info!("iface: read Packet({src_addr} -> {dst_addr}, {len} bytes)");
|
||||
|
||||
// TODO: route packet to the correct peer.
|
||||
log::info!("...forward packet to the correct peer (NOT YET IMPLEMENTED)");
|
||||
// Route packet to the correct peer.
|
||||
if let Some(peer_tx) = peers_by_ip.lock().unwrap().longest_match(dst_addr).map(|(_, tx)| tx) {
|
||||
log::info!("Forward packet to wg tunnel");
|
||||
peer_tx
|
||||
.send(Event::IpPacket(packet.to_vec().into()))
|
||||
.tap_err(|err| log::error!("{err}"))
|
||||
.unwrap();
|
||||
} else {
|
||||
log::info!("No peer found, packet dropped");
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
log::info!("iface: read error: {err}");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::net::IpAddr;
|
||||
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use boringtun::x25519;
|
||||
use log::info;
|
||||
@@ -15,35 +17,47 @@ pub const TUN_DEVICE_NETMASK: &str = "255.255.255.0";
|
||||
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
|
||||
const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
|
||||
|
||||
// The public keys of the registered peers (clients)
|
||||
const PEERS: &[&str; 1] = &[
|
||||
// Corresponding private key: "ILeN6gEh6vJ3Ju8RJ3HVswz+sPgkcKtAYTqzQRhTtlo="
|
||||
"NCIhkgiqxFx1ckKl3Zuh595DzIFl8mxju1Vg995EZhI=",
|
||||
// Another key
|
||||
// "mxV/mw7WZTe+0Msa0kvJHMHERDA/cSskiZWQce+TdEs=",
|
||||
];
|
||||
// The public keys of the registered peer (clients)
|
||||
// Corresponding private key: "ILeN6gEh6vJ3Ju8RJ3HVswz+sPgkcKtAYTqzQRhTtlo="
|
||||
const PEER: &str = "NCIhkgiqxFx1ckKl3Zuh595DzIFl8mxju1Vg995EZhI=";
|
||||
|
||||
pub fn init_static_dev_keys() -> (x25519::StaticSecret, x25519::PublicKey) {
|
||||
// TODO: this is a temporary solution for development
|
||||
let static_private_bytes: [u8; 32] = general_purpose::STANDARD
|
||||
.decode(PRIVATE_KEY)
|
||||
// The AllowedIPs for the connected peer, which is one a single IP and the same as the IP that the
|
||||
// peer has configured on their side.
|
||||
const ALLOWED_IPS: &str = "10.0.0.2";
|
||||
|
||||
fn decode_base64_key(base64_key: &str) -> [u8; 32] {
|
||||
general_purpose::STANDARD
|
||||
.decode(base64_key)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn server_static_private_key() -> x25519::StaticSecret {
|
||||
// TODO: this is a temporary solution for development
|
||||
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY);
|
||||
let static_private = x25519::StaticSecret::try_from(static_private_bytes).unwrap();
|
||||
let static_public = x25519::PublicKey::from(&static_private);
|
||||
info!(
|
||||
"wg public key: {}",
|
||||
general_purpose::STANDARD.encode(static_public)
|
||||
);
|
||||
|
||||
// TODO: A single static public key is used for all peers during development
|
||||
let peer_static_public_bytes: [u8; 32] = general_purpose::STANDARD
|
||||
.decode(PEERS[0])
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
|
||||
|
||||
(static_private, peer_static_public)
|
||||
static_private
|
||||
}
|
||||
|
||||
pub fn peer_static_public_key() -> x25519::PublicKey {
|
||||
// A single static public key is used during development
|
||||
let peer_static_public_bytes: [u8; 32] = decode_base64_key(PEER);
|
||||
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
|
||||
info!(
|
||||
"peer public key: {}",
|
||||
general_purpose::STANDARD.encode(peer_static_public)
|
||||
);
|
||||
peer_static_public
|
||||
}
|
||||
|
||||
pub fn peer_allowed_ips() -> ip_network::IpNetwork {
|
||||
let key: IpAddr = ALLOWED_IPS.parse().unwrap();
|
||||
let cidr = 0u8;
|
||||
ip_network::IpNetwork::new_truncate(key, cidr).unwrap()
|
||||
}
|
||||
|
||||
@@ -1,22 +1,31 @@
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use futures::StreamExt;
|
||||
use log::error;
|
||||
use nym_task::TaskClient;
|
||||
use tap::TapFallible;
|
||||
use tokio::{net::UdpSocket, sync::mpsc::UnboundedSender};
|
||||
use tokio::{
|
||||
net::UdpSocket,
|
||||
sync::mpsc::{self},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
event::Event,
|
||||
setup::{WG_ADDRESS, WG_PORT},
|
||||
ActivePeers,
|
||||
network_table::NetworkTable,
|
||||
setup::{self, WG_ADDRESS, WG_PORT},
|
||||
TunTaskTx,
|
||||
};
|
||||
|
||||
const MAX_PACKET: usize = 65535;
|
||||
|
||||
pub async fn start_udp_listener(
|
||||
tun_task_tx: UnboundedSender<Vec<u8>>,
|
||||
pub(crate) type ActivePeers = DashMap<SocketAddr, mpsc::UnboundedSender<Event>>;
|
||||
pub(crate) type PeersByIp = NetworkTable<mpsc::UnboundedSender<Event>>;
|
||||
|
||||
pub(crate) async fn start_udp_listener(
|
||||
tun_task_tx: TunTaskTx,
|
||||
active_peers: Arc<ActivePeers>,
|
||||
peers_by_ip: Arc<std::sync::Mutex<PeersByIp>>,
|
||||
mut task_client: TaskClient,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
let wg_address = SocketAddr::new(WG_ADDRESS.parse().unwrap(), WG_PORT);
|
||||
@@ -24,7 +33,9 @@ pub async fn start_udp_listener(
|
||||
let udp_socket = Arc::new(UdpSocket::bind(wg_address).await?);
|
||||
|
||||
// Setup some static keys for development
|
||||
let (static_private, peer_static_public) = crate::setup::init_static_dev_keys();
|
||||
let static_private = setup::server_static_private_key();
|
||||
let peer_static_public = setup::peer_static_public_key();
|
||||
let peer_allowed_ips = setup::peer_allowed_ips();
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Each tunnel is run in its own task, and the task handle is stored here so we can remove
|
||||
@@ -44,6 +55,7 @@ pub async fn start_udp_listener(
|
||||
Ok(addr) => {
|
||||
log::info!("Removing peer: {addr:?}");
|
||||
active_peers.remove(&addr);
|
||||
// TODO: remove from peers_by_ip
|
||||
}
|
||||
Err(err) => {
|
||||
error!("WireGuard UDP listener: error receiving shutdown from peer: {err}");
|
||||
@@ -61,13 +73,22 @@ pub async fn start_udp_listener(
|
||||
.unwrap();
|
||||
} else {
|
||||
log::info!("udp: received {len} bytes from {addr} from unknown peer, starting tunnel");
|
||||
let (join_handle, peer_tx) = crate::tun::start_wg_tunnel(
|
||||
// TODO: this is a temporary solution for development since this
|
||||
// assumes we know the peer_static_public this corresponds to.
|
||||
// TODO: rework this before production! This is likely not secure!
|
||||
log::warn!("Assuming peer_static_public is known");
|
||||
log::warn!("SECURITY: Rework me to do proper handshake before creating the tunnel!");
|
||||
let (join_handle, peer_tx) = crate::wg_tunnel::start_wg_tunnel(
|
||||
addr,
|
||||
udp_socket.clone(),
|
||||
static_private.clone(),
|
||||
peer_static_public,
|
||||
peer_allowed_ips,
|
||||
tun_task_tx.clone(),
|
||||
);
|
||||
|
||||
peers_by_ip.lock().unwrap().insert(peer_allowed_ips, peer_tx.clone());
|
||||
|
||||
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
|
||||
.tap_err(|err| log::error!("{err}"))
|
||||
.unwrap();
|
||||
|
||||
@@ -6,7 +6,6 @@ use boringtun::{
|
||||
x25519,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use etherparse::{InternetSlice, SlicedPacket};
|
||||
use log::{debug, error, info, warn};
|
||||
use tap::TapFallible;
|
||||
use tokio::{
|
||||
@@ -15,7 +14,7 @@ use tokio::{
|
||||
time::timeout,
|
||||
};
|
||||
|
||||
use crate::{error::WgError, event::Event};
|
||||
use crate::{error::WgError, event::Event, network_table::NetworkTable, TunTaskTx};
|
||||
|
||||
const MAX_PACKET: usize = 65535;
|
||||
|
||||
@@ -27,10 +26,10 @@ pub struct WireGuardTunnel {
|
||||
udp: Arc<UdpSocket>,
|
||||
|
||||
// Peer endpoint
|
||||
endpoint: SocketAddr,
|
||||
endpoint: Arc<tokio::sync::RwLock<SocketAddr>>,
|
||||
|
||||
// The source address of the last packet received from the peer
|
||||
source_addr: Arc<std::sync::RwLock<Option<std::net::Ipv4Addr>>>,
|
||||
// AllowedIPs for this peer
|
||||
allowed_ips: NetworkTable<()>,
|
||||
|
||||
// `boringtun` tunnel, used for crypto & WG protocol
|
||||
wg_tunnel: Arc<tokio::sync::Mutex<Tunn>>,
|
||||
@@ -40,7 +39,7 @@ pub struct WireGuardTunnel {
|
||||
close_rx: broadcast::Receiver<()>,
|
||||
|
||||
// Send data to the task that handles sending data through the tun device
|
||||
tun_task_tx: mpsc::UnboundedSender<Vec<u8>>,
|
||||
tun_task_tx: TunTaskTx,
|
||||
}
|
||||
|
||||
impl Drop for WireGuardTunnel {
|
||||
@@ -51,12 +50,13 @@ impl Drop for WireGuardTunnel {
|
||||
}
|
||||
|
||||
impl WireGuardTunnel {
|
||||
pub fn new(
|
||||
pub(crate) fn new(
|
||||
udp: Arc<UdpSocket>,
|
||||
endpoint: SocketAddr,
|
||||
static_private: x25519::StaticSecret,
|
||||
peer_static_public: x25519::PublicKey,
|
||||
tunnel_tx: mpsc::UnboundedSender<Vec<u8>>,
|
||||
peer_allowed_ips: ip_network::IpNetwork,
|
||||
tunnel_tx: TunTaskTx,
|
||||
) -> (Self, mpsc::UnboundedSender<Event>) {
|
||||
let local_addr = udp.local_addr().unwrap();
|
||||
let peer_addr = udp.peer_addr();
|
||||
@@ -85,11 +85,14 @@ impl WireGuardTunnel {
|
||||
// Signal close tunnel
|
||||
let (close_tx, close_rx) = broadcast::channel(1);
|
||||
|
||||
let mut allowed_ips = NetworkTable::new();
|
||||
allowed_ips.insert(peer_allowed_ips, ());
|
||||
|
||||
let tunnel = WireGuardTunnel {
|
||||
peer_rx,
|
||||
udp,
|
||||
endpoint,
|
||||
source_addr: Default::default(),
|
||||
endpoint: Arc::new(tokio::sync::RwLock::new(endpoint)),
|
||||
allowed_ips,
|
||||
wg_tunnel,
|
||||
close_tx,
|
||||
close_rx,
|
||||
@@ -134,7 +137,7 @@ impl WireGuardTunnel {
|
||||
},
|
||||
}
|
||||
}
|
||||
info!("WireGuard tunnel ({}): closed", self.endpoint);
|
||||
info!("WireGuard tunnel ({}): closed", self.endpoint.read().await);
|
||||
}
|
||||
|
||||
async fn wg_tunnel_lock(&self) -> Result<tokio::sync::MutexGuard<'_, Tunn>, WgError> {
|
||||
@@ -143,16 +146,11 @@ impl WireGuardTunnel {
|
||||
.map_err(|_| WgError::UnableToGetTunnel)
|
||||
}
|
||||
|
||||
fn set_source_addr(&self, source_addr: std::net::Ipv4Addr) {
|
||||
let to_update = {
|
||||
let stored_source_addr = self.source_addr.read().unwrap();
|
||||
stored_source_addr
|
||||
.map(|sa| sa != source_addr)
|
||||
.unwrap_or(true)
|
||||
};
|
||||
if to_update {
|
||||
log::info!("wg tunnel set_source_addr: {source_addr}");
|
||||
*self.source_addr.write().unwrap() = Some(source_addr);
|
||||
#[allow(unused)]
|
||||
async fn set_endpoint(&self, addr: SocketAddr) {
|
||||
if *self.endpoint.read().await != addr {
|
||||
log::info!("wg tunnel update endpoint: {addr}");
|
||||
*self.endpoint.write().await = addr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +159,9 @@ impl WireGuardTunnel {
|
||||
let mut tunnel = self.wg_tunnel_lock().await?;
|
||||
match tunnel.decapsulate(None, data, &mut send_buf) {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
log::info!("udp: send {} bytes to {}", packet.len(), self.endpoint);
|
||||
if let Err(err) = self.udp.send_to(packet, self.endpoint).await {
|
||||
let endpoint = self.endpoint.read().await;
|
||||
log::info!("udp: send {} bytes to {}", packet.len(), *endpoint);
|
||||
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
|
||||
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
|
||||
};
|
||||
// Flush pending queue
|
||||
@@ -170,8 +169,8 @@ impl WireGuardTunnel {
|
||||
let mut send_buf = [0u8; MAX_PACKET];
|
||||
match tunnel.decapsulate(None, &[], &mut send_buf) {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
log::info!("udp: send {} bytes to {}", packet.len(), self.endpoint);
|
||||
if let Err(err) = self.udp.send_to(packet, self.endpoint).await {
|
||||
log::info!("udp: send {} bytes to {}", packet.len(), *endpoint);
|
||||
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
|
||||
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
|
||||
break;
|
||||
};
|
||||
@@ -182,14 +181,23 @@ impl WireGuardTunnel {
|
||||
}
|
||||
}
|
||||
}
|
||||
TunnResult::WriteToTunnelV4(packet, _) | TunnResult::WriteToTunnelV6(packet, _) => {
|
||||
let headers = SlicedPacket::from_ip(packet).unwrap();
|
||||
let (source_addr, _destination_addr) = match headers.ip.unwrap() {
|
||||
InternetSlice::Ipv4(ip, _) => (ip.source_addr(), ip.destination_addr()),
|
||||
InternetSlice::Ipv6(_, _) => unimplemented!(),
|
||||
};
|
||||
self.set_source_addr(source_addr);
|
||||
self.tun_task_tx.send(packet.to_vec()).unwrap();
|
||||
TunnResult::WriteToTunnelV4(packet, addr) => {
|
||||
// TODO: once the flow is redone, we should add updating the endpoint dynamically
|
||||
// self.set_endpoint(addr);
|
||||
if self.allowed_ips.longest_match(addr).is_some() {
|
||||
self.tun_task_tx.send(packet.to_vec()).unwrap();
|
||||
} else {
|
||||
warn!("Packet from {addr} not in allowed_ips");
|
||||
}
|
||||
}
|
||||
TunnResult::WriteToTunnelV6(packet, addr) => {
|
||||
// TODO: once the flow is redone, we should add updating the endpoint dynamically
|
||||
// self.set_endpoint(addr);
|
||||
if self.allowed_ips.longest_match(addr).is_some() {
|
||||
self.tun_task_tx.send(packet.to_vec()).unwrap();
|
||||
} else {
|
||||
warn!("Packet (v6) from {addr} not in allowed_ips");
|
||||
}
|
||||
}
|
||||
TunnResult::Done => {
|
||||
debug!("WireGuard: decapsulate done");
|
||||
@@ -209,9 +217,10 @@ impl WireGuardTunnel {
|
||||
encapsulated_packet.len()
|
||||
);
|
||||
|
||||
info!("consume_eth: send to {}: {}", self.endpoint, data.len());
|
||||
let endpoint = self.endpoint.read().await;
|
||||
info!("consume_eth: send to {}: {}", *endpoint, data.len());
|
||||
self.udp
|
||||
.send_to(&encapsulated_packet, self.endpoint)
|
||||
.send_to(&encapsulated_packet, *endpoint)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
@@ -244,12 +253,9 @@ impl WireGuardTunnel {
|
||||
async fn handle_routine_tun_result<'a: 'async_recursion>(&self, result: TunnResult<'a>) {
|
||||
match result {
|
||||
TunnResult::WriteToNetwork(packet) => {
|
||||
log::info!(
|
||||
"routine: write to network: {}: {}",
|
||||
self.endpoint,
|
||||
packet.len()
|
||||
);
|
||||
if let Err(err) = self.udp.send_to(packet, self.endpoint).await {
|
||||
let endpoint = self.endpoint.read().await;
|
||||
log::info!("routine: write to network: {}: {}", endpoint, packet.len());
|
||||
if let Err(err) = self.udp.send_to(packet, *endpoint).await {
|
||||
error!("routine: failed to send packet: {err:?}");
|
||||
};
|
||||
}
|
||||
@@ -276,18 +282,25 @@ impl WireGuardTunnel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_wg_tunnel(
|
||||
pub(crate) fn start_wg_tunnel(
|
||||
endpoint: SocketAddr,
|
||||
udp: Arc<UdpSocket>,
|
||||
static_private: x25519::StaticSecret,
|
||||
peer_static_public: x25519::PublicKey,
|
||||
tunnel_tx: mpsc::UnboundedSender<Vec<u8>>,
|
||||
peer_allowed_ips: ip_network::IpNetwork,
|
||||
tunnel_tx: TunTaskTx,
|
||||
) -> (
|
||||
tokio::task::JoinHandle<SocketAddr>,
|
||||
mpsc::UnboundedSender<Event>,
|
||||
) {
|
||||
let (mut tunnel, peer_tx) =
|
||||
WireGuardTunnel::new(udp, endpoint, static_private, peer_static_public, tunnel_tx);
|
||||
let (mut tunnel, peer_tx) = WireGuardTunnel::new(
|
||||
udp,
|
||||
endpoint,
|
||||
static_private,
|
||||
peer_static_public,
|
||||
peer_allowed_ips,
|
||||
tunnel_tx,
|
||||
);
|
||||
let join_handle = tokio::spawn(async move {
|
||||
tunnel.spin_off().await;
|
||||
endpoint
|
||||
Generated
+13
-13
@@ -810,7 +810,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1628,9 +1628,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
version = "1.0.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -1894,7 +1894,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1927,7 +1927,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2041,9 +2041,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.12"
|
||||
version = "2.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927"
|
||||
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2065,22 +2065,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.40"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.40"
|
||||
version = "1.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2427,5 +2427,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.12",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
@@ -48,3 +48,5 @@ cw3 = "=1.1.0"
|
||||
cw3-fixed-multisig = "=1.1.0"
|
||||
cw4 = "=1.1.0"
|
||||
cw20 = "=1.1.0"
|
||||
|
||||
thiserror = "1.0.48"
|
||||
|
||||
@@ -23,7 +23,7 @@ cw-storage-plus = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.23"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
schema-gen = ["nym-coconut-bandwidth-contract-common/schema", "cosmwasm-schema"]
|
||||
@@ -22,7 +22,7 @@ cw-storage-plus = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
cw4 = { workspace = true }
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.23"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = { workspace = true }
|
||||
|
||||
@@ -22,7 +22,7 @@ cw-utils = { workspace = true }
|
||||
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.23"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
nym-coconut-bandwidth = { path = "../coconut-bandwidth" }
|
||||
nym-coconut-dkg = { path = "../coconut-dkg" }
|
||||
|
||||
@@ -23,7 +23,7 @@ cw-controllers = { workspace = true }
|
||||
cw4 = { workspace = true }
|
||||
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.23"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cw-multi-test = { workspace = true }
|
||||
|
||||
@@ -243,7 +243,7 @@ impl TestSetup {
|
||||
ContractMessageContent::new(Addr::unchecked(owner), proxy, vec![stake], payload);
|
||||
let sign_payload = SignableMixNodeBondingMsg::new(signing_nonce, content);
|
||||
let plaintext = sign_payload.to_plaintext().unwrap();
|
||||
let signature = keypair.private_key().sign(&plaintext);
|
||||
let signature = keypair.private_key().sign(plaintext);
|
||||
let msg_signature = MessageSignature::from(signature.to_bytes().as_ref());
|
||||
|
||||
(mixnode, msg_signature)
|
||||
|
||||
@@ -39,7 +39,7 @@ cw-storage-plus = { workspace = true }
|
||||
|
||||
bs58 = "0.4.0"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
thiserror = { workspace = true }
|
||||
time = { version = "0.3", features = ["macros"] }
|
||||
semver = { version = "1.0.16", default-features = false }
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ pub mod test_helpers {
|
||||
|
||||
let sig_bytes = family_owner_keys
|
||||
.private_key()
|
||||
.sign(&msg.to_plaintext().unwrap())
|
||||
.sign(msg.to_plaintext().unwrap())
|
||||
.to_bytes();
|
||||
MessageSignature::from(sig_bytes.as_ref())
|
||||
}
|
||||
@@ -956,7 +956,7 @@ pub mod test_helpers {
|
||||
match message.algorithm {
|
||||
SigningAlgorithm::Ed25519 => {
|
||||
let plaintext = message.to_plaintext().unwrap();
|
||||
let signature = private_key.sign(&plaintext);
|
||||
let signature = private_key.sign(plaintext);
|
||||
MessageSignature::from(signature.to_bytes().as_ref())
|
||||
}
|
||||
SigningAlgorithm::Secp256k1 => {
|
||||
|
||||
@@ -41,5 +41,5 @@ cosmwasm-schema = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
schemars = "0.8.1"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0.23" }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts
|
||||
nym-name-service-common = { path = "../../common/cosmwasm-smart-contracts/name-service" }
|
||||
semver = { version = "1.0.16", default-features = false }
|
||||
serde = { version = "1.0.155", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.39"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] }
|
||||
|
||||
@@ -29,7 +29,7 @@ pub fn ed25519_sign_message<T: Serialize + SigningPurpose>(
|
||||
match message.algorithm {
|
||||
SigningAlgorithm::Ed25519 => {
|
||||
let plaintext = message.to_plaintext().unwrap();
|
||||
let signature = private_key.sign(&plaintext);
|
||||
let signature = private_key.sign(plaintext);
|
||||
MessageSignature::from(signature.to_bytes().as_ref())
|
||||
}
|
||||
SigningAlgorithm::Secp256k1 => {
|
||||
|
||||
@@ -22,7 +22,7 @@ nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts
|
||||
nym-service-provider-directory-common = { path = "../../common/cosmwasm-smart-contracts/service-provider-directory" }
|
||||
semver = { version = "1.0.16", default-features = false }
|
||||
serde = { version = "1.0.155", default-features = false, features = ["derive"] }
|
||||
thiserror = "1.0.39"
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "=7.4.3", default-features = false, features = ["build", "git", "rustc"] }
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn ed25519_sign_message<T: Serialize + SigningPurpose>(
|
||||
match message.algorithm {
|
||||
SigningAlgorithm::Ed25519 => {
|
||||
let plaintext = message.to_plaintext().unwrap();
|
||||
let signature = private_key.sign(&plaintext);
|
||||
let signature = private_key.sign(plaintext);
|
||||
MessageSignature::from(signature.to_bytes().as_ref())
|
||||
}
|
||||
SigningAlgorithm::Secp256k1 => {
|
||||
|
||||
@@ -35,7 +35,7 @@ cw2 = { workspace = true }
|
||||
cw-storage-plus = { workspace = true, features = ["iterator"] }
|
||||
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0" }
|
||||
thiserror ={ workspace = true }
|
||||
semver = { version = "1.0.16", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -40,7 +40,7 @@ Yes, to run a mix node only is an option. However it will be less rewarded as no
|
||||
|
||||
### What are the incentives for the node operator?
|
||||
|
||||
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic (`[Nym API](https://github.com/nymtech/nym/tree/master/nym-api)` will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
|
||||
In the original setup there were no incentives to run a `network-requester`. After the transition all the users will buy multiple tickets of zkNyms credentials and use those as [anonymous e-cash](https://arxiv.org/abs/2303.08221) to pay for their data traffic ([`Nym API`](https://github.com/nymtech/nym/tree/master/nym-api) will do the do cryptographical checks to prevent double-spending). All collected fees get distributed to all active nodes proportionally to their work by the end of each epoch.
|
||||
|
||||
### How does this change the token economics?
|
||||
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ nym-config = { path = "../common/config" }
|
||||
nym-ephemera-common = { path = "../common/cosmwasm-smart-contracts/ephemera" }
|
||||
pretty_env_logger = "0.4"
|
||||
refinery = { version = "0.8.7", features = ["rusqlite"], optional = true }
|
||||
reqwest = { version = "0.11.6", features = ["json"] }
|
||||
reqwest = { version = "0.11.22", features = ["json"] }
|
||||
# Rocksdb kills compilation times and we're not currently using it. The reason
|
||||
# we comment it out is that rust-analyzer runs with --all-features
|
||||
#rocksdb = { version = "0.21.0", optional = true }
|
||||
@@ -44,14 +44,14 @@ rusqlite = { version = "0.27.0", features = ["bundled"], optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_derive = "1.0.149"
|
||||
serde_json = "1.0.91"
|
||||
thiserror = "1.0.37"
|
||||
thiserror = { workspace = true }
|
||||
tokio = { version = "1", features = ["macros", "net","rt-multi-thread"] }
|
||||
tokio-tungstenite = { workspace = true }
|
||||
tokio-util = { version = "0.7.4", features = ["full"] }
|
||||
toml = "0.7.0"
|
||||
unsigned-varint = "0.7.1"
|
||||
utoipa = { version = "3.0.1", features = ["actix_extras"] }
|
||||
utoipa-swagger-ui = { version = "3.0.2", features = ["actix-web"] }
|
||||
utoipa = { workspace = true, features = ["actix_extras"] }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["actix-web"] }
|
||||
uuid = { version = "1.2.2", features = ["v4"] }
|
||||
|
||||
# Temporary fix to https://github.com/bluejekyll/trust-dns/issues/1946
|
||||
|
||||
@@ -24,10 +24,10 @@ 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"] }
|
||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
||||
serde = "1.0.126"
|
||||
serde_json = "1.0.66"
|
||||
thiserror = "1.0.29"
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = {version = "1.21.2", features = ["full"] }
|
||||
|
||||
nym-bin-common = { path = "../common/bin-common"}
|
||||
|
||||
@@ -7,6 +7,6 @@ edition = "2021"
|
||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common" }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
schemars = { version = "0.8", features = ["preserve_order"] }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
ts-rs = { workspace = true, optional = true }
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::helpers::best_effort_small_dec_to_f64;
|
||||
use crate::mix_node::models::EconomicDynamicsStats;
|
||||
use nym_contracts_common::truncate_decimal;
|
||||
use nym_mixnet_contract_common::MixId;
|
||||
use nym_validator_client::client::NymApiClientExt;
|
||||
|
||||
pub(crate) async fn retrieve_mixnode_econ_stats(
|
||||
client: &ThreadsafeValidatorClient,
|
||||
|
||||
+30
-3
@@ -15,6 +15,15 @@ rust-version = "1.56"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum = "0.6.20"
|
||||
sha2 = "0.10.8"
|
||||
hmac = "0.12.1"
|
||||
axum-macros = "0.3.8" # Useful for debugging axum Handler trait errors
|
||||
fastrand = "2"
|
||||
x25519-dalek = { version = "2.0.0", features = ["static_secrets"] }
|
||||
base64 = "0.21.4"
|
||||
|
||||
|
||||
anyhow = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
atty = "0.2"
|
||||
@@ -34,10 +43,21 @@ pretty_env_logger = "0.4"
|
||||
rand = "0.7"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "sqlite", "macros", "migrate", ] }
|
||||
sqlx = { version = "0.5", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
"macros",
|
||||
"migrate",
|
||||
] }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"] }
|
||||
thiserror = "1"
|
||||
tokio = { workspace = true, features = [ "rt-multi-thread", "net", "signal", "fs", "time" ] }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = [
|
||||
"rt-multi-thread",
|
||||
"net",
|
||||
"signal",
|
||||
"fs",
|
||||
"time",
|
||||
] }
|
||||
tokio-stream = { version = "0.1.11", features = ["fs"] }
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = { version = "0.7.4", features = ["codec"] }
|
||||
@@ -45,6 +65,8 @@ url = { version = "2.2", features = ["serde"] }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
# internal
|
||||
nym-node = { path = "../nym-node" }
|
||||
|
||||
nym-api-requests = { path = "../nym-api/nym-api-requests" }
|
||||
nym-bin-common = { path = "../common/bin-common", features = ["output_format"] }
|
||||
nym-coconut-interface = { path = "../common/coconut-interface" }
|
||||
@@ -64,6 +86,11 @@ nym-types = { path = "../common/types" }
|
||||
nym-validator-client = { path = "../common/client-libs/validator-client" }
|
||||
nym-wireguard = { path = "../common/wireguard", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tower = "0.4.13"
|
||||
rand = "0.8.5"
|
||||
hyper = "0.14.27"
|
||||
|
||||
[build-dependencies]
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
sqlx = { version = "0.5", features = [
|
||||
|
||||
@@ -17,7 +17,7 @@ log = { workspace = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
thiserror = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
nym-crypto = { path = "../../common/crypto" }
|
||||
|
||||
@@ -137,7 +137,7 @@ impl<'a, S> State<'a, S> {
|
||||
.chain(remote_ephemeral_key.to_bytes().iter().cloned())
|
||||
.collect();
|
||||
|
||||
let signature = self.identity.private_key().sign(&message);
|
||||
let signature = self.identity.private_key().sign(message);
|
||||
let zero_iv = stream_cipher::zero_iv::<GatewayEncryptionAlgorithm>();
|
||||
stream_cipher::encrypt::<GatewayEncryptionAlgorithm>(
|
||||
self.derived_shared_keys.as_ref().unwrap().encryption_key(),
|
||||
@@ -191,7 +191,7 @@ impl<'a, S> State<'a, S> {
|
||||
self.remote_pubkey
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.verify(&signed_payload, &signature)
|
||||
.verify(signed_payload, &signature)
|
||||
.map_err(|_| HandshakeError::InvalidSignature)
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ pub(crate) struct OverrideConfig {
|
||||
impl OverrideConfig {
|
||||
pub(crate) fn do_override(self, mut config: Config) -> Result<Config, GatewayError> {
|
||||
config = config
|
||||
.with_optional(Config::with_listening_address, self.host)
|
||||
.with_optional(Config::with_host, self.host)
|
||||
.with_optional(Config::with_mix_port, self.mix_port)
|
||||
.with_optional(Config::with_clients_port, self.clients_port)
|
||||
.with_optional_custom_env(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::config::old_config_v1_1_20::ConfigV1_1_20;
|
||||
use crate::config::old_config_v1_1_28::ConfigV1_1_28;
|
||||
use crate::config::old_config_v1_1_29::ConfigV1_1_29;
|
||||
use crate::config::{default_config_filepath, Config};
|
||||
use crate::error::GatewayError;
|
||||
use log::info;
|
||||
@@ -20,7 +21,8 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, GatewayError> {
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_28 = old_config.into();
|
||||
let updated: Config = updated_step1.into();
|
||||
let updated_step2: ConfigV1_1_29 = updated_step1.into();
|
||||
let updated: Config = updated_step2.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
.map_err(|err| GatewayError::ConfigSaveFailure {
|
||||
@@ -42,6 +44,29 @@ fn try_upgrade_v1_1_28_config(id: &str) -> Result<bool, GatewayError> {
|
||||
info!("It seems the gateway is using <= v1.1.28 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated_step1: ConfigV1_1_29 = old_config.into();
|
||||
let updated: Config = updated_step1.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
.map_err(|err| GatewayError::ConfigSaveFailure {
|
||||
path: default_config_filepath(id),
|
||||
id: id.to_string(),
|
||||
source: err,
|
||||
})?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_29_config(id: &str) -> Result<bool, GatewayError> {
|
||||
// explicitly load it as v1.1.29 (which is incompatible with the current, i.e. 1.1.30+)
|
||||
let Ok(old_config) = ConfigV1_1_29::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
|
||||
return Ok(false);
|
||||
};
|
||||
info!("It seems the gateway is using <= v1.1.29 config template.");
|
||||
info!("It is going to get updated to the current specification.");
|
||||
|
||||
let updated: Config = old_config.into();
|
||||
updated
|
||||
.save_to_default_location()
|
||||
@@ -61,6 +86,9 @@ pub(crate) fn try_upgrade_config(id: &str) -> Result<(), GatewayError> {
|
||||
if try_upgrade_v1_1_28_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
if try_upgrade_v1_1_29_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -12,9 +12,10 @@ use nym_config::{
|
||||
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
|
||||
};
|
||||
use nym_network_defaults::mainnet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use nym_node::config;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::io;
|
||||
use std::net::IpAddr;
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -22,6 +23,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
pub(crate) mod old_config_v1_1_20;
|
||||
pub(crate) mod old_config_v1_1_28;
|
||||
pub(crate) mod old_config_v1_1_29;
|
||||
pub mod persistence;
|
||||
mod template;
|
||||
|
||||
@@ -38,6 +40,18 @@ const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000;
|
||||
const DEFAULT_STORED_MESSAGE_FILENAME_LENGTH: u16 = 16;
|
||||
const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
|
||||
|
||||
fn de_maybe_port<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let port = u16::deserialize(deserializer)?;
|
||||
if port == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(port))
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive default path to gateway's config directory.
|
||||
/// It should get resolved to `$HOME/.nym/gateways/<id>/config`
|
||||
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
@@ -71,8 +85,17 @@ pub struct Config {
|
||||
#[serde(skip)]
|
||||
pub(crate) save_path: Option<PathBuf>,
|
||||
|
||||
pub host: config::Host,
|
||||
|
||||
#[serde(default)]
|
||||
pub http: config::Http,
|
||||
|
||||
pub gateway: Gateway,
|
||||
|
||||
#[serde(default)]
|
||||
// currently not really used for anything useful
|
||||
pub wireguard: config::Wireguard,
|
||||
|
||||
pub storage_paths: GatewayPaths,
|
||||
|
||||
pub network_requester: NetworkRequester,
|
||||
@@ -92,9 +115,16 @@ impl NymConfigTemplate for Config {
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: AsRef<str>>(id: S) -> Self {
|
||||
let default_gateway = Gateway::new_default(id.as_ref());
|
||||
Config {
|
||||
save_path: None,
|
||||
gateway: Gateway::new_default(id.as_ref()),
|
||||
host: config::Host {
|
||||
public_ips: vec![default_gateway.listening_address],
|
||||
..Default::default()
|
||||
},
|
||||
http: Default::default(),
|
||||
gateway: default_gateway,
|
||||
wireguard: Default::default(),
|
||||
storage_paths: GatewayPaths::new_default(id.as_ref()),
|
||||
network_requester: Default::default(),
|
||||
logging: Default::default(),
|
||||
@@ -182,8 +212,16 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self {
|
||||
pub fn with_host(mut self, listening_address: IpAddr) -> Self {
|
||||
self.gateway.listening_address = listening_address;
|
||||
|
||||
// temporary workaround
|
||||
self.host.public_ips = vec![listening_address];
|
||||
let http_port = self.http.bind_address.port();
|
||||
self.http.bind_address = SocketAddr::new(listening_address, http_port);
|
||||
let wg_port = self.wireguard.bind_address.port();
|
||||
self.wireguard.bind_address = SocketAddr::new(listening_address, wg_port);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
@@ -245,6 +283,11 @@ pub struct Gateway {
|
||||
/// (default: 9000)
|
||||
pub clients_port: u16,
|
||||
|
||||
/// If applicable, announced port for listening for secure websocket client traffic.
|
||||
/// (default: None)
|
||||
#[serde(deserialize_with = "de_maybe_port")]
|
||||
pub clients_wss_port: Option<u16>,
|
||||
|
||||
/// Whether gateway collects and sends anonymized statistics
|
||||
pub enabled_statistics: bool,
|
||||
|
||||
@@ -279,6 +322,7 @@ impl Gateway {
|
||||
listening_address: inaddr_any(),
|
||||
mix_port: DEFAULT_MIX_LISTENING_PORT,
|
||||
clients_port: DEFAULT_CLIENT_LISTENING_PORT,
|
||||
clients_wss_port: None,
|
||||
enabled_statistics: false,
|
||||
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS
|
||||
.parse()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::persistence::paths::{GatewayPaths, KeysPaths};
|
||||
use crate::config::{Config, Debug, Gateway};
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use crate::config::old_config_v1_1_29::{
|
||||
ConfigV1_1_29, DebugV1_1_29, GatewayPathsV1_1_29, GatewayV1_1_29, KeysPathsV1_1_29,
|
||||
LoggingSettingsV1_1_29,
|
||||
};
|
||||
use nym_config::{
|
||||
must_get_home, read_config_from_toml_file, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, NYM_DIR,
|
||||
};
|
||||
@@ -84,11 +85,13 @@ impl ConfigV1_1_28 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigV1_1_28> for Config {
|
||||
impl From<ConfigV1_1_28> for ConfigV1_1_29 {
|
||||
fn from(value: ConfigV1_1_28) -> Self {
|
||||
Config {
|
||||
ConfigV1_1_29 {
|
||||
// \/ ADDED
|
||||
save_path: None,
|
||||
gateway: Gateway {
|
||||
// /\ ADDED
|
||||
gateway: GatewayV1_1_29 {
|
||||
version: value.gateway.version,
|
||||
id: value.gateway.id,
|
||||
only_coconut_credentials: value.gateway.only_coconut_credentials,
|
||||
@@ -101,19 +104,25 @@ impl From<ConfigV1_1_28> for Config {
|
||||
statistics_service_url: value.gateway.statistics_service_url,
|
||||
cosmos_mnemonic: value.gateway.cosmos_mnemonic,
|
||||
},
|
||||
storage_paths: GatewayPaths {
|
||||
keys: KeysPaths {
|
||||
storage_paths: GatewayPathsV1_1_29 {
|
||||
keys: KeysPathsV1_1_29 {
|
||||
private_identity_key_file: value.storage_paths.keys.private_identity_key_file,
|
||||
public_identity_key_file: value.storage_paths.keys.public_identity_key_file,
|
||||
private_sphinx_key_file: value.storage_paths.keys.private_sphinx_key_file,
|
||||
public_sphinx_key_file: value.storage_paths.keys.public_sphinx_key_file,
|
||||
},
|
||||
clients_storage: value.storage_paths.clients_storage,
|
||||
|
||||
// \/ ADDED
|
||||
network_requester_config: None,
|
||||
// /\ ADDED
|
||||
},
|
||||
|
||||
// \/ ADDED
|
||||
network_requester: Default::default(),
|
||||
logging: LoggingSettings {},
|
||||
debug: Debug {
|
||||
// /\ ADDED
|
||||
logging: LoggingSettingsV1_1_29 {},
|
||||
debug: DebugV1_1_29 {
|
||||
packet_forwarding_initial_backoff: value.debug.packet_forwarding_initial_backoff,
|
||||
packet_forwarding_maximum_backoff: value.debug.packet_forwarding_maximum_backoff,
|
||||
initial_connection_timeout: value.debug.initial_connection_timeout,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user