Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f25f76c1df | |||
| 096a599673 | |||
| 41da67ad6f | |||
| 273a741cdf | |||
| b5c8b69547 | |||
| 29f95febe9 |
+2
-1
@@ -42,4 +42,5 @@ storybook-static
|
||||
envs/qwerty.env
|
||||
.parcel-cache
|
||||
**/.DS_Store
|
||||
cpu-cycles/libcpucycles/build
|
||||
cpu-cycles/libcpucycles/build
|
||||
foxyfox.env
|
||||
Generated
+133
-217
@@ -73,6 +73,17 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.1"
|
||||
@@ -222,7 +233,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -233,7 +244,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -256,12 +267,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.5.1"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
]
|
||||
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
@@ -525,9 +533,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.1"
|
||||
version = "3.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8"
|
||||
checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
@@ -626,9 +634,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
|
||||
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
@@ -637,15 +645,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
|
||||
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
|
||||
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
@@ -710,9 +718,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.2.1"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473"
|
||||
checksum = "1594fe2312ec4abf402076e407628f5c313e54c32ade058521df4ee34ecac8a8"
|
||||
dependencies = [
|
||||
"clap 4.2.7",
|
||||
]
|
||||
@@ -736,7 +744,7 @@ dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -763,16 +771,6 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
@@ -814,9 +812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e57ff02e8ad8e06ab9731d5dc72dc23bef9200778eae1a89d555d8c42e5d4a86"
|
||||
checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e"
|
||||
dependencies = [
|
||||
"prost 0.11.9",
|
||||
"prost-types 0.11.9",
|
||||
@@ -826,9 +824,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console-subscriber"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a3a81dfaf6b66bce5d159eddae701e3a002f194d378cbf7be5f053c281d9be"
|
||||
checksum = "57ab2224a0311582eb03adba4caaf18644f7b1f10a760803a803b9b605187fc7"
|
||||
dependencies = [
|
||||
"console-api",
|
||||
"crossbeam-channel",
|
||||
@@ -874,7 +872,7 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"sha2 0.10.6",
|
||||
"subtle 2.4.1",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -1304,50 +1302,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.13.4"
|
||||
@@ -1623,7 +1577,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1960,7 +1914,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2089,7 +2043,7 @@ checksum = "e77ac7b51b8e6313251737fcef4b1c01a2ea102bde68415b62c0ee9268fec357"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2149,9 +2103,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.18"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21"
|
||||
checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@@ -2192,7 +2146,7 @@ version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2201,7 +2155,16 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2215,11 +2178,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
|
||||
checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa"
|
||||
dependencies = [
|
||||
"hashbrown 0.12.3",
|
||||
"hashbrown 0.13.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2525,12 +2488,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2574,7 +2536,7 @@ checksum = "bfbcff6ae46750b15cc594bfd277b188cbddcfdc1817848f97f03f26f8625b9e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"uuid 1.3.2",
|
||||
"uuid 1.3.3",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
@@ -2886,9 +2848,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.142"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
@@ -2904,9 +2866,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
|
||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
@@ -2931,15 +2893,6 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.7"
|
||||
@@ -3145,9 +3098,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.1.0"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9"
|
||||
checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossbeam-channel",
|
||||
@@ -3158,7 +3111,7 @@ dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"walkdir",
|
||||
"windows-sys 0.42.0",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3283,7 +3236,7 @@ dependencies = [
|
||||
"sqlx 0.6.3",
|
||||
"tap",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"ts-rs",
|
||||
@@ -3413,7 +3366,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tap",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
@@ -3485,7 +3438,7 @@ dependencies = [
|
||||
"tap",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-tungstenite 0.14.0",
|
||||
@@ -3836,7 +3789,7 @@ dependencies = [
|
||||
"serde-json-wasm",
|
||||
"serde_repr",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
@@ -4017,6 +3970,7 @@ dependencies = [
|
||||
"log",
|
||||
"nym-crypto",
|
||||
"nym-sphinx",
|
||||
"nym-sphinx-params",
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"rand 0.7.3",
|
||||
@@ -4058,8 +4012,10 @@ dependencies = [
|
||||
"curve25519-dalek",
|
||||
"fastrand",
|
||||
"getrandom 0.2.9",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"sphinx-packet 0.1.0 (git+https://github.com/nymtech/sphinx.git)",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4193,6 +4149,7 @@ dependencies = [
|
||||
"jni",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
@@ -4237,7 +4194,6 @@ dependencies = [
|
||||
"log",
|
||||
"nym-crypto",
|
||||
"nym-mixnet-contract-common",
|
||||
"nym-outfox",
|
||||
"nym-sphinx-acknowledgements",
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-anonymous-replies",
|
||||
@@ -4336,6 +4292,7 @@ dependencies = [
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-params",
|
||||
"nym-sphinx-types",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4372,7 +4329,9 @@ dependencies = [
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"sphinx-packet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nym-outfox",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4611,7 +4570,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4809,7 +4768,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics 0.10.0",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4886,7 +4845,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4902,22 +4861,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.12"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
|
||||
checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.12"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
|
||||
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5052,9 +5011,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.56"
|
||||
version = "1.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -5080,7 +5039,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
@@ -5175,9 +5134,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -5470,7 +5429,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5507,9 +5466,9 @@ checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.17"
|
||||
version = "0.11.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
|
||||
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
@@ -5610,7 +5569,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"state",
|
||||
"tempfile",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
@@ -5672,7 +5631,7 @@ dependencies = [
|
||||
"smallvec",
|
||||
"stable-pattern",
|
||||
"state",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tokio",
|
||||
"uncased",
|
||||
]
|
||||
@@ -5881,12 +5840,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.6.1"
|
||||
@@ -5922,9 +5875,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
||||
checksum = "ca2855b3715770894e67cbfa3df957790aa0c9edc3bf06efa1a84d77fa0839d1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
@@ -5935,9 +5888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
@@ -5984,9 +5937,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.162"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
|
||||
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -6022,13 +5975,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.162"
|
||||
version = "1.0.163"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
|
||||
checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6061,7 +6014,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6267,29 +6220,6 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sphinx-packet"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/nymtech/sphinx.git#ca107d94360cdf8bbfbdb12fe5320ed74f80e40c"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"arrayref",
|
||||
"blake2 0.8.1",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
"chacha",
|
||||
"curve25519-dalek",
|
||||
"digest 0.9.0",
|
||||
"hkdf 0.11.0",
|
||||
"hmac 0.11.0",
|
||||
"lioness",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rand_distr",
|
||||
"sha2 0.9.9",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
@@ -6363,7 +6293,7 @@ version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
"atoi 0.4.0",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
@@ -6409,7 +6339,7 @@ version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
"atoi 1.0.0",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
@@ -6426,7 +6356,7 @@ dependencies = [
|
||||
"futures-executor",
|
||||
"futures-intrusive",
|
||||
"futures-util",
|
||||
"hashlink 0.8.1",
|
||||
"hashlink 0.8.2",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
@@ -6625,9 +6555,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
version = "2.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6701,7 +6631,7 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
"subtle-encoding",
|
||||
"tendermint-proto",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -6734,7 +6664,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
"subtle-encoding",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6762,7 +6692,7 @@ dependencies = [
|
||||
"tendermint-config",
|
||||
"tendermint-proto",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
@@ -6802,7 +6732,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6828,9 +6758,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.20"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"js-sys",
|
||||
@@ -6841,15 +6771,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
@@ -6881,9 +6811,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.28.0"
|
||||
version = "1.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f"
|
||||
checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"bytes",
|
||||
@@ -6917,7 +6847,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7040,14 +6970,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.8.3"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb"
|
||||
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.13.1",
|
||||
"base64 0.21.0",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -7059,15 +6988,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost 0.11.9",
|
||||
"prost-derive 0.11.9",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"tracing-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7121,7 +7047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
@@ -7133,29 +7059,19 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-futures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
@@ -7316,9 +7232,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
version = "0.9.7"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622"
|
||||
checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"version_check",
|
||||
@@ -7457,9 +7373,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.2"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
|
||||
checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
|
||||
dependencies = [
|
||||
"getrandom 0.2.9",
|
||||
"wasm-bindgen",
|
||||
@@ -7491,7 +7407,7 @@ dependencies = [
|
||||
"rustc_version 0.4.0",
|
||||
"rustversion",
|
||||
"thiserror",
|
||||
"time 0.3.20",
|
||||
"time 0.3.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7944,5 +7860,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
+13
-10
@@ -116,18 +116,21 @@ async-trait = "0.1.64"
|
||||
anyhow = "1.0.71"
|
||||
bip39 = { version = "2.0.0", features = ["zeroize"] }
|
||||
cfg-if = "1.0.0"
|
||||
cosmwasm-derive = "=1.0.0"
|
||||
cosmwasm-schema = "=1.0.0"
|
||||
cosmwasm-std = "=1.0.0"
|
||||
cosmwasm-storage = "=1.0.0"
|
||||
cw-utils = "=0.13.4"
|
||||
cw-storage-plus = "=0.13.4"
|
||||
cw2 = { version = "=0.13.4" }
|
||||
cw3 = { version = "=0.13.4" }
|
||||
cw3-fixed-multisig = { version = "=0.13.4" }
|
||||
cw4 = { version = "=0.13.4" }
|
||||
cosmwasm-derive = "=1.2.5"
|
||||
cosmwasm-schema = "=1.2.5"
|
||||
cosmwasm-std = "=1.2.5"
|
||||
cosmwasm-storage = "=1.2.5"
|
||||
cosmrs = "=0.8.0"
|
||||
cw-utils = "=1.0.1"
|
||||
cw-storage-plus = "=1.0.1"
|
||||
cw2 = { version = "=1.0.1" }
|
||||
cw3 = { version = "=1.0.1" }
|
||||
cw3-fixed-multisig = { version = "=1.0.1" }
|
||||
cw4 = { version = "=1.0.1" }
|
||||
cw-controllers = { version = "=1.0.1" }
|
||||
dotenvy = "0.15.6"
|
||||
generic-array = "0.14.7"
|
||||
k256 = "0.11"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4"
|
||||
once_cell = "1.7.2"
|
||||
|
||||
@@ -20,6 +20,7 @@ use nym_client_core::client::received_buffer::{
|
||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||
@@ -63,6 +64,7 @@ impl SocketClient {
|
||||
client_state: ClientState,
|
||||
self_address: &Recipient,
|
||||
shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
info!("Starting websocket listener...");
|
||||
|
||||
@@ -88,6 +90,7 @@ impl SocketClient {
|
||||
self_address,
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
Some(packet_type),
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
||||
@@ -137,7 +140,8 @@ impl SocketClient {
|
||||
}
|
||||
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
@@ -150,6 +154,7 @@ impl SocketClient {
|
||||
client_state,
|
||||
&self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
packet_type,
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
@@ -164,7 +169,8 @@ impl SocketClient {
|
||||
}
|
||||
|
||||
let base_builder = self.create_base_client_builder().await?;
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
@@ -186,6 +192,7 @@ impl SocketClient {
|
||||
reconstructed_receiver,
|
||||
address,
|
||||
shutdown_notifier: started_client.task_manager,
|
||||
packet_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -199,6 +206,7 @@ pub struct DirectClient {
|
||||
|
||||
// we need to keep reference to this guy otherwise things will start dropping
|
||||
shutdown_notifier: TaskManager,
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl DirectClient {
|
||||
@@ -219,7 +227,7 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, Some(self.packet_type));
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -238,7 +246,13 @@ impl DirectClient {
|
||||
reply_surbs: u32,
|
||||
) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg = InputMessage::new_anonymous(
|
||||
recipient,
|
||||
message,
|
||||
reply_surbs,
|
||||
lane,
|
||||
Some(self.packet_type),
|
||||
);
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -252,7 +266,8 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_reply(recipient_tag, message, lane, Some(self.packet_type));
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
|
||||
@@ -14,6 +14,7 @@ use nym_client_core::client::{
|
||||
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
@@ -41,6 +42,7 @@ pub(crate) struct HandlerBuilder {
|
||||
self_full_address: Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl HandlerBuilder {
|
||||
@@ -51,6 +53,7 @@ impl HandlerBuilder {
|
||||
self_full_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
Self {
|
||||
msg_input,
|
||||
@@ -59,6 +62,7 @@ impl HandlerBuilder {
|
||||
self_full_address: *self_full_address,
|
||||
lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +77,7 @@ impl HandlerBuilder {
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
reply_controller_sender: self.reply_controller_sender.clone(),
|
||||
packet_type: self.packet_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +91,7 @@ pub(crate) struct Handler {
|
||||
received_response_type: ReceivedResponseType,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
@@ -160,7 +166,7 @@ impl Handler {
|
||||
});
|
||||
|
||||
// the ack control is now responsible for chunking, etc.
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -191,7 +197,8 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -218,7 +225,7 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
|
||||
@@ -91,6 +91,7 @@ impl From<Init> for OverrideConfig {
|
||||
no_cover: init_config.no_cover,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
outfox: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_config::{NymConfig, OptionalSet};
|
||||
use nym_socks5_client_core::config::old_config_v1_1_13::OldConfigV1_1_13;
|
||||
use nym_socks5_client_core::config::{BaseConfig, Config};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -64,6 +65,7 @@ pub(crate) struct OverrideConfig {
|
||||
no_cover: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
@@ -80,9 +82,15 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
PacketType::Mix
|
||||
};
|
||||
config
|
||||
.with_base(BaseConfig::with_high_default_traffic_volume, args.fastmode)
|
||||
.with_base(BaseConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
.with_optional(Config::with_port, args.port)
|
||||
.with_optional_custom_env_ext(
|
||||
|
||||
@@ -68,6 +68,9 @@ pub(crate) struct Run {
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long, hide = true)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
#[clap(long, hide = true, action)]
|
||||
outfox: bool,
|
||||
}
|
||||
|
||||
impl From<Run> for OverrideConfig {
|
||||
@@ -80,6 +83,7 @@ impl From<Run> for OverrideConfig {
|
||||
no_cover: run_config.no_cover,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
outfox: run_config.outfox,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
bin/
|
||||
pkg/
|
||||
wasm-pack.log
|
||||
|
||||
Generated
+5175
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ use nym_client_core::config::{
|
||||
DebugConfig as ConfigDebug, GatewayConnection as ConfigGatewayConnection,
|
||||
ReplySurbs as ConfigReplySurbs, Topology as ConfigTopology, Traffic as ConfigTraffic,
|
||||
};
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
@@ -34,6 +34,8 @@ pub struct Config {
|
||||
pub(crate) gateway: Option<IdentityKey>,
|
||||
|
||||
pub(crate) debug: ConfigDebug,
|
||||
|
||||
pub(crate) packet_type: PacketType,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -42,9 +44,18 @@ impl Config {
|
||||
pub fn new(
|
||||
id: String,
|
||||
validator_server: String,
|
||||
packet_type: Option<String>,
|
||||
gateway: Option<IdentityKey>,
|
||||
debug: Option<Debug>,
|
||||
) -> Self {
|
||||
let packet_type = if let Some(packet_type) = packet_type {
|
||||
match packet_type.as_str() {
|
||||
"outfox" => PacketType::Outfox,
|
||||
_ => PacketType::Mix,
|
||||
}
|
||||
} else {
|
||||
PacketType::Mix
|
||||
};
|
||||
Config {
|
||||
id,
|
||||
nym_api_url: Some(
|
||||
@@ -55,6 +66,7 @@ impl Config {
|
||||
disabled_credentials_mode: true,
|
||||
gateway,
|
||||
debug: debug.map(Into::into).unwrap_or_default(),
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,6 +109,7 @@ impl From<Traffic> for ConfigTraffic {
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: use_extended_packet_size,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ use nym_client_core::client::inbound_messages::InputMessage;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_client_core::config::{CoverTraffic, DebugConfig, Topology, Traffic};
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use nym_topology::provider_trait::{HardcodedTopologyProvider, TopologyProvider};
|
||||
@@ -52,6 +53,7 @@ pub struct NymClient {
|
||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
||||
// and if it's dropped, everything will start going offline
|
||||
_task_manager: TaskManager,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -68,6 +70,7 @@ pub struct NymClientBuilder {
|
||||
bandwidth_controller:
|
||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||
disabled_credentials: bool,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -86,6 +89,7 @@ impl NymClientBuilder {
|
||||
on_message,
|
||||
bandwidth_controller: None,
|
||||
disabled_credentials: true,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +128,7 @@ impl NymClientBuilder {
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
packet_type: PacketType::Mix,
|
||||
};
|
||||
|
||||
NymClientBuilder {
|
||||
@@ -136,6 +141,7 @@ impl NymClientBuilder {
|
||||
bandwidth_controller: None,
|
||||
disabled_credentials: true,
|
||||
storage_passphrase: None,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +208,8 @@ impl NymClientBuilder {
|
||||
base_builder = base_builder.with_topology_provider(topology_provider);
|
||||
}
|
||||
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.packet_type;
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address.to_string();
|
||||
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
@@ -216,6 +223,7 @@ impl NymClientBuilder {
|
||||
client_state: Arc::new(started_client.client_state),
|
||||
_full_topology: None,
|
||||
_task_manager: started_client.task_manager,
|
||||
packet_type: self.packet_type,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -291,7 +299,7 @@ impl NymClient {
|
||||
let input_msgs = request
|
||||
.test_msgs
|
||||
.into_iter()
|
||||
.map(|p| InputMessage::new_regular(recipient, p, lane))
|
||||
.map(|p| InputMessage::new_regular(recipient, p, lane, None))
|
||||
.collect();
|
||||
|
||||
self.client_input.send_messages(input_msgs)
|
||||
@@ -311,7 +319,7 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -338,7 +346,8 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -356,7 +365,7 @@ impl NymClient {
|
||||
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ mod v1 {
|
||||
pub const GATEWAY_CONFIG: &str = "gateway_config";
|
||||
|
||||
pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair";
|
||||
pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_key";
|
||||
pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_keypair";
|
||||
|
||||
// TODO: for those we could actually use the subtle crypto storage
|
||||
pub const AES128CTR_ACK_KEY: &str = "aes128ctr_ack_key";
|
||||
|
||||
@@ -130,7 +130,7 @@ impl AsyncFileWatcher {
|
||||
Ok(event) => {
|
||||
let now = Instant::now();
|
||||
if self.should_propagate(&event, now) {
|
||||
self.last_received.insert(event.kind.clone(), now);
|
||||
self.last_received.insert(event.kind, now);
|
||||
if let Err(_err) = self.event_sender.unbounded_send(event) {
|
||||
log::error!("the file watcher receiver has been dropped!");
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ use nym_gateway_client::{
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::{ReconstructedMessage, SphinxMessageReceiver};
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
@@ -275,6 +276,7 @@ where
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_connection_rx: ConnectionCommandReceiver,
|
||||
shutdown: TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
info!("Starting real traffic stream...");
|
||||
|
||||
@@ -290,7 +292,7 @@ where
|
||||
lane_queue_lengths,
|
||||
client_connection_rx,
|
||||
)
|
||||
.start_with_shutdown(shutdown);
|
||||
.start_with_shutdown(shutdown, packet_type);
|
||||
}
|
||||
|
||||
// buffer controlling all messages fetched from provider
|
||||
@@ -426,7 +428,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
||||
// controller for sending packets to mixnet (either real traffic or cover traffic)
|
||||
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
|
||||
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
||||
// requests?
|
||||
@@ -477,7 +479,10 @@ where
|
||||
self.managed_keys = ManagedKeys::load_or_generate(&mut rng, &self.key_store).await;
|
||||
}
|
||||
|
||||
pub async fn start_base(mut self) -> Result<BaseClient, ClientCoreError>
|
||||
pub async fn start_base(
|
||||
mut self,
|
||||
packet_type: PacketType,
|
||||
) -> Result<BaseClient, ClientCoreError>
|
||||
where
|
||||
<S::ReplyStore as ReplyStorageBackend>::StorageError: Sync + Send,
|
||||
S::ReplyStore: Send + Sync,
|
||||
@@ -548,11 +553,11 @@ where
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
// The sphinx_message_sender is the transmitter for any component generating sphinx packets
|
||||
// The message_sender is the transmitter for any component generating sphinx packets
|
||||
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
let sphinx_message_sender =
|
||||
let message_sender =
|
||||
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
@@ -574,13 +579,14 @@ where
|
||||
shared_topology_accessor.clone(),
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
sphinx_message_sender.clone(),
|
||||
message_sender.clone(),
|
||||
reply_storage,
|
||||
reply_controller_sender.clone(),
|
||||
reply_controller_receiver,
|
||||
shared_lane_queue_lengths.clone(),
|
||||
client_connection_rx,
|
||||
task_manager.subscribe(),
|
||||
packet_type,
|
||||
);
|
||||
|
||||
if !self
|
||||
@@ -593,7 +599,7 @@ where
|
||||
self.managed_keys.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor.clone(),
|
||||
sphinx_message_sender,
|
||||
message_sender,
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,15 +12,15 @@ use nym_credential_storage::ephemeral_storage::{
|
||||
};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::base_client::non_wasm_helpers;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::key_manager::persistence::OnDiskKeys;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::config::{persistence::key_pathfinder::ClientKeyPathfinder, Config};
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::error::ClientCoreError;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
@@ -74,14 +74,14 @@ impl MixnetClientStorage for Ephemeral {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
pub struct OnDiskPersistent {
|
||||
pub(crate) key_store: OnDiskKeys,
|
||||
pub(crate) reply_store: fs_backend::Backend,
|
||||
pub(crate) credential_store: PersistentCredentialStorage,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
impl OnDiskPersistent {
|
||||
pub fn new(
|
||||
key_store: OnDiskKeys,
|
||||
@@ -116,7 +116,7 @@ impl OnDiskPersistent {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
impl MixnetClientStorage for OnDiskPersistent {
|
||||
type KeyStore = OnDiskKeys;
|
||||
type ReplyStore = fs_backend::Backend;
|
||||
|
||||
@@ -45,7 +45,7 @@ where
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
next_delay: Pin<Box<wasm_timer::Delay>>,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
@@ -194,6 +194,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
||||
self.average_ack_delay,
|
||||
self.cover_traffic.loop_cover_traffic_average_delay,
|
||||
cover_traffic_packet_size,
|
||||
nym_sphinx::params::PacketType::Mix,
|
||||
)
|
||||
.expect("Somehow failed to generate a loop cover message with a valid topology");
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
|
||||
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
||||
@@ -53,18 +54,49 @@ pub enum InputMessage {
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
},
|
||||
|
||||
MessageWrapper {
|
||||
message: Box<InputMessage>,
|
||||
packet_type: PacketType,
|
||||
},
|
||||
}
|
||||
|
||||
impl InputMessage {
|
||||
pub fn new_premade(msgs: Vec<MixPacket>, lane: TransmissionLane) -> Self {
|
||||
InputMessage::Premade { msgs, lane }
|
||||
pub fn new_premade(
|
||||
msgs: Vec<MixPacket>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Self {
|
||||
let message = InputMessage::Premade { msgs, lane };
|
||||
if packet_type == PacketType::Mix {
|
||||
message
|
||||
} else {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_regular(recipient: Recipient, data: Vec<u8>, lane: TransmissionLane) -> Self {
|
||||
InputMessage::Regular {
|
||||
pub fn new_wrapper(message: InputMessage, packet_type: PacketType) -> Self {
|
||||
InputMessage::MessageWrapper {
|
||||
message: Box::new(message),
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_regular(
|
||||
recipient: Recipient,
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
let message = InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,12 +105,18 @@ impl InputMessage {
|
||||
data: Vec<u8>,
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
InputMessage::Anonymous {
|
||||
let message = InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +124,17 @@ impl InputMessage {
|
||||
recipient_tag: AnonymousSenderTag,
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
InputMessage::Reply {
|
||||
let message = InputMessage::Reply {
|
||||
recipient_tag,
|
||||
data,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +144,7 @@ impl InputMessage {
|
||||
| InputMessage::Anonymous { lane, .. }
|
||||
| InputMessage::Reply { lane, .. }
|
||||
| InputMessage::Premade { lane, .. } => lane,
|
||||
InputMessage::MessageWrapper { message, .. } => message.lane(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,15 +40,15 @@ where
|
||||
pub fn new(
|
||||
gateway_client: GatewayClient<C, St>,
|
||||
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
|
||||
let (sphinx_message_sender, sphinx_message_receiver) =
|
||||
let (message_sender, message_receiver) =
|
||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||
(
|
||||
MixTrafficController {
|
||||
gateway_client,
|
||||
mix_rx: sphinx_message_receiver,
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
},
|
||||
sphinx_message_sender,
|
||||
message_sender,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ impl AcknowledgementListener {
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
acks = self.ack_receiver.next() => match acks {
|
||||
Some(acks) => self.handle_ack_receiver_item(acks).await,
|
||||
Some(acks) => {self.handle_ack_receiver_item(acks).await}
|
||||
None => {
|
||||
log::trace!("AcknowledgementListener: Stopping since channel closed");
|
||||
break;
|
||||
|
||||
+44
-4
@@ -9,6 +9,7 @@ use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
@@ -71,10 +72,11 @@ where
|
||||
recipient: Recipient,
|
||||
content: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_plain_message(recipient, content, lane)
|
||||
.try_send_plain_message(recipient, content, lane, packet_type)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send a plain message - {err}")
|
||||
@@ -87,10 +89,11 @@ where
|
||||
content: Vec<u8>,
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane)
|
||||
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send a repliable message - {err}")
|
||||
@@ -103,14 +106,17 @@ where
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
} => self.handle_plain_message(recipient, data, lane).await,
|
||||
} => {
|
||||
self.handle_plain_message(recipient, data, lane, PacketType::Mix)
|
||||
.await
|
||||
}
|
||||
InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane)
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix)
|
||||
.await
|
||||
}
|
||||
InputMessage::Reply {
|
||||
@@ -121,6 +127,40 @@ where
|
||||
self.handle_reply(recipient_tag, data, lane).await;
|
||||
}
|
||||
InputMessage::Premade { msgs, lane } => self.handle_premade_packets(msgs, lane).await,
|
||||
InputMessage::MessageWrapper {
|
||||
message,
|
||||
packet_type,
|
||||
} => match *message {
|
||||
InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_plain_message(recipient, data, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
InputMessage::Reply {
|
||||
recipient_tag,
|
||||
data,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_reply(recipient_tag, data, lane).await;
|
||||
}
|
||||
InputMessage::Premade { msgs, lane } => {
|
||||
self.handle_premade_packets(msgs, lane).await
|
||||
}
|
||||
// MessageWrappers can't be nested
|
||||
InputMessage::MessageWrapper { .. } => unimplemented!(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nym_gateway_client::AcknowledgementReceiver;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::{
|
||||
acknowledgements::AckKey,
|
||||
addressing::clients::Recipient,
|
||||
@@ -249,7 +249,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
pub(super) fn start_with_shutdown(
|
||||
self,
|
||||
shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
let mut acknowledgement_listener = self.acknowledgement_listener;
|
||||
let mut input_message_listener = self.input_message_listener;
|
||||
let mut retransmission_request_listener = self.retransmission_request_listener;
|
||||
@@ -275,7 +279,7 @@ where
|
||||
let shutdown_handle = shutdown.clone();
|
||||
spawn_future(async move {
|
||||
retransmission_request_listener
|
||||
.run_with_shutdown(shutdown_handle)
|
||||
.run_with_shutdown(shutdown_handle, packet_type)
|
||||
.await;
|
||||
debug!("The retransmission request listener has finished execution!");
|
||||
});
|
||||
|
||||
+12
-4
@@ -11,9 +11,9 @@ use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::chunking::fragment::Fragment;
|
||||
use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
@@ -48,17 +48,20 @@ where
|
||||
&mut self,
|
||||
packet_recipient: Recipient,
|
||||
chunk_data: Fragment,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, PreparationError> {
|
||||
debug!("retransmitting normal packet...");
|
||||
|
||||
// TODO: Figure out retransmission packet type signaling
|
||||
self.message_handler
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data)
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, packet_type)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn on_retransmission_request(
|
||||
&mut self,
|
||||
weak_timed_out_ack: Weak<PendingAcknowledgement>,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
let timed_out_ack = match weak_timed_out_ack.upgrade() {
|
||||
Some(timed_out_ack) => timed_out_ack,
|
||||
@@ -85,6 +88,7 @@ where
|
||||
self.prepare_normal_retransmission_chunk(
|
||||
**recipient,
|
||||
timed_out_ack.message_chunk.clone(),
|
||||
packet_type,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -140,13 +144,17 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
|
||||
pub(super) async fn run_with_shutdown(
|
||||
&mut self,
|
||||
mut shutdown: nym_task::TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
debug!("Started RetransmissionRequestListener with graceful shutdown support");
|
||||
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
timed_out_ack = self.request_receiver.next() => match timed_out_ack {
|
||||
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack).await,
|
||||
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack, packet_type).await,
|
||||
None => {
|
||||
log::trace!("RetransmissionRequestListener: Stopping since channel closed");
|
||||
break;
|
||||
|
||||
@@ -15,7 +15,7 @@ use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessa
|
||||
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx::message::NymMessage;
|
||||
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::params::{PacketSize, PacketType, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||
use nym_sphinx::Delay;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
@@ -27,7 +27,7 @@ use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
// TODO: move that error elsewhere since it seems to be contaminating different files
|
||||
#[derive(Debug, Clone, Error)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PreparationError {
|
||||
#[error(transparent)]
|
||||
NymTopologyError(#[from] NymTopologyError),
|
||||
@@ -417,9 +417,10 @@ where
|
||||
recipient: Recipient,
|
||||
message: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
let message = NymMessage::new_plain(message);
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -428,7 +429,9 @@ where
|
||||
message: NymMessage,
|
||||
recipient: Recipient,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
debug!("Sending non-reply message with packet type {packet_type}");
|
||||
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
||||
debug_assert!(!matches!(message, NymMessage::Reply(_)));
|
||||
|
||||
@@ -436,7 +439,11 @@ where
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = self.get_topology(&topology_permit)?;
|
||||
|
||||
let packet_size = self.optimal_packet_size(&message);
|
||||
let packet_size = if packet_type == PacketType::Outfox {
|
||||
PacketSize::OutfoxRegularPacket
|
||||
} else {
|
||||
self.optimal_packet_size(&message)
|
||||
};
|
||||
debug!("Using {packet_size} packets for {message}");
|
||||
let fragments = self
|
||||
.message_preparer
|
||||
@@ -453,6 +460,7 @@ where
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
)?;
|
||||
|
||||
let real_message = RealMessage::new(
|
||||
@@ -476,7 +484,9 @@ where
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
amount: u32,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
debug!("Sending additional reply SURBs with packet type {packet_type}");
|
||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||
let (reply_surbs, reply_keys) =
|
||||
self.generate_reply_surbs_with_keys(amount as usize).await?;
|
||||
@@ -490,6 +500,7 @@ where
|
||||
message,
|
||||
recipient,
|
||||
TransmissionLane::AdditionalReplySurbs,
|
||||
packet_type,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -505,7 +516,9 @@ where
|
||||
message: Vec<u8>,
|
||||
num_reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), SurbWrappedPreparationError> {
|
||||
debug!("Sending message with reply SURBs with packet type {packet_type}");
|
||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||
let (reply_surbs, reply_keys) = self
|
||||
.generate_reply_surbs_with_keys(num_reply_surbs as usize)
|
||||
@@ -514,7 +527,7 @@ where
|
||||
let message =
|
||||
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
|
||||
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
||||
.await?;
|
||||
|
||||
log::trace!("storing {} reply keys", reply_keys.len());
|
||||
@@ -527,13 +540,21 @@ where
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
chunk: Fragment,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, PreparationError> {
|
||||
debug!("Sending single chunk with packet type {packet_type}");
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = self.get_topology(&topology_permit)?;
|
||||
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_chunk_for_sending(chunk, topology, &self.config.ack_key, &recipient)
|
||||
.prepare_chunk_for_sending(
|
||||
chunk,
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(prepared_fragment)
|
||||
@@ -569,6 +590,7 @@ where
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
reply_surb,
|
||||
PacketType::Mix,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
@@ -588,7 +610,13 @@ where
|
||||
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_reply_chunk_for_sending(chunk, topology, &self.config.ack_key, reply_surb)
|
||||
.prepare_reply_chunk_for_sending(
|
||||
chunk,
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
reply_surb,
|
||||
PacketType::Mix,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(prepared_fragment)
|
||||
|
||||
@@ -26,6 +26,7 @@ use log::*;
|
||||
use nym_gateway_client::AcknowledgementReceiver;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
|
||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||
use std::sync::Arc;
|
||||
@@ -207,7 +208,7 @@ impl RealMessagesController<OsRng> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
|
||||
pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient, packet_type: PacketType) {
|
||||
let mut out_queue_control = self.out_queue_control;
|
||||
let ack_control = self.ack_control;
|
||||
let mut reply_control = self.reply_control;
|
||||
@@ -223,6 +224,6 @@ impl RealMessagesController<OsRng> {
|
||||
debug!("The reply controller has finished execution!");
|
||||
});
|
||||
|
||||
ack_control.start_with_shutdown(shutdown);
|
||||
ack_control.start_with_shutdown(shutdown, packet_type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ where
|
||||
// messages.
|
||||
sending_delay_controller: SendingDelayController,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// Channel used for sending prepared packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
@@ -136,7 +136,7 @@ impl From<PreparedFragment> for RealMessage {
|
||||
|
||||
impl RealMessage {
|
||||
pub(crate) fn packet_size(&self) -> usize {
|
||||
self.mix_packet.sphinx_packet().len()
|
||||
self.mix_packet.packet().len()
|
||||
}
|
||||
|
||||
pub(crate) fn new(mix_packet: MixPacket, fragment_id: Option<FragmentIdentifier>) -> Self {
|
||||
@@ -247,6 +247,7 @@ where
|
||||
self.config.average_ack_delay,
|
||||
self.config.traffic.average_packet_delay,
|
||||
cover_traffic_packet_size,
|
||||
self.config.traffic.packet_type.unwrap_or_default(),
|
||||
)
|
||||
.expect(
|
||||
"Somehow failed to generate a loop cover message with a valid topology",
|
||||
@@ -386,7 +387,7 @@ where
|
||||
|
||||
// On every iteration we get new messages from upstream. Given that these come bunched
|
||||
// in `Vec`, this ensures that on average we will fetch messages faster than we can
|
||||
// send, which is a condition for being able to multiplex sphinx packets from multiple
|
||||
// send, which is a condition for being able to multiplex packets from multiple
|
||||
// data streams.
|
||||
match Pin::new(&mut self.real_receiver).poll_recv(cx) {
|
||||
// in the case our real message channel stream was closed, we should also indicate we are closed
|
||||
|
||||
@@ -512,7 +512,11 @@ where
|
||||
let to_send = min(remaining, 100);
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_additional_reply_surbs(recipient, to_send)
|
||||
.try_send_additional_reply_surbs(
|
||||
recipient,
|
||||
to_send,
|
||||
nym_sphinx::params::PacketType::Mix,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send additional surbs to {recipient} - {err}");
|
||||
|
||||
@@ -28,7 +28,7 @@ impl SizedData for RealMessage {
|
||||
|
||||
impl SizedData for Fragment {
|
||||
fn data_size(&self) -> usize {
|
||||
// note that raw `Fragment` is smaller than sphinx packet payload
|
||||
// note that raw `Fragment` is smaller than packet payload
|
||||
// as it doesn't include surb-ack or the [shared] key materials
|
||||
self.payload_size()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use nym_config::{NymConfig, OptionalSet, CRED_DB_FILE_NAME};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -259,6 +259,11 @@ impl<T> Config<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_packet_type(mut self, packet_type: PacketType) -> Self {
|
||||
self.client.packet_type = Some(packet_type);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_high_default_traffic_volume(&mut self) {
|
||||
self.debug.traffic.average_packet_delay = Duration::from_millis(10);
|
||||
// basically don't really send cover messages
|
||||
@@ -446,6 +451,10 @@ impl<T> Config<T> {
|
||||
pub fn get_maximum_reply_key_age(&self) -> Duration {
|
||||
self.debug.reply_surbs.maximum_reply_key_age
|
||||
}
|
||||
|
||||
pub fn get_packet_type(&self) -> PacketType {
|
||||
self.client.packet_type.unwrap_or(PacketType::Mix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Config<T> {
|
||||
@@ -568,6 +577,8 @@ pub struct Client<T> {
|
||||
|
||||
#[serde(skip)]
|
||||
pub super_struct: PhantomData<T>,
|
||||
|
||||
pub packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl<T: NymConfig> Default for Client<T> {
|
||||
@@ -606,6 +617,7 @@ impl<T: NymConfig> Default for Client<T> {
|
||||
reply_surb_database_path: Default::default(),
|
||||
nym_root_directory: T::default_root_directory(),
|
||||
super_struct: Default::default(),
|
||||
packet_type: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -677,6 +689,8 @@ pub struct Traffic {
|
||||
/// Note that its use decreases overall anonymity.
|
||||
/// Do not set it it unless you understand the consequences of that change.
|
||||
pub secondary_packet_size: Option<PacketSize>,
|
||||
|
||||
pub packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Traffic {
|
||||
@@ -700,6 +714,7 @@ impl Default for Traffic {
|
||||
disable_main_poisson_packet_distribution: false,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: None,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@ impl From<OldDebugConfigV1_1_13> for DebugConfig {
|
||||
.disable_main_poisson_packet_distribution,
|
||||
primary_packet_size: PacketSize::RegularPacket,
|
||||
secondary_packet_size: value.use_extended_packet_size.map(Into::into),
|
||||
packet_type: None,
|
||||
},
|
||||
cover_traffic: CoverTraffic {
|
||||
loop_cover_traffic_average_delay: value.loop_cover_traffic_average_delay,
|
||||
@@ -210,8 +211,8 @@ impl<T, U> From<OldConfigV1_1_13<T>> for Config<U> {
|
||||
database_path: value.client.database_path,
|
||||
reply_surb_database_path: value.client.reply_surb_database_path,
|
||||
nym_root_directory: value.client.nym_root_directory,
|
||||
|
||||
super_struct: PhantomData,
|
||||
packet_type: Some(nym_sphinx::params::PacketType::Mix),
|
||||
},
|
||||
logging: value.logging,
|
||||
debug: value.debug.into(),
|
||||
|
||||
@@ -40,11 +40,17 @@ impl ClientKeyPathfinder {
|
||||
}
|
||||
|
||||
pub fn identity_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(self.private_identity_key(), self.public_identity_key())
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_identity_key().to_path_buf(),
|
||||
self.public_identity_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn encryption_key_pair_path(&self) -> nym_pemstore::KeyPairPath {
|
||||
nym_pemstore::KeyPairPath::new(self.private_encryption_key(), self.public_encryption_key())
|
||||
nym_pemstore::KeyPairPath::new(
|
||||
self.private_encryption_key().to_path_buf(),
|
||||
self.public_encryption_key().to_path_buf(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn any_file_exists(&self) -> bool {
|
||||
|
||||
@@ -571,7 +571,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
||||
packets
|
||||
.iter()
|
||||
.map(|packet| packet.sphinx_packet().len())
|
||||
.map(|packet| packet.packet().len())
|
||||
.sum::<usize>() as i64
|
||||
}
|
||||
|
||||
@@ -579,6 +579,8 @@ impl<C, St> GatewayClient<C, St> {
|
||||
&mut self,
|
||||
packets: Vec<MixPacket>,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
debug!("Sending {} mix packets", packets.len());
|
||||
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
@@ -623,9 +625,10 @@ impl<C, St> GatewayClient<C, St> {
|
||||
) -> Result<(), GatewayClientError> {
|
||||
if let Err(err) = self.send_websocket_message_without_response(msg).await {
|
||||
if err.is_closed_connection() && self.should_reconnect_on_failure {
|
||||
info!("Going to attempt a reconnection");
|
||||
debug!("Going to attempt a reconnection");
|
||||
self.attempt_reconnection().await
|
||||
} else {
|
||||
warn!("{err}");
|
||||
Err(err)
|
||||
}
|
||||
} else {
|
||||
@@ -652,9 +655,9 @@ impl<C, St> GatewayClient<C, St> {
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
if (mix_packet.packet().len() as i64) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
mix_packet.packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -50,10 +50,15 @@ impl PacketRouter {
|
||||
let ack_overhead = PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
|
||||
for received_packet in unwrapped_packets {
|
||||
if received_packet.len() == PacketSize::AckPacket.plaintext_size() {
|
||||
if received_packet.len() == PacketSize::AckPacket.plaintext_size()
|
||||
|| received_packet.len() == PacketSize::OutfoxAckPacket.plaintext_size()
|
||||
{
|
||||
received_acks.push(received_packet);
|
||||
} else if received_packet.len()
|
||||
== PacketSize::RegularPacket.plaintext_size() - ack_overhead
|
||||
|| received_packet.len()
|
||||
== PacketSize::OutfoxRegularPacket.plaintext_size() - ack_overhead
|
||||
|| received_packet.len() == PacketSize::OutfoxRegularPacket.size() - 6
|
||||
{
|
||||
trace!("routing regular packet");
|
||||
received_messages.push(received_packet);
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::framing::codec::SphinxCodec;
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::params::PacketMode;
|
||||
use nym_sphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
|
||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::NymPacket;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
@@ -50,8 +51,8 @@ pub trait SendWithoutResponse {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> io::Result<()>;
|
||||
}
|
||||
|
||||
@@ -61,12 +62,12 @@ pub struct Client {
|
||||
}
|
||||
|
||||
struct ConnectionSender {
|
||||
channel: mpsc::Sender<FramedSphinxPacket>,
|
||||
channel: mpsc::Sender<FramedNymPacket>,
|
||||
current_reconnection_attempt: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
impl ConnectionSender {
|
||||
fn new(channel: mpsc::Sender<FramedSphinxPacket>) -> Self {
|
||||
fn new(channel: mpsc::Sender<FramedNymPacket>) -> Self {
|
||||
ConnectionSender {
|
||||
channel,
|
||||
current_reconnection_attempt: Arc::new(AtomicU32::new(0)),
|
||||
@@ -84,7 +85,7 @@ impl Client {
|
||||
|
||||
async fn manage_connection(
|
||||
address: SocketAddr,
|
||||
receiver: mpsc::Receiver<FramedSphinxPacket>,
|
||||
receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: &AtomicU32,
|
||||
) {
|
||||
@@ -96,7 +97,7 @@ impl Client {
|
||||
debug!("Managed to establish connection to {}", address);
|
||||
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
||||
current_reconnection.store(0, Ordering::Release);
|
||||
Framed::new(stream, SphinxCodec)
|
||||
Framed::new(stream, NymCodec)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
@@ -148,11 +149,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_connection(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
pending_packet: FramedSphinxPacket,
|
||||
) {
|
||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
|
||||
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
||||
@@ -200,12 +197,12 @@ impl SendWithoutResponse for Client {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> io::Result<()> {
|
||||
trace!("Sending packet to {:?}", address);
|
||||
let framed_packet =
|
||||
FramedSphinxPacket::new(packet, packet_mode, self.config.use_legacy_version);
|
||||
FramedNymPacket::new(packet, packet_type, self.config.use_legacy_version);
|
||||
|
||||
if let Some(sender) = self.conn_new.get_mut(&address) {
|
||||
if let Err(err) = sender.channel.try_send(framed_packet) {
|
||||
|
||||
@@ -59,14 +59,14 @@ impl PacketForwarder {
|
||||
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
|
||||
|
||||
let next_hop = mix_packet.next_hop();
|
||||
let packet_mode = mix_packet.packet_mode();
|
||||
let sphinx_packet = mix_packet.into_sphinx_packet();
|
||||
let packet_type = mix_packet.packet_type();
|
||||
let packet = mix_packet.into_packet();
|
||||
// we don't care about responses, we just want to fire packets
|
||||
// as quickly as possible
|
||||
|
||||
if let Err(err) =
|
||||
self.mixnet_client
|
||||
.send_without_response(next_hop, sphinx_packet, packet_mode)
|
||||
.send_without_response(next_hop, packet, packet_type)
|
||||
{
|
||||
debug!("failed to forward the packet - {err}")
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ nym-api-requests = { path = "../../../nym-api/nym-api-requests" }
|
||||
async-trait = { workspace = true, optional = true }
|
||||
bip39 = { workspace = true, features = ["rand"], optional = true }
|
||||
nym-config = { path = "../../config", optional = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true }
|
||||
cosmrs = { workspace = true, features = ["rpc", "bip32", "cosmwasm"], optional = true }
|
||||
# note that this has the same version as used by cosmrs
|
||||
eyre = { version = "0.6", optional = true }
|
||||
cw3 = { workspace = true, optional = true }
|
||||
@@ -54,7 +54,7 @@ cosmwasm-std = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bip39 = { workspace = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32"] }
|
||||
cosmrs = { workspace = true, features = ["rpc", "bip32"] }
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ impl GasAdjustable for Gas {
|
||||
mod sealed {
|
||||
use cosmrs::tx::{self, Gas};
|
||||
use cosmrs::Coin as CosmosCoin;
|
||||
use cosmrs::{AccountId, Decimal as CosmosDecimal, Denom as CosmosDenom};
|
||||
use cosmrs::{AccountId, Denom as CosmosDenom};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
fn cosmos_denom_inner_getter(val: &CosmosDenom) -> String {
|
||||
@@ -144,29 +144,11 @@ mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
fn cosmos_decimal_inner_getter(val: &CosmosDecimal) -> u64 {
|
||||
// haha, this code is so disgusting. I'll make a PR on cosmrs to slightly alleviate those issues...
|
||||
// note: unwrap here is fine as the to_string is just returning a stringified u64 which, well, is a valid u64
|
||||
val.to_string().parse().unwrap()
|
||||
}
|
||||
|
||||
// at the time of writing it the current cosmrs' Decimal is extremely limited...
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "CosmosDecimal")]
|
||||
struct Decimal(#[serde(getter = "cosmos_decimal_inner_getter")] u64);
|
||||
|
||||
impl From<Decimal> for CosmosDecimal {
|
||||
fn from(val: Decimal) -> Self {
|
||||
val.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
struct Coin {
|
||||
#[serde(with = "Denom")]
|
||||
denom: CosmosDenom,
|
||||
#[serde(with = "Decimal")]
|
||||
amount: CosmosDecimal,
|
||||
amount: u128,
|
||||
}
|
||||
|
||||
impl From<Coin> for CosmosCoin {
|
||||
|
||||
@@ -39,7 +39,7 @@ pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo;
|
||||
pub use cosmrs::tendermint::Time as TendermintTime;
|
||||
pub use cosmrs::tx::{self, Gas};
|
||||
pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmrs::{bip32, AccountId, Decimal, Denom};
|
||||
pub use cosmrs::{bip32, AccountId, Denom};
|
||||
use cosmwasm_std::Addr;
|
||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
|
||||
|
||||
@@ -14,7 +14,7 @@ clap = { version = "4.0", features = ["derive"] }
|
||||
cw-utils = { workspace = true }
|
||||
handlebars = "3.0.1"
|
||||
humantime-serde = "1.0"
|
||||
k256 = { version = "0.10", features = ["ecdsa", "sha256"] }
|
||||
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
|
||||
log = { workspace = true }
|
||||
rand = {version = "0.6", features = ["std"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
@@ -25,7 +25,7 @@ toml = "0.5.6"
|
||||
url = "2.2"
|
||||
tap = "1"
|
||||
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||
cosmrs = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
|
||||
nym-validator-client = { path = "../client-libs/validator-client", features = ["nyxd-client"] }
|
||||
|
||||
@@ -56,6 +56,8 @@ pub async fn generate(args: Args) {
|
||||
.expect("threshold can't be converted to Decimal"),
|
||||
},
|
||||
max_voting_period: Duration::Time(args.max_voting_period),
|
||||
executor: None,
|
||||
proposal_deposit: None,
|
||||
coconut_bandwidth_contract_address: coconut_bandwidth_contract_address.to_string(),
|
||||
coconut_dkg_contract_address: coconut_dkg_contract_address.to_string(),
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct InstantiateMsg {
|
||||
pub mix_denom: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
DepositFunds { data: DepositData },
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::msg::ExecuteMsg;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct SpendCredentialData {
|
||||
funds: Coin,
|
||||
blinded_serial_number: String,
|
||||
@@ -43,7 +43,7 @@ pub enum SpendCredentialStatus {
|
||||
Spent,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct SpendCredential {
|
||||
funds: Coin,
|
||||
blinded_serial_number: String,
|
||||
@@ -74,7 +74,7 @@ impl SpendCredential {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedSpendCredentialResponse {
|
||||
pub spend_credentials: Vec<SpendCredential>,
|
||||
pub per_page: usize,
|
||||
@@ -95,7 +95,7 @@ impl PagedSpendCredentialResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct SpendCredentialResponse {
|
||||
pub spend_credential: Option<SpendCredential>,
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ pub type Nonce = u32;
|
||||
|
||||
// define this type explicitly for [hopefully] better usability
|
||||
// (so you wouldn't need to worry about whether you should use bytes, bs58, etc.)
|
||||
#[derive(Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct MessageSignature(Vec<u8>);
|
||||
|
||||
impl MessageSignature {
|
||||
|
||||
@@ -6,6 +6,8 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-schema = { workspace = true }
|
||||
cw4 = { workspace = true }
|
||||
cw-controllers = { workspace = true }
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||
use cw4::Member;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg {
|
||||
/// The admin is the only account that can update the group state.
|
||||
/// Omit it to make the group immutable.
|
||||
@@ -15,8 +9,7 @@ pub struct InstantiateMsg {
|
||||
pub members: Vec<Member>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[cw_serde]
|
||||
pub enum ExecuteMsg {
|
||||
/// Change the admin
|
||||
UpdateAdmin { admin: Option<String> },
|
||||
@@ -32,23 +25,24 @@ pub enum ExecuteMsg {
|
||||
RemoveHook { addr: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[cw_serde]
|
||||
#[derive(QueryResponses)]
|
||||
pub enum QueryMsg {
|
||||
/// Return AdminResponse
|
||||
#[returns(cw_controllers::AdminResponse)]
|
||||
Admin {},
|
||||
/// Return TotalWeightResponse
|
||||
TotalWeight {},
|
||||
/// Returns MembersListResponse
|
||||
#[returns(cw4::TotalWeightResponse)]
|
||||
TotalWeight { at_height: Option<u64> },
|
||||
#[returns(cw4::MemberListResponse)]
|
||||
ListMembers {
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
/// Returns MemberResponse
|
||||
#[returns(cw4::MemberResponse)]
|
||||
Member {
|
||||
addr: String,
|
||||
at_height: Option<u64>,
|
||||
},
|
||||
/// Shows all registered hooks. Returns HooksResponse.
|
||||
/// Shows all registered hooks.
|
||||
#[returns(cw_controllers::HooksResponse)]
|
||||
Hooks {},
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub fn generate_owner_storage_subkey(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
||||
pub struct Delegation {
|
||||
/// Address of the owner of this delegation.
|
||||
pub owner: Addr,
|
||||
@@ -114,7 +114,7 @@ impl Delegation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedMixNodeDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<OwnerProxySubKey>,
|
||||
@@ -129,7 +129,7 @@ impl PagedMixNodeDelegationsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedDelegatorDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<(MixId, OwnerProxySubKey)>,
|
||||
@@ -147,7 +147,7 @@ impl PagedDelegatorDelegationsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeDelegationResponse {
|
||||
pub delegation: Option<Delegation>,
|
||||
pub mixnode_still_bonded: bool,
|
||||
@@ -162,7 +162,7 @@ impl MixNodeDelegationResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedAllDelegationsResponse {
|
||||
pub delegations: Vec<Delegation>,
|
||||
pub start_next_after: Option<StorageKey>,
|
||||
|
||||
@@ -23,7 +23,7 @@ pub struct Gateway {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct GatewayBond {
|
||||
pub pledge_amount: Coin,
|
||||
pub owner: Addr,
|
||||
@@ -132,7 +132,7 @@ impl GatewayConfigUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedGatewayResponse {
|
||||
pub nodes: Vec<GatewayBond>,
|
||||
pub per_page: usize,
|
||||
@@ -153,13 +153,13 @@ impl PagedGatewayResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct GatewayOwnershipResponse {
|
||||
pub address: Addr,
|
||||
pub gateway: Option<GatewayBond>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct GatewayBondResponse {
|
||||
pub identity: IdentityKey,
|
||||
pub gateway: Option<GatewayBond>,
|
||||
|
||||
@@ -489,7 +489,7 @@ impl CurrentIntervalResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct PendingEpochEventsResponse {
|
||||
pub seconds_until_executable: i64,
|
||||
pub events: Vec<PendingEpochEvent>,
|
||||
@@ -510,7 +510,7 @@ impl PendingEpochEventsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct PendingIntervalEventsResponse {
|
||||
pub seconds_until_executable: i64,
|
||||
pub events: Vec<PendingIntervalEvent>,
|
||||
|
||||
@@ -33,7 +33,7 @@ impl RewardedSetNodeStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeDetails {
|
||||
pub bond_information: MixNodeBond,
|
||||
pub rewarding_details: MixNodeRewarding,
|
||||
@@ -86,7 +86,7 @@ impl MixNodeDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeRewarding {
|
||||
/// Information provided by the operator that influence the cost function.
|
||||
pub cost_params: MixNodeCostParams,
|
||||
@@ -465,7 +465,7 @@ impl MixNodeRewarding {
|
||||
}
|
||||
|
||||
// operator information + data assigned by the contract(s)
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeBond {
|
||||
/// Unique id assigned to the bonded mixnode.
|
||||
pub mix_id: MixId,
|
||||
@@ -559,7 +559,7 @@ pub struct MixNode {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixNodeCostParams {
|
||||
pub profit_margin_percent: Percent,
|
||||
|
||||
@@ -686,7 +686,7 @@ impl MixNodeConfigUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedMixnodeBondsResponse {
|
||||
pub nodes: Vec<MixNodeBond>,
|
||||
pub per_page: usize,
|
||||
@@ -703,7 +703,7 @@ impl PagedMixnodeBondsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct PagedMixnodesDetailsResponse {
|
||||
pub nodes: Vec<MixNodeDetails>,
|
||||
pub per_page: usize,
|
||||
@@ -745,19 +745,19 @@ impl PagedUnbondedMixnodesResponse {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixOwnershipResponse {
|
||||
pub address: Addr,
|
||||
pub mixnode_details: Option<MixNodeDetails>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixnodeDetailsResponse {
|
||||
pub mix_id: MixId,
|
||||
pub mixnode_details: Option<MixNodeDetails>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||
pub struct MixnodeRewardingDetailsResponse {
|
||||
pub mix_id: MixId,
|
||||
pub rewarding_details: Option<MixNodeRewarding>,
|
||||
|
||||
@@ -7,19 +7,19 @@ use crate::{BlockHeight, EpochEventId, IntervalEventId, MixId};
|
||||
use cosmwasm_std::{Addr, Coin};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PendingEpochEvent {
|
||||
pub id: EpochEventId,
|
||||
pub event: PendingEpochEventData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PendingEpochEventData {
|
||||
pub created_at: BlockHeight,
|
||||
pub kind: PendingEpochEventKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum PendingEpochEventKind {
|
||||
// can't just pass the `Delegation` struct here as it's impossible to determine
|
||||
// `cumulative_reward_ratio` ahead of time
|
||||
@@ -68,19 +68,19 @@ impl From<(EpochEventId, PendingEpochEventData)> for PendingEpochEvent {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PendingIntervalEvent {
|
||||
pub id: IntervalEventId,
|
||||
pub event: PendingIntervalEventData,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct PendingIntervalEventData {
|
||||
pub created_at: BlockHeight,
|
||||
pub kind: PendingIntervalEventKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum PendingIntervalEventKind {
|
||||
ChangeMixCostParams {
|
||||
mix_id: MixId,
|
||||
|
||||
@@ -35,7 +35,7 @@ pub struct RewardDistribution {
|
||||
pub delegates: Decimal,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct PendingRewardResponse {
|
||||
pub amount_staked: Option<Coin>,
|
||||
pub amount_earned: Option<Coin>,
|
||||
@@ -46,7 +46,7 @@ pub struct PendingRewardResponse {
|
||||
pub mixnode_still_fully_bonded: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, JsonSchema, PartialEq, Eq)]
|
||||
pub struct EstimatedCurrentEpochRewardResponse {
|
||||
pub original_stake: Option<Coin>,
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ pub type EpochEventId = u32;
|
||||
pub type IntervalEventId = u32;
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, PartialEq, Eq)]
|
||||
pub struct LayerAssignment {
|
||||
mix_id: MixId,
|
||||
layer: Layer,
|
||||
@@ -119,7 +119,7 @@ impl Index<Layer> for LayerDistribution {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct ContractState {
|
||||
pub owner: Addr, // only the owner account can update state
|
||||
pub rewarding_validator_address: Addr,
|
||||
@@ -131,7 +131,7 @@ pub struct ContractState {
|
||||
pub params: ContractStateParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct ContractStateParams {
|
||||
/// Minimum amount a delegator must stake in orders for his delegation to get accepted.
|
||||
pub minimum_mixnode_delegation: Option<Coin>,
|
||||
|
||||
@@ -9,6 +9,8 @@ edition = "2021"
|
||||
cw-utils = { workspace = true }
|
||||
cw3 = { workspace = true }
|
||||
cw4 = { workspace= true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
cosmwasm-schema = { workspace = true }
|
||||
cosmwasm-std = { workspace = true }
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::StdError;
|
||||
use cw_utils::ThresholdError;
|
||||
use cw3::DepositError;
|
||||
use cw_utils::{PaymentError, ThresholdError};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -17,9 +18,6 @@ pub enum ContractError {
|
||||
#[error("Group contract invalid address '{addr}'")]
|
||||
InvalidGroup { addr: String },
|
||||
|
||||
#[error("Coconut bandwidth contract address not found")]
|
||||
InvalidCoconutBandwidth {},
|
||||
|
||||
#[error("Unauthorized")]
|
||||
Unauthorized {},
|
||||
|
||||
@@ -43,4 +41,10 @@ pub enum ContractError {
|
||||
|
||||
#[error("Cannot close completed or passed proposals")]
|
||||
WrongCloseStatus {},
|
||||
|
||||
#[error("{0}")]
|
||||
Payment(#[from] PaymentError),
|
||||
|
||||
#[error("{0}")]
|
||||
Deposit(#[from] DepositError),
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod error;
|
||||
pub mod msg;
|
||||
pub mod state;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||
use cosmwasm_std::{CosmosMsg, Empty};
|
||||
use cw3::Vote;
|
||||
use cw3::{UncheckedDepositInfo, Vote};
|
||||
use cw4::MemberChangedHookMsg;
|
||||
use cw_utils::{Duration, Expiration, Threshold};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
|
||||
use crate::state::Executor;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct InstantiateMsg {
|
||||
// this is the group contract that contains the member list
|
||||
pub group_addr: String,
|
||||
@@ -17,11 +17,15 @@ pub struct InstantiateMsg {
|
||||
pub coconut_dkg_contract_address: String,
|
||||
pub threshold: Threshold,
|
||||
pub max_voting_period: Duration,
|
||||
// who is able to execute passed proposals
|
||||
// None means that anyone can execute
|
||||
pub executor: Option<Executor>,
|
||||
/// The cost of creating a proposal (if any).
|
||||
pub proposal_deposit: Option<UncheckedDepositInfo>,
|
||||
}
|
||||
|
||||
// TODO: add some T variants? Maybe good enough as fixed Empty for now
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[cw_serde]
|
||||
pub enum ExecuteMsg {
|
||||
Propose {
|
||||
title: String,
|
||||
@@ -45,41 +49,44 @@ pub enum ExecuteMsg {
|
||||
}
|
||||
|
||||
// We can also add this as a cw3 extension
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[cw_serde]
|
||||
#[derive(QueryResponses)]
|
||||
pub enum QueryMsg {
|
||||
/// Return ThresholdResponse
|
||||
#[returns(cw_utils::ThresholdResponse)]
|
||||
Threshold {},
|
||||
/// Returns ProposalResponse
|
||||
#[returns(cw3::ProposalResponse)]
|
||||
Proposal { proposal_id: u64 },
|
||||
/// Returns ProposalListResponse
|
||||
#[returns(cw3::ProposalListResponse)]
|
||||
ListProposals {
|
||||
start_after: Option<u64>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
/// Returns ProposalListResponse
|
||||
#[returns(cw3::ProposalListResponse)]
|
||||
ReverseProposals {
|
||||
start_before: Option<u64>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
/// Returns VoteResponse
|
||||
#[returns(cw3::VoteResponse)]
|
||||
Vote { proposal_id: u64, voter: String },
|
||||
/// Returns VoteListResponse
|
||||
#[returns(cw3::VoteListResponse)]
|
||||
ListVotes {
|
||||
proposal_id: u64,
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
/// Returns VoterInfo
|
||||
#[returns(cw3::VoterResponse)]
|
||||
Voter { address: String },
|
||||
/// Returns VoterListResponse
|
||||
#[returns(cw3::VoterListResponse)]
|
||||
ListVoters {
|
||||
start_after: Option<String>,
|
||||
limit: Option<u32>,
|
||||
},
|
||||
/// Gets the current configuration.
|
||||
#[returns(crate::state::Config)]
|
||||
Config {},
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
||||
#[cw_serde]
|
||||
pub struct MigrateMsg {
|
||||
pub coconut_bandwidth_address: String,
|
||||
pub coconut_dkg_address: String,
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
use cosmwasm_schema::cw_serde;
|
||||
use cosmwasm_std::{Addr, QuerierWrapper};
|
||||
use cw3::DepositInfo;
|
||||
use cw4::Cw4Contract;
|
||||
use cw_storage_plus::Item;
|
||||
use cw_utils::{Duration, Threshold};
|
||||
|
||||
use crate::error::ContractError;
|
||||
|
||||
/// Defines who is able to execute proposals once passed
|
||||
#[cw_serde]
|
||||
pub enum Executor {
|
||||
/// Any member of the voting group, even with 0 points
|
||||
Member,
|
||||
/// Only the given address
|
||||
Only(Addr),
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct Config {
|
||||
pub threshold: Threshold,
|
||||
pub max_voting_period: Duration,
|
||||
// Total weight and voters are queried from this contract
|
||||
pub group_addr: Cw4Contract,
|
||||
pub coconut_bandwidth_addr: Addr,
|
||||
pub coconut_dkg_addr: Addr,
|
||||
// who is able to execute passed proposals
|
||||
// None means that anyone can execute
|
||||
pub executor: Option<Executor>,
|
||||
/// The price, if any, of creating a new proposal.
|
||||
pub proposal_deposit: Option<DepositInfo>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
// Executor can be set in 3 ways:
|
||||
// - Member: any member of the voting group is authorized
|
||||
// - Only: only passed address is authorized
|
||||
// - None: Everyone are authorized
|
||||
pub fn authorize(&self, querier: &QuerierWrapper, sender: &Addr) -> Result<(), ContractError> {
|
||||
if let Some(executor) = &self.executor {
|
||||
match executor {
|
||||
Executor::Member => {
|
||||
self.group_addr
|
||||
.is_member(querier, sender, None)?
|
||||
.ok_or(ContractError::Unauthorized {})?;
|
||||
}
|
||||
Executor::Only(addr) => {
|
||||
if addr != sender {
|
||||
return Err(ContractError::Unauthorized {});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// unique items
|
||||
pub const CONFIG: Item<Config> = Item::new("config");
|
||||
@@ -28,7 +28,7 @@ pub enum Period {
|
||||
After,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct PledgeData {
|
||||
pub amount: Coin,
|
||||
pub block_time: Timestamp,
|
||||
@@ -49,7 +49,7 @@ impl PledgeData {
|
||||
}
|
||||
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub enum PledgeCap {
|
||||
Percent(Percent),
|
||||
Absolute(Uint128), // This has to be in unym
|
||||
@@ -77,7 +77,7 @@ impl Default for PledgeCap {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
pub struct OriginalVestingResponse {
|
||||
pub amount: Coin,
|
||||
pub number_of_periods: usize,
|
||||
|
||||
@@ -55,7 +55,7 @@ impl VestingSpecification {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ExecuteMsg {
|
||||
// Families
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||
cosmrs = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
|
||||
# I guess temporarily until we get serde support in coconut up and running
|
||||
|
||||
@@ -6,8 +6,8 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bip32 = "0.3.0"
|
||||
k256 = "0.10.4"
|
||||
bip32 = "0.4.0"
|
||||
k256 = { workspace = true }
|
||||
ledger-transport = "0.10.0"
|
||||
ledger-transport-hid = "0.10.0"
|
||||
thiserror = "1"
|
||||
@@ -3,12 +3,15 @@
|
||||
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddressError;
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::{NymPacketError, SphinxError};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MixProcessingError {
|
||||
#[error("failed to process received packet: {0}")]
|
||||
NymPacketProcessingError(#[from] NymPacketError),
|
||||
|
||||
#[error("failed to process received sphinx packet: {0}")]
|
||||
SphinxProcessingError(#[from] SphinxError),
|
||||
|
||||
#[error("the forward hop address was malformed: {0}")]
|
||||
|
||||
@@ -7,11 +7,11 @@ use log::*;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||
use nym_sphinx_framing::packet::FramedNymPacket;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use nym_sphinx_types::{
|
||||
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, Payload, PrivateKey,
|
||||
ProcessedPacket, SphinxPacket,
|
||||
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, NymPacket, NymProcessedPacket,
|
||||
PrivateKey, ProcessedPacket,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
@@ -53,14 +53,14 @@ impl SphinxPacketProcessor {
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, packet), fields(cpucycles))
|
||||
)]
|
||||
fn perform_initial_sphinx_packet_processing(
|
||||
fn perform_initial_packet_processing(
|
||||
&self,
|
||||
packet: SphinxPacket,
|
||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||
packet: NymPacket,
|
||||
) -> Result<NymProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
packet.process(&self.sphinx_key).map_err(|err| {
|
||||
debug!("Failed to unwrap Sphinx packet: {err}");
|
||||
MixProcessingError::SphinxProcessingError(err)
|
||||
debug!("Failed to unwrap NymPacket packet: {err}");
|
||||
MixProcessingError::NymPacketProcessingError(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -72,17 +72,12 @@ impl SphinxPacketProcessor {
|
||||
)]
|
||||
fn perform_initial_unwrapping(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||
received: FramedNymPacket,
|
||||
) -> Result<NymProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
let packet_mode = received.packet_mode();
|
||||
let sphinx_packet = received.into_inner();
|
||||
let packet = received.into_inner();
|
||||
|
||||
if packet_mode.is_old_vpn() {
|
||||
return Err(MixProcessingError::ReceivedOldTypeVpnPacket);
|
||||
}
|
||||
|
||||
self.perform_initial_sphinx_packet_processing(sphinx_packet)
|
||||
self.perform_initial_packet_processing(packet)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,14 +85,14 @@ impl SphinxPacketProcessor {
|
||||
/// and packs all the data in a way that can be easily sent to the next hop.
|
||||
fn process_forward_hop(
|
||||
&self,
|
||||
packet: SphinxPacket,
|
||||
packet: NymPacket,
|
||||
forward_address: NodeAddressBytes,
|
||||
delay: SphinxDelay,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
let next_hop_address = NymNodeRoutingAddress::try_from(forward_address)?;
|
||||
|
||||
let mix_packet = MixPacket::new(next_hop_address, packet, packet_mode);
|
||||
let mix_packet = MixPacket::new(next_hop_address, packet, packet_type);
|
||||
Ok(MixProcessingResult::ForwardHop(mix_packet, Some(delay)))
|
||||
}
|
||||
|
||||
@@ -106,14 +101,17 @@ impl SphinxPacketProcessor {
|
||||
fn split_hop_data_into_ack_and_message(
|
||||
&self,
|
||||
mut extracted_data: Vec<u8>,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(Vec<u8>, Vec<u8>), MixProcessingError> {
|
||||
let ack_len = SurbAck::len(Some(packet_type));
|
||||
|
||||
// in theory it's impossible for this to fail since it managed to go into correct `match`
|
||||
// branch at the caller
|
||||
if extracted_data.len() < SurbAck::len() {
|
||||
if extracted_data.len() < ack_len {
|
||||
return Err(MixProcessingError::NoSurbAckInFinalHop);
|
||||
}
|
||||
|
||||
let message = extracted_data.split_off(SurbAck::len());
|
||||
let message = extracted_data.split_off(ack_len);
|
||||
let ack_data = extracted_data;
|
||||
Ok((ack_data, message))
|
||||
}
|
||||
@@ -124,21 +122,30 @@ impl SphinxPacketProcessor {
|
||||
&self,
|
||||
data: Vec<u8>,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(Option<MixPacket>, Vec<u8>), MixProcessingError> {
|
||||
match packet_size {
|
||||
PacketSize::AckPacket => {
|
||||
PacketSize::AckPacket | PacketSize::OutfoxAckPacket => {
|
||||
trace!("received an ack packet!");
|
||||
Ok((None, data))
|
||||
}
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => {
|
||||
| PacketSize::ExtendedPacket32
|
||||
| PacketSize::OutfoxRegularPacket => {
|
||||
trace!("received a normal packet!");
|
||||
let (ack_data, message) = self.split_hop_data_into_ack_and_message(data)?;
|
||||
let (ack_first_hop, ack_packet) = SurbAck::try_recover_first_hop_packet(&ack_data)?;
|
||||
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_mode);
|
||||
let (ack_data, message) =
|
||||
self.split_hop_data_into_ack_and_message(data, packet_type)?;
|
||||
let (ack_first_hop, ack_packet) =
|
||||
match SurbAck::try_recover_first_hop_packet(&ack_data, packet_type) {
|
||||
Ok((first_hop, packet)) => (first_hop, packet),
|
||||
Err(err) => {
|
||||
debug!("Failed to recover first hop from ack data: {err}");
|
||||
return Err(err.into());
|
||||
}
|
||||
};
|
||||
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_type);
|
||||
Ok((Some(forward_ack), message))
|
||||
}
|
||||
}
|
||||
@@ -150,14 +157,12 @@ impl SphinxPacketProcessor {
|
||||
fn process_final_hop(
|
||||
&self,
|
||||
destination: DestinationAddressBytes,
|
||||
payload: Payload,
|
||||
payload: Vec<u8>,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
let packet_message = payload.recover_plaintext()?;
|
||||
|
||||
let (forward_ack, message) =
|
||||
self.split_into_ack_and_message(packet_message, packet_size, packet_mode)?;
|
||||
self.split_into_ack_and_message(payload, packet_size, packet_type)?;
|
||||
|
||||
Ok(MixProcessingResult::FinalHop(ProcessedFinalHop {
|
||||
destination,
|
||||
@@ -170,18 +175,48 @@ impl SphinxPacketProcessor {
|
||||
/// or a final hop.
|
||||
fn perform_final_processing(
|
||||
&self,
|
||||
packet: ProcessedPacket,
|
||||
packet: NymProcessedPacket,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
match packet {
|
||||
ProcessedPacket::ForwardHop(packet, address, delay) => {
|
||||
self.process_forward_hop(*packet, address, delay, packet_mode)
|
||||
NymProcessedPacket::Sphinx(packet) => {
|
||||
match packet {
|
||||
ProcessedPacket::ForwardHop(packet, address, delay) => self
|
||||
.process_forward_hop(
|
||||
NymPacket::Sphinx(*packet),
|
||||
address,
|
||||
delay,
|
||||
packet_type,
|
||||
),
|
||||
// right now there's no use for the surb_id included in the header - probably it should get removed from the
|
||||
// sphinx all together?
|
||||
ProcessedPacket::FinalHop(destination, _, payload) => self.process_final_hop(
|
||||
destination,
|
||||
payload.recover_plaintext()?,
|
||||
packet_size,
|
||||
packet_type,
|
||||
),
|
||||
}
|
||||
}
|
||||
// right now there's no use for the surb_id included in the header - probably it should get removed from the
|
||||
// sphinx all together?
|
||||
ProcessedPacket::FinalHop(destination, _, payload) => {
|
||||
self.process_final_hop(destination, payload, packet_size, packet_mode)
|
||||
NymProcessedPacket::Outfox(packet) => {
|
||||
let next_address = *packet.next_address();
|
||||
let packet = packet.into_packet();
|
||||
if packet.is_final_hop() {
|
||||
self.process_final_hop(
|
||||
DestinationAddressBytes::from_bytes(next_address),
|
||||
packet.recover_plaintext().to_vec(),
|
||||
packet_size,
|
||||
packet_type,
|
||||
)
|
||||
} else {
|
||||
let mix_packet = MixPacket::new(
|
||||
NymNodeRoutingAddress::try_from_bytes(&next_address)?,
|
||||
NymPacket::Outfox(packet),
|
||||
PacketType::Outfox,
|
||||
);
|
||||
Ok(MixProcessingResult::ForwardHop(mix_packet, None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,19 +227,19 @@ impl SphinxPacketProcessor {
|
||||
)]
|
||||
pub fn process_received(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
// explicit packet size will help to correctly parse final hop
|
||||
measure!({
|
||||
let packet_size = received.packet_size();
|
||||
let packet_mode = received.packet_mode();
|
||||
let packet_type = received.packet_type();
|
||||
|
||||
// unwrap the sphinx packet and if possible and appropriate, cache keys
|
||||
let processed_packet = self.perform_initial_unwrapping(received)?;
|
||||
|
||||
// for forward packets, extract next hop and set delay (but do NOT delay here)
|
||||
// for final packets, extract SURBAck
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_mode)
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_type)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -226,31 +261,71 @@ mod tests {
|
||||
|
||||
let short_data = vec![42u8];
|
||||
assert!(processor
|
||||
.split_hop_data_into_ack_and_message(short_data)
|
||||
.split_hop_data_into_ack_and_message(short_data, PacketType::Mix)
|
||||
.is_err());
|
||||
|
||||
let sufficient_data = vec![42u8; SurbAck::len()];
|
||||
let sufficient_data = vec![42u8; SurbAck::len(Some(PacketType::Mix))];
|
||||
let (ack, data) = processor
|
||||
.split_hop_data_into_ack_and_message(sufficient_data.clone())
|
||||
.split_hop_data_into_ack_and_message(sufficient_data.clone(), PacketType::Mix)
|
||||
.unwrap();
|
||||
assert_eq!(sufficient_data, ack);
|
||||
assert!(data.is_empty());
|
||||
|
||||
let long_data = vec![42u8; SurbAck::len() * 5];
|
||||
let long_data = vec![42u8; SurbAck::len(Some(PacketType::Mix)) * 5];
|
||||
let (ack, data) = processor
|
||||
.split_hop_data_into_ack_and_message(long_data)
|
||||
.split_hop_data_into_ack_and_message(long_data, PacketType::Mix)
|
||||
.unwrap();
|
||||
assert_eq!(ack.len(), SurbAck::len());
|
||||
assert_eq!(data.len(), SurbAck::len() * 4)
|
||||
assert_eq!(ack.len(), SurbAck::len(Some(PacketType::Mix)));
|
||||
assert_eq!(data.len(), SurbAck::len(Some(PacketType::Mix)) * 4)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn splitting_hop_data_works_for_sufficiently_long_payload_outfox() {
|
||||
let processor = fixture();
|
||||
|
||||
let short_data = vec![42u8];
|
||||
assert!(processor
|
||||
.split_hop_data_into_ack_and_message(short_data, PacketType::Outfox)
|
||||
.is_err());
|
||||
|
||||
let sufficient_data = vec![42u8; SurbAck::len(Some(PacketType::Outfox))];
|
||||
let (ack, data) = processor
|
||||
.split_hop_data_into_ack_and_message(sufficient_data.clone(), PacketType::Outfox)
|
||||
.unwrap();
|
||||
assert_eq!(sufficient_data, ack);
|
||||
assert!(data.is_empty());
|
||||
|
||||
let long_data = vec![42u8; SurbAck::len(Some(PacketType::Outfox)) * 5];
|
||||
let (ack, data) = processor
|
||||
.split_hop_data_into_ack_and_message(long_data, PacketType::Outfox)
|
||||
.unwrap();
|
||||
assert_eq!(ack.len(), SurbAck::len(Some(PacketType::Outfox)));
|
||||
assert_eq!(data.len(), SurbAck::len(Some(PacketType::Outfox)) * 4)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn splitting_into_ack_and_message_returns_whole_data_for_ack() {
|
||||
let processor = fixture();
|
||||
|
||||
let data = vec![42u8; SurbAck::len() + 10];
|
||||
let data = vec![42u8; SurbAck::len(Some(PacketType::Mix)) + 10];
|
||||
let (ack, message) = processor
|
||||
.split_into_ack_and_message(data.clone(), PacketSize::AckPacket, Default::default())
|
||||
.split_into_ack_and_message(data.clone(), PacketSize::AckPacket, PacketType::Mix)
|
||||
.unwrap();
|
||||
assert!(ack.is_none());
|
||||
assert_eq!(data, message)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn splitting_into_ack_and_message_returns_whole_data_for_ack_outfox() {
|
||||
let processor = fixture();
|
||||
|
||||
let data = vec![42u8; SurbAck::len(Some(PacketType::Outfox)) + 10];
|
||||
let (ack, message) = processor
|
||||
.split_into_ack_and_message(
|
||||
data.clone(),
|
||||
PacketSize::OutfoxAckPacket,
|
||||
PacketType::Outfox,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(ack.is_none());
|
||||
assert_eq!(data, message)
|
||||
|
||||
@@ -17,6 +17,7 @@ tokio = { workspace = true, features = ["macros"]}
|
||||
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
|
||||
nym-task = { path = "../task" }
|
||||
nym-topology = { path = "../topology" }
|
||||
nym-sphinx-params = { path = "../nymsphinx/params" }
|
||||
# TODO: do we need the whole nymsphinx?
|
||||
nym-sphinx = { path = "../nymsphinx" }
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::message::NymMessage;
|
||||
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::preparer::{FragmentPreparer, PreparedFragment};
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_topology::{gateway, mix, NymTopology};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use serde::Serialize;
|
||||
@@ -243,7 +244,14 @@ where
|
||||
|
||||
// TODO: can we avoid this arc clone?
|
||||
let ack_key = Arc::clone(&self.ack_key);
|
||||
Ok(self.prepare_chunk_for_sending(fragment, topology, &ack_key, &address, &address)?)
|
||||
Ok(self.prepare_chunk_for_sending(
|
||||
fragment,
|
||||
topology,
|
||||
&ack_key,
|
||||
&address,
|
||||
&address,
|
||||
PacketType::Mix,
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn create_test_packet<T>(
|
||||
|
||||
@@ -28,9 +28,6 @@ nym-sphinx-types = { path = "types" }
|
||||
nym-crypto = { path = "../crypto", version = "0.3.0" }
|
||||
nym-topology = { path = "../topology" }
|
||||
|
||||
# outfox
|
||||
nym-outfox = { path = "../../nym-outfox" }
|
||||
|
||||
[dev-dependencies]
|
||||
nym-mixnet-contract-common = { path = "../cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-crypto = { path = "../crypto", version = "0.3.0", features = ["asymmetric"] }
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
|
||||
use crate::AckKey;
|
||||
use nym_crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, IvSizeUser};
|
||||
use nym_sphinx_params::{
|
||||
packet_sizes::PacketSize, AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN,
|
||||
};
|
||||
use nym_sphinx_params::{AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
// TODO: should those functions even exist in this file?
|
||||
@@ -26,12 +24,6 @@ pub fn recover_identifier(
|
||||
key: &AckKey,
|
||||
iv_id_ciphertext: &[u8],
|
||||
) -> Option<SerializedFragmentIdentifier> {
|
||||
// The content of an 'ACK' packet consists of AckEncryptionAlgorithm::IV followed by
|
||||
// serialized FragmentIdentifier
|
||||
if iv_id_ciphertext.len() != PacketSize::AckPacket.plaintext_size() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let iv_size = AckEncryptionAlgorithm::iv_size();
|
||||
let iv = iv_from_slice::<AckEncryptionAlgorithm>(&iv_id_ciphertext[..iv_size]);
|
||||
|
||||
|
||||
@@ -8,21 +8,18 @@ use nym_sphinx_addressing::nodes::{
|
||||
NymNodeRoutingAddress, NymNodeRoutingAddressError, MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
};
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::{
|
||||
delays::{self, Delay},
|
||||
SphinxPacket,
|
||||
};
|
||||
use nym_sphinx_params::{PacketType, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::delays::{self, Delay};
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError, MIN_PACKET_SIZE};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
use std::time;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SurbAck {
|
||||
surb_ack_packet: SphinxPacket,
|
||||
surb_ack_packet: NymPacket,
|
||||
first_hop_address: NymNodeRoutingAddress,
|
||||
expected_total_delay: Delay,
|
||||
}
|
||||
@@ -35,8 +32,8 @@ pub enum SurbAckRecoveryError {
|
||||
#[error("could not extract first hop address information - {0}")]
|
||||
InvalidAddress(#[from] NymNodeRoutingAddressError),
|
||||
|
||||
#[error("the contained sphinx packet was not correctly formed - {0}")]
|
||||
InvalidSphinxPacket(#[from] SphinxError),
|
||||
#[error("packet: {0}")]
|
||||
NymPacket(#[from] NymPacketError),
|
||||
}
|
||||
|
||||
impl SurbAck {
|
||||
@@ -47,6 +44,7 @@ impl SurbAck {
|
||||
marshaled_fragment_id: [u8; 5],
|
||||
average_delay: time::Duration,
|
||||
topology: &NymTopology,
|
||||
packet_type: PacketType,
|
||||
) -> Result<Self, NymTopologyError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
@@ -57,11 +55,34 @@ impl SurbAck {
|
||||
let destination = recipient.as_sphinx_destination();
|
||||
|
||||
let surb_ack_payload = prepare_identifier(rng, ack_key, marshaled_fragment_id);
|
||||
let packet_size = match packet_type {
|
||||
PacketType::Outfox => surb_ack_payload.len().max(MIN_PACKET_SIZE),
|
||||
PacketType::Mix => PacketSize::AckPacket.payload_size(),
|
||||
PacketType::Vpn => PacketSize::AckPacket.payload_size(),
|
||||
};
|
||||
|
||||
let surb_ack_packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(PacketSize::AckPacket.payload_size())
|
||||
.build_packet(surb_ack_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
let surb_ack_packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_build(
|
||||
surb_ack_payload,
|
||||
route.as_slice(),
|
||||
&destination,
|
||||
Some(packet_size),
|
||||
)?,
|
||||
PacketType::Mix => NymPacket::sphinx_build(
|
||||
packet_size,
|
||||
surb_ack_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
packet_size,
|
||||
surb_ack_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
};
|
||||
|
||||
// in our case, the last hop is a gateway that does NOT do any delays
|
||||
let expected_total_delay = delays.iter().take(delays.len() - 1).sum();
|
||||
@@ -75,45 +96,50 @@ impl SurbAck {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn len() -> usize {
|
||||
pub fn len(packet_type: Option<PacketType>) -> usize {
|
||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||
PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN
|
||||
let packet_type = packet_type.unwrap_or(PacketType::Mix);
|
||||
match packet_type {
|
||||
PacketType::Outfox => {
|
||||
PacketSize::OutfoxAckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN
|
||||
}
|
||||
PacketType::Mix => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
PacketType::Vpn => PacketSize::AckPacket.size() + MAX_NODE_ADDRESS_UNPADDED_LEN,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expected_total_delay(&self) -> Delay {
|
||||
self.expected_total_delay
|
||||
}
|
||||
|
||||
pub fn prepare_for_sending(self) -> (Delay, Vec<u8>) {
|
||||
pub fn prepare_for_sending(self) -> Result<(Delay, Vec<u8>), SurbAckRecoveryError> {
|
||||
// SURB_FIRST_HOP || SURB_ACK
|
||||
let surb_bytes: Vec<_> = self
|
||||
.first_hop_address
|
||||
.as_zero_padded_bytes(MAX_NODE_ADDRESS_UNPADDED_LEN)
|
||||
.into_iter()
|
||||
.chain(self.surb_ack_packet.to_bytes().into_iter())
|
||||
.chain(self.surb_ack_packet.to_bytes()?.into_iter())
|
||||
.collect();
|
||||
(self.expected_total_delay, surb_bytes)
|
||||
Ok((self.expected_total_delay, surb_bytes))
|
||||
}
|
||||
|
||||
// partial reciprocal of `prepare_for_sending` performed by the gateway
|
||||
pub fn try_recover_first_hop_packet(
|
||||
b: &[u8],
|
||||
) -> Result<(NymNodeRoutingAddress, SphinxPacket), SurbAckRecoveryError> {
|
||||
if b.len() != Self::len() {
|
||||
Err(SurbAckRecoveryError::InvalidPacketSize {
|
||||
received: b.len(),
|
||||
expected: Self::len(),
|
||||
})
|
||||
} else {
|
||||
let address = NymNodeRoutingAddress::try_from_bytes(b)?;
|
||||
packet_type: PacketType,
|
||||
) -> Result<(NymNodeRoutingAddress, NymPacket), SurbAckRecoveryError> {
|
||||
let address = NymNodeRoutingAddress::try_from_bytes(b)?;
|
||||
|
||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
let packet = SphinxPacket::from_bytes(&b[address_offset..])?;
|
||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(&b[address_offset..])?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(&b[address_offset..])?,
|
||||
};
|
||||
|
||||
Ok((address, packet))
|
||||
}
|
||||
Ok((address, packet))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use nym_crypto::{generic_array::typenum::Unsigned, Digest};
|
||||
use nym_sphinx_addressing::clients::Recipient;
|
||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::{delays, Error as SphinxError, SURBMaterial, SphinxPacket, SURB};
|
||||
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::{delays, NymPacket, SURBMaterial, SphinxError, SURB};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::de::{Error as SerdeError, Visitor};
|
||||
@@ -173,7 +173,8 @@ impl ReplySurb {
|
||||
self,
|
||||
message: M,
|
||||
packet_size: PacketSize,
|
||||
) -> Result<(SphinxPacket, NymNodeRoutingAddress), ReplySurbError> {
|
||||
_packet_type: PacketType,
|
||||
) -> Result<(NymPacket, NymNodeRoutingAddress), ReplySurbError> {
|
||||
let message_bytes = message.as_ref();
|
||||
if message_bytes.len() != packet_size.plaintext_size() {
|
||||
return Err(ReplySurbError::UnpaddedMessageError);
|
||||
@@ -187,6 +188,6 @@ impl ReplySurb {
|
||||
|
||||
let first_hop_address = NymNodeRoutingAddress::try_from(first_hop).unwrap();
|
||||
|
||||
Ok((packet, first_hop_address))
|
||||
Ok((NymPacket::Sphinx(packet), first_hop_address))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
||||
use nym_sphinx_acknowledgements::AckKey;
|
||||
use nym_sphinx_addressing::clients::Recipient;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
@@ -11,10 +11,9 @@ use nym_sphinx_chunking::fragment::COVER_FRAG_ID;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{
|
||||
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketMode, DEFAULT_NUM_MIX_HOPS,
|
||||
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketType, DEFAULT_NUM_MIX_HOPS,
|
||||
};
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{delays, Error as SphinxError};
|
||||
use nym_sphinx_types::{delays, NymPacket};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
@@ -28,8 +27,11 @@ pub enum CoverMessageError {
|
||||
#[error("Could not construct cover message due to invalid topology - {0}")]
|
||||
InvalidTopologyError(#[from] NymTopologyError),
|
||||
|
||||
#[error("Could not construct a valid sphinx packet - {0}")]
|
||||
SphinxError(#[from] SphinxError),
|
||||
#[error("SurbAck: {0}")]
|
||||
SurbAck(#[from] SurbAckRecoveryError),
|
||||
|
||||
#[error("NymPacket: {0}")]
|
||||
NymPacket(#[from] nym_sphinx_types::NymPacketError),
|
||||
}
|
||||
|
||||
pub fn generate_loop_cover_surb_ack<R>(
|
||||
@@ -38,6 +40,7 @@ pub fn generate_loop_cover_surb_ack<R>(
|
||||
ack_key: &AckKey,
|
||||
full_address: &Recipient,
|
||||
average_ack_delay: time::Duration,
|
||||
packet_type: PacketType,
|
||||
) -> Result<SurbAck, CoverMessageError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
@@ -49,9 +52,11 @@ where
|
||||
COVER_FRAG_ID.to_bytes(),
|
||||
average_ack_delay,
|
||||
topology,
|
||||
packet_type,
|
||||
)?)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn generate_loop_cover_packet<R>(
|
||||
rng: &mut R,
|
||||
topology: &NymTopology,
|
||||
@@ -60,14 +65,21 @@ pub fn generate_loop_cover_packet<R>(
|
||||
average_ack_delay: time::Duration,
|
||||
average_packet_delay: time::Duration,
|
||||
packet_size: PacketSize,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixPacket, CoverMessageError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
// we don't care about total ack delay - we will not be retransmitting it anyway
|
||||
let (_, ack_bytes) =
|
||||
generate_loop_cover_surb_ack(rng, topology, ack_key, full_address, average_ack_delay)?
|
||||
.prepare_for_sending();
|
||||
let (_, ack_bytes) = generate_loop_cover_surb_ack(
|
||||
rng,
|
||||
topology,
|
||||
ack_key,
|
||||
full_address,
|
||||
average_ack_delay,
|
||||
packet_type,
|
||||
)?
|
||||
.prepare_for_sending()?;
|
||||
|
||||
// cover message can't be distinguishable from a normal traffic so we have to go through
|
||||
// all the effort of key generation, encryption, etc. Note here we are generating shared key
|
||||
@@ -111,15 +123,18 @@ where
|
||||
let destination = full_address.as_sphinx_destination();
|
||||
|
||||
// once merged, that's an easy rng injection point for sphinx packets : )
|
||||
let packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
let packet = NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?;
|
||||
|
||||
let first_hop_address =
|
||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||
|
||||
Ok(MixPacket::new(first_hop_address, packet, PacketMode::Mix))
|
||||
Ok(MixPacket::new(first_hop_address, packet, PacketType::Mix))
|
||||
}
|
||||
|
||||
/// Helper function used to determine if given message represents a loop cover message.
|
||||
|
||||
@@ -12,3 +12,4 @@ nym-sphinx-addressing = { path = "../addressing" }
|
||||
nym-sphinx-params = { path = "../params" }
|
||||
nym-sphinx-types = { path = "../types" }
|
||||
nym-outfox = { path = "../../../nym-outfox" }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -2,42 +2,28 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
|
||||
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MixPacketFormattingError {
|
||||
#[error("too few bytes provided to recover from bytes")]
|
||||
TooFewBytesProvided,
|
||||
InvalidPacketMode,
|
||||
#[error("provided packet mode is invalid")]
|
||||
InvalidPacketType,
|
||||
#[error("received request had invalid size - received {0}")]
|
||||
InvalidPacketSize(usize),
|
||||
#[error("address field was incorrectly encoded")]
|
||||
InvalidAddress,
|
||||
#[error("received sphinx packet was malformed")]
|
||||
MalformedSphinxPacket,
|
||||
#[error("Packet: {0}")]
|
||||
Packet(#[from] NymPacketError),
|
||||
}
|
||||
|
||||
impl Display for MixPacketFormattingError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
use MixPacketFormattingError::*;
|
||||
match self {
|
||||
TooFewBytesProvided => write!(f, "Too few bytes provided to recover from bytes"),
|
||||
InvalidAddress => write!(f, "address field was incorrectly encoded"),
|
||||
InvalidPacketSize(actual) =>
|
||||
write!(
|
||||
f,
|
||||
"received request had invalid size. (actual: {}, but expected one of: {} (ACK), {} (REGULAR), {}, {}, {} (EXTENDED))",
|
||||
actual, PacketSize::AckPacket.size(), PacketSize::RegularPacket.size(),
|
||||
PacketSize::ExtendedPacket8.size(), PacketSize::ExtendedPacket16.size(),
|
||||
PacketSize::ExtendedPacket32.size()
|
||||
),
|
||||
MalformedSphinxPacket => write!(f, "received sphinx packet was malformed"),
|
||||
InvalidPacketMode => write!(f, "provided packet mode is invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MixPacketFormattingError {}
|
||||
|
||||
impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
||||
fn from(_: NymNodeRoutingAddressError) -> Self {
|
||||
MixPacketFormattingError::InvalidAddress
|
||||
@@ -46,19 +32,16 @@ impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
||||
|
||||
pub struct MixPacket {
|
||||
next_hop: NymNodeRoutingAddress,
|
||||
sphinx_packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Debug for MixPacket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"MixPacket to {:?} with packet_mode {:?}. Sphinx header: {:?}, payload length: {}",
|
||||
self.next_hop,
|
||||
self.packet_mode,
|
||||
self.sphinx_packet.header,
|
||||
self.sphinx_packet.payload.len()
|
||||
"MixPacket to {:?} with packet_type {:?}. Packet {:?}",
|
||||
self.next_hop, self.packet_type, self.packet
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -66,13 +49,13 @@ impl Debug for MixPacket {
|
||||
impl MixPacket {
|
||||
pub fn new(
|
||||
next_hop: NymNodeRoutingAddress,
|
||||
sphinx_packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> Self {
|
||||
MixPacket {
|
||||
next_hop,
|
||||
sphinx_packet,
|
||||
packet_mode,
|
||||
packet,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,52 +63,52 @@ impl MixPacket {
|
||||
self.next_hop
|
||||
}
|
||||
|
||||
pub fn sphinx_packet(&self) -> &SphinxPacket {
|
||||
&self.sphinx_packet
|
||||
pub fn packet(&self) -> &NymPacket {
|
||||
&self.packet
|
||||
}
|
||||
|
||||
pub fn into_sphinx_packet(self) -> SphinxPacket {
|
||||
self.sphinx_packet
|
||||
pub fn into_packet(self) -> NymPacket {
|
||||
self.packet
|
||||
}
|
||||
|
||||
pub fn packet_mode(&self) -> PacketMode {
|
||||
self.packet_mode
|
||||
pub fn packet_type(&self) -> PacketType {
|
||||
self.packet_type
|
||||
}
|
||||
|
||||
// the message is formatted as follows:
|
||||
// PACKET_MODE || FIRST_HOP || SPHINX_PACKET
|
||||
// packet_type || FIRST_HOP || packet
|
||||
pub fn try_from_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
|
||||
let packet_mode = match PacketMode::try_from(b[0]) {
|
||||
let packet_type = match PacketType::try_from(b[0]) {
|
||||
Ok(mode) => mode,
|
||||
Err(_) => return Err(MixPacketFormattingError::InvalidPacketMode),
|
||||
Err(_) => return Err(MixPacketFormattingError::InvalidPacketType),
|
||||
};
|
||||
|
||||
let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[1..])?;
|
||||
let addr_offset = next_hop.bytes_min_len();
|
||||
|
||||
let sphinx_packet_data = &b[addr_offset + 1..];
|
||||
let packet_size = sphinx_packet_data.len();
|
||||
let packet_data = &b[addr_offset + 1..];
|
||||
let packet_size = packet_data.len();
|
||||
if PacketSize::get_type(packet_size).is_err() {
|
||||
Err(MixPacketFormattingError::InvalidPacketSize(packet_size))
|
||||
} else {
|
||||
let sphinx_packet = match SphinxPacket::from_bytes(sphinx_packet_data) {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => return Err(MixPacketFormattingError::MalformedSphinxPacket),
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(packet_data)?,
|
||||
_ => NymPacket::sphinx_from_bytes(packet_data)?,
|
||||
};
|
||||
|
||||
Ok(MixPacket {
|
||||
next_hop,
|
||||
sphinx_packet,
|
||||
packet_mode,
|
||||
packet,
|
||||
packet_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
std::iter::once(self.packet_mode as u8)
|
||||
pub fn into_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
|
||||
Ok(std::iter::once(self.packet_type as u8)
|
||||
.chain(self.next_hop.as_bytes().into_iter())
|
||||
.chain(self.sphinx_packet.to_bytes().into_iter())
|
||||
.collect()
|
||||
.chain(self.packet.to_bytes()?.into_iter())
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +1,56 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::packet::{FramedSphinxPacket, Header};
|
||||
use crate::packet::{FramedNymPacket, Header};
|
||||
use bytes::{Buf, BufMut, BytesMut};
|
||||
use nym_sphinx_params::packet_modes::InvalidPacketMode;
|
||||
use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::packet_types::InvalidPacketType;
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SphinxCodecError {
|
||||
pub enum NymCodecError {
|
||||
#[error("the packet size information was malformed - {0}")]
|
||||
InvalidPacketSize(#[from] InvalidPacketSize),
|
||||
|
||||
#[error("the packet mode information was malformed - {0}")]
|
||||
InvalidPacketMode(#[from] InvalidPacketMode),
|
||||
|
||||
#[error("the actual sphinx packet was malformed - {0}")]
|
||||
MalformedSphinxPacket(#[from] SphinxError),
|
||||
InvalidPacketType(#[from] InvalidPacketType),
|
||||
|
||||
#[error("encountered an IO error - {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
}
|
||||
|
||||
impl From<SphinxCodecError> for io::Error {
|
||||
fn from(err: SphinxCodecError) -> Self {
|
||||
match err {
|
||||
SphinxCodecError::InvalidPacketSize(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::InvalidPacketMode(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::MalformedSphinxPacket(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidData, source)
|
||||
}
|
||||
SphinxCodecError::IoError(err) => err,
|
||||
}
|
||||
}
|
||||
#[error("encountered a packet error - {0}")]
|
||||
NymPacket(#[from] NymPacketError),
|
||||
|
||||
#[error("could not convert to bytes")]
|
||||
ToBytes,
|
||||
|
||||
#[error("could not convert to bytes")]
|
||||
FromBytes,
|
||||
}
|
||||
|
||||
// TODO: in the future it could be extended to have state containing symmetric encryption key
|
||||
// so that all data could be encrypted easily (alternatively we could just slap TLS)
|
||||
pub struct SphinxCodec;
|
||||
pub struct NymCodec;
|
||||
|
||||
impl Encoder<FramedSphinxPacket> for SphinxCodec {
|
||||
type Error = SphinxCodecError;
|
||||
impl Encoder<FramedNymPacket> for NymCodec {
|
||||
type Error = NymCodecError;
|
||||
|
||||
fn encode(&mut self, item: FramedSphinxPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
fn encode(&mut self, item: FramedNymPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
item.header.encode(dst);
|
||||
dst.put(item.packet.to_bytes().as_ref());
|
||||
let packet_bytes = item.packet.to_bytes()?;
|
||||
let encoded = packet_bytes.as_slice();
|
||||
dst.put(encoded);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for SphinxCodec {
|
||||
type Item = FramedSphinxPacket;
|
||||
type Error = SphinxCodecError;
|
||||
impl Decoder for NymCodec {
|
||||
type Item = FramedNymPacket;
|
||||
type Error = NymCodecError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if src.is_empty() {
|
||||
@@ -76,23 +67,32 @@ impl Decoder for SphinxCodec {
|
||||
None => return Ok(None), // we have some data but not enough to get header back
|
||||
};
|
||||
|
||||
let sphinx_packet_size = header.packet_size.size();
|
||||
let frame_len = header.size() + sphinx_packet_size;
|
||||
let packet_size = header.packet_size.size();
|
||||
let frame_len = header.size() + packet_size;
|
||||
|
||||
if src.len() < frame_len {
|
||||
// we don't have enough bytes to read the rest of frame
|
||||
src.reserve(sphinx_packet_size);
|
||||
src.reserve(packet_size);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// advance buffer past the header - at this point we have enough bytes
|
||||
src.advance(header.size());
|
||||
let sphinx_packet_bytes = src.split_to(sphinx_packet_size);
|
||||
let packet_bytes = src.split_to(packet_size);
|
||||
let packet = if let Some(slice) = packet_bytes.get(..) {
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
match header.packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(slice)?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(slice)?,
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(slice)?,
|
||||
}
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||
let nymsphinx_packet = FramedSphinxPacket { header, packet };
|
||||
// let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||
let nymsphinx_packet = FramedNymPacket { header, packet };
|
||||
|
||||
// As per docs:
|
||||
// Before returning from the function, implementations should ensure that the buffer
|
||||
@@ -104,6 +104,7 @@ impl Decoder for SphinxCodec {
|
||||
// reserve for that.
|
||||
// we also assume the next packet coming from the same client will use exactly the same versioning
|
||||
// as the current packet
|
||||
|
||||
let mut allocate_for_next_packet = header.size() + PacketSize::AckPacket.size();
|
||||
if !src.is_empty() {
|
||||
match Header::decode(src) {
|
||||
@@ -120,7 +121,6 @@ impl Decoder for SphinxCodec {
|
||||
};
|
||||
}
|
||||
src.reserve(allocate_for_next_packet);
|
||||
|
||||
Ok(Some(nymsphinx_packet))
|
||||
}
|
||||
}
|
||||
@@ -128,13 +128,47 @@ impl Decoder for SphinxCodec {
|
||||
#[cfg(test)]
|
||||
mod packet_encoding {
|
||||
use super::*;
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{
|
||||
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
|
||||
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
};
|
||||
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> SphinxPacket {
|
||||
fn make_valid_outfox_packet(size: PacketSize) -> NymPacket {
|
||||
let (_, node1_pk) = crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||
node1_pk,
|
||||
);
|
||||
let (_, node2_pk) = crypto::keygen();
|
||||
let node2 = Node::new(
|
||||
NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
|
||||
node2_pk,
|
||||
);
|
||||
let (_, node3_pk) = crypto::keygen();
|
||||
let node3 = Node::new(
|
||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||
node3_pk,
|
||||
);
|
||||
|
||||
let (_, node4_pk) = crypto::keygen();
|
||||
let node4 = Node::new(
|
||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||
node4_pk,
|
||||
);
|
||||
|
||||
let destination = Destination::new(
|
||||
DestinationAddressBytes::from_bytes([3u8; DESTINATION_ADDRESS_LENGTH]),
|
||||
[4u8; IDENTIFIER_LENGTH],
|
||||
);
|
||||
|
||||
let route = &[node1, node2, node3, node4];
|
||||
|
||||
let payload = vec![1; 48];
|
||||
|
||||
NymPacket::outfox_build(payload, route, &destination, Some(size.plaintext_size())).unwrap()
|
||||
}
|
||||
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> NymPacket {
|
||||
let (_, node1_pk) = crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||
@@ -161,9 +195,7 @@ mod packet_encoding {
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
];
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(size.payload_size())
|
||||
.build_packet(b"foomp", &route, &destination, &delays)
|
||||
NymPacket::sphinx_build(size.payload_size(), b"foomp", &route, &destination, &delays)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -171,32 +203,50 @@ mod packet_encoding {
|
||||
fn whole_packet_can_be_decoded_from_a_valid_encoded_instance() {
|
||||
let header = Default::default();
|
||||
let sphinx_packet = make_valid_sphinx_packet(Default::default());
|
||||
let sphinx_bytes = sphinx_packet.to_bytes();
|
||||
let sphinx_bytes = sphinx_packet.to_bytes().unwrap();
|
||||
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header,
|
||||
packet: sphinx_packet,
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = SphinxCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
|
||||
assert_eq!(decoded.header, header);
|
||||
assert_eq!(decoded.packet.to_bytes(), sphinx_bytes)
|
||||
assert_eq!(decoded.packet.to_bytes().unwrap(), sphinx_bytes)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_outfox_can_be_decoded_from_a_valid_encoded_instance() {
|
||||
let header = Header::outfox();
|
||||
let packet = make_valid_outfox_packet(PacketSize::OutfoxRegularPacket);
|
||||
let packet_bytes = packet.to_bytes().unwrap();
|
||||
|
||||
NymPacket::outfox_from_bytes(packet_bytes.as_slice()).unwrap();
|
||||
|
||||
let packet = FramedNymPacket { header, packet };
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
|
||||
assert_eq!(decoded.header, header);
|
||||
assert_eq!(decoded.packet.to_bytes().unwrap(), packet_bytes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod decode_will_allocate_enough_bytes_for_next_call {
|
||||
use super::*;
|
||||
use nym_sphinx_params::packet_version::PacketVersion;
|
||||
use nym_sphinx_params::PacketMode;
|
||||
use nym_sphinx_params::PacketType;
|
||||
|
||||
#[test]
|
||||
fn for_empty_bytes() {
|
||||
// empty bytes should allocate for header + ack packet
|
||||
let mut empty_bytes = BytesMut::new();
|
||||
assert!(SphinxCodec.decode(&mut empty_bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut empty_bytes).unwrap().is_none());
|
||||
assert_eq!(
|
||||
empty_bytes.capacity(),
|
||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -217,11 +267,11 @@ mod packet_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
assert_eq!(bytes.capacity(), Header::LEGACY_SIZE + packet_size.size())
|
||||
}
|
||||
@@ -241,11 +291,11 @@ mod packet_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Versioned(123),
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
@@ -257,18 +307,17 @@ mod packet_encoding {
|
||||
#[test]
|
||||
fn for_full_frame_with_legacy_header() {
|
||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size: Default::default(),
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -278,14 +327,14 @@ mod packet_encoding {
|
||||
#[test]
|
||||
fn for_full_frame_with_versioned_header() {
|
||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
Header::VERSIONED_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -304,20 +353,19 @@ mod packet_encoding {
|
||||
];
|
||||
|
||||
for packet_size in packet_sizes {
|
||||
let first_packet = FramedSphinxPacket {
|
||||
let first_packet = FramedNymPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size: Default::default(),
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
bytes.put_u8(packet_size as u8);
|
||||
bytes.put_u8(PacketMode::default() as u8);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
bytes.put_u8(PacketType::default() as u8);
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
|
||||
assert!(bytes.capacity() >= Header::LEGACY_SIZE + packet_size.size())
|
||||
}
|
||||
@@ -335,53 +383,53 @@ mod packet_encoding {
|
||||
];
|
||||
|
||||
for packet_size in packet_sizes {
|
||||
let first_packet = FramedSphinxPacket {
|
||||
let first_packet = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
bytes.put_u8(PacketVersion::new_versioned(123).as_u8().unwrap());
|
||||
bytes.put_u8(packet_size as u8);
|
||||
bytes.put_u8(PacketMode::default() as u8);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
bytes.put_u8(PacketType::default() as u8);
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
|
||||
assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
||||
// assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_decode_two_packets_immediately() {
|
||||
let packet1 = FramedSphinxPacket {
|
||||
let packet1 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let packet2 = FramedSphinxPacket {
|
||||
let packet2 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
|
||||
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||
SphinxCodec.encode(packet2, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet2, &mut bytes).unwrap();
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_decode_two_packets_in_separate_calls() {
|
||||
let packet1 = FramedSphinxPacket {
|
||||
let packet1 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let packet2 = FramedSphinxPacket {
|
||||
let packet2 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
@@ -389,18 +437,17 @@ mod packet_encoding {
|
||||
let mut bytes = BytesMut::new();
|
||||
let mut bytes_tmp = BytesMut::new();
|
||||
|
||||
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||
SphinxCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
||||
|
||||
let tmp = bytes_tmp.split_off(100);
|
||||
bytes.put(bytes_tmp);
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
bytes.put(tmp);
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,57 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::codec::SphinxCodecError;
|
||||
use crate::codec::NymCodecError;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::packet_version::PacketVersion;
|
||||
use nym_sphinx_params::PacketMode;
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_sphinx_types::NymPacket;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub struct FramedSphinxPacket {
|
||||
#[derive(Debug)]
|
||||
pub struct FramedNymPacket {
|
||||
/// Contains any metadata helping receiver to handle the underlying packet.
|
||||
pub(crate) header: Header,
|
||||
|
||||
/// The actual SphinxPacket being sent.
|
||||
pub(crate) packet: SphinxPacket,
|
||||
pub(crate) packet: NymPacket,
|
||||
}
|
||||
|
||||
impl FramedSphinxPacket {
|
||||
pub fn new(packet: SphinxPacket, packet_mode: PacketMode, use_legacy_version: bool) -> Self {
|
||||
impl FramedNymPacket {
|
||||
pub fn new(packet: NymPacket, packet_type: PacketType, use_legacy_version: bool) -> Self {
|
||||
// If this fails somebody is using the library in a super incorrect way, because they
|
||||
// already managed to somehow create a sphinx packet
|
||||
let packet_size = PacketSize::get_type(packet.len()).unwrap();
|
||||
|
||||
FramedSphinxPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::new(use_legacy_version),
|
||||
packet_size,
|
||||
packet_mode,
|
||||
},
|
||||
packet,
|
||||
}
|
||||
let use_legacy = if packet_type == PacketType::Outfox {
|
||||
false
|
||||
} else {
|
||||
use_legacy_version
|
||||
};
|
||||
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::new(use_legacy),
|
||||
packet_size,
|
||||
packet_type,
|
||||
};
|
||||
|
||||
FramedNymPacket { header, packet }
|
||||
}
|
||||
|
||||
pub fn header(&self) -> Header {
|
||||
self.header
|
||||
}
|
||||
|
||||
pub fn packet_size(&self) -> PacketSize {
|
||||
self.header.packet_size
|
||||
}
|
||||
|
||||
pub fn packet_mode(&self) -> PacketMode {
|
||||
self.header.packet_mode
|
||||
pub fn packet_type(&self) -> PacketType {
|
||||
self.header.packet_type
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> SphinxPacket {
|
||||
pub fn into_inner(self) -> NymPacket {
|
||||
self.packet
|
||||
}
|
||||
}
|
||||
@@ -64,15 +74,23 @@ pub struct Header {
|
||||
///
|
||||
/// TODO: ask @AP whether this can be sent like this - could it introduce some anonymity issues?
|
||||
/// (note: this will be behind some encryption, either something implemented by us or some SSL action)
|
||||
// Note: currently packet_mode is deprecated but is still left as a concept behind to not break
|
||||
// Note: currently packet_type is deprecated but is still left as a concept behind to not break
|
||||
// compatibility with existing network
|
||||
pub(crate) packet_mode: PacketMode,
|
||||
pub(crate) packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
pub(crate) const LEGACY_SIZE: usize = 2;
|
||||
pub(crate) const VERSIONED_SIZE: usize = 3;
|
||||
|
||||
pub fn outfox() -> Header {
|
||||
Header {
|
||||
packet_version: PacketVersion::default(),
|
||||
packet_size: PacketSize::OutfoxRegularPacket,
|
||||
packet_type: PacketType::Outfox,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
if self.packet_version.is_legacy() {
|
||||
Self::LEGACY_SIZE
|
||||
@@ -90,12 +108,12 @@ impl Header {
|
||||
}
|
||||
|
||||
dst.put_u8(self.packet_size as u8);
|
||||
dst.put_u8(self.packet_mode as u8);
|
||||
dst.put_u8(self.packet_type as u8);
|
||||
// reserve bytes for the actual packet
|
||||
dst.reserve(self.packet_size.size());
|
||||
}
|
||||
|
||||
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, SphinxCodecError> {
|
||||
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, NymCodecError> {
|
||||
if src.len() < Self::LEGACY_SIZE {
|
||||
// can't do anything if we don't have enough bytes - but reserve enough for the next call
|
||||
src.reserve(Self::LEGACY_SIZE);
|
||||
@@ -107,7 +125,7 @@ impl Header {
|
||||
Ok(Some(Header {
|
||||
packet_version,
|
||||
packet_size: PacketSize::try_from(src[0])?,
|
||||
packet_mode: PacketMode::try_from(src[1])?,
|
||||
packet_type: PacketType::try_from(src[1])?,
|
||||
}))
|
||||
} else if src.len() < Self::VERSIONED_SIZE {
|
||||
// we're missing that 1 byte to read the full header...
|
||||
@@ -117,7 +135,7 @@ impl Header {
|
||||
Ok(Some(Header {
|
||||
packet_version,
|
||||
packet_size: PacketSize::try_from(src[1])?,
|
||||
packet_mode: PacketMode::try_from(src[2])?,
|
||||
packet_type: PacketType::try_from(src[2])?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -148,7 +166,7 @@ mod header_encoding {
|
||||
[
|
||||
PacketVersion::new_versioned(123).as_u8().unwrap(),
|
||||
unknown_packet_size,
|
||||
PacketMode::default() as u8,
|
||||
PacketType::default() as u8,
|
||||
]
|
||||
.as_ref(),
|
||||
);
|
||||
@@ -156,12 +174,12 @@ mod header_encoding {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding_will_fail_for_unknown_packet_mode() {
|
||||
let unknown_packet_mode: u8 = 255;
|
||||
fn decoding_will_fail_for_unknown_packet_type() {
|
||||
let unknown_packet_type: u8 = 255;
|
||||
// make sure this is still 'unknown' for if we make changes in the future
|
||||
assert!(PacketMode::try_from(unknown_packet_mode).is_err());
|
||||
assert!(PacketType::try_from(unknown_packet_type).is_err());
|
||||
|
||||
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_mode].as_ref());
|
||||
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_type].as_ref());
|
||||
assert!(Header::decode(&mut bytes).is_err())
|
||||
}
|
||||
|
||||
@@ -191,7 +209,7 @@ mod header_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
@@ -212,7 +230,7 @@ mod header_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Versioned(123),
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
|
||||
@@ -8,11 +8,11 @@ use nym_crypto::ctr;
|
||||
type Aes128Ctr = ctr::Ctr64BE<Aes128>;
|
||||
|
||||
// Re-export for ease of use
|
||||
pub use packet_modes::PacketMode;
|
||||
pub use packet_sizes::PacketSize;
|
||||
pub use packet_types::PacketType;
|
||||
|
||||
pub mod packet_modes;
|
||||
pub mod packet_sizes;
|
||||
pub mod packet_types;
|
||||
pub mod packet_version;
|
||||
|
||||
// If somebody can provide an argument why it might be reasonable to have more than 255 mix hops,
|
||||
@@ -29,7 +29,7 @@ pub type SerializedFragmentIdentifier = [u8; FRAG_ID_LEN];
|
||||
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
|
||||
// - packet_version (starting with v1.1.0)
|
||||
// - packet_size indicator
|
||||
// - packet_mode
|
||||
// - packet_type
|
||||
// it also just so happens that the only valid values for packet_size indicator include values 1-6
|
||||
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
|
||||
// otherwise we should treat it as legacy
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketMode {
|
||||
received: u8,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum PacketMode {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
#[default]
|
||||
Mix = 0,
|
||||
|
||||
/// Represents a VPN packet that should not be delayed and ideally cached pre-computed keys
|
||||
/// should be used for unwrapping data. Note that it does not offer the same level of anonymity.
|
||||
Vpn = 1,
|
||||
}
|
||||
|
||||
impl PacketMode {
|
||||
pub fn is_mix(self) -> bool {
|
||||
self == PacketMode::Mix
|
||||
}
|
||||
|
||||
pub fn is_old_vpn(self) -> bool {
|
||||
self == PacketMode::Vpn
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for PacketMode {
|
||||
type Error = InvalidPacketMode;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketMode::Mix as u8) => Ok(Self::Mix),
|
||||
_ if value == (PacketMode::Vpn as u8) => Ok(Self::Vpn),
|
||||
v => Err(InvalidPacketMode { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::FRAG_ID_LEN;
|
||||
use crate::{PacketType, FRAG_ID_LEN};
|
||||
use nym_sphinx_types::header::HEADER_SIZE;
|
||||
use nym_sphinx_types::PAYLOAD_OVERHEAD_SIZE;
|
||||
use nym_sphinx_types::{
|
||||
MIN_PACKET_SIZE, MIX_PARAMS_LEN, OUTFOX_PACKET_OVERHEAD, PAYLOAD_OVERHEAD_SIZE,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
@@ -12,20 +14,24 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
// each sphinx packet contains mandatory header and payload padding + markers
|
||||
const PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
||||
const SPHINX_PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
||||
|
||||
// it's up to the smart people to figure those values out : )
|
||||
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + PACKET_OVERHEAD;
|
||||
|
||||
// TODO: even though we have 16B IV, is having just 5B (FRAG_ID_LEN) of the ID possibly insecure?
|
||||
|
||||
// TODO: I'm not entirely sure if we can easily extract `<AckEncryptionAlgorithm as NewStreamCipher>::NonceSize`
|
||||
// into a const usize before relevant stuff is stabilised in rust...
|
||||
const ACK_IV_SIZE: usize = 16;
|
||||
|
||||
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + PACKET_OVERHEAD;
|
||||
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + SPHINX_PACKET_OVERHEAD;
|
||||
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
|
||||
const OUTFOX_ACK_PACKET_SIZE: usize = MIN_PACKET_SIZE + OUTFOX_PACKET_OVERHEAD;
|
||||
const OUTFOX_REGULAR_PACKET_SIZE: usize = 2 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum InvalidPacketSize {
|
||||
@@ -62,6 +68,13 @@ pub enum PacketSize {
|
||||
// for example for streaming fast and furious in compressed XviD quality
|
||||
#[serde(rename = "extended16")]
|
||||
ExtendedPacket16 = 5,
|
||||
|
||||
#[serde(rename = "outfox_regular")]
|
||||
OutfoxRegularPacket = 6,
|
||||
|
||||
// for sending SURB-ACKs
|
||||
#[serde(rename = "outfox_ack")]
|
||||
OutfoxAckPacket = 7,
|
||||
}
|
||||
|
||||
impl PartialOrd for PacketSize {
|
||||
@@ -88,6 +101,8 @@ impl FromStr for PacketSize {
|
||||
"extended8" => Ok(Self::ExtendedPacket8),
|
||||
"extended16" => Ok(Self::ExtendedPacket16),
|
||||
"extended32" => Ok(Self::ExtendedPacket32),
|
||||
"outfox_regular" => Ok(Self::OutfoxRegularPacket),
|
||||
"outfox_ack" => Ok(Self::OutfoxAckPacket),
|
||||
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
|
||||
received: s.to_string(),
|
||||
}),
|
||||
@@ -103,6 +118,8 @@ impl Display for PacketSize {
|
||||
PacketSize::ExtendedPacket32 => write!(f, "extended32"),
|
||||
PacketSize::ExtendedPacket8 => write!(f, "extended8"),
|
||||
PacketSize::ExtendedPacket16 => write!(f, "extended16"),
|
||||
PacketSize::OutfoxRegularPacket => write!(f, "outfox_regular"),
|
||||
PacketSize::OutfoxAckPacket => write!(f, "outfox_ack"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,6 +144,8 @@ impl TryFrom<u8> for PacketSize {
|
||||
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
|
||||
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
|
||||
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
|
||||
_ if value == (PacketSize::OutfoxRegularPacket as u8) => Ok(Self::OutfoxRegularPacket),
|
||||
_ if value == (PacketSize::OutfoxAckPacket as u8) => Ok(Self::OutfoxAckPacket),
|
||||
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
|
||||
}
|
||||
}
|
||||
@@ -140,15 +159,41 @@ impl PacketSize {
|
||||
PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
|
||||
PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
|
||||
PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
|
||||
PacketSize::OutfoxRegularPacket => OUTFOX_REGULAR_PACKET_SIZE,
|
||||
PacketSize::OutfoxAckPacket => OUTFOX_ACK_PACKET_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn header_size(&self) -> usize {
|
||||
match self {
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => HEADER_SIZE,
|
||||
PacketSize::OutfoxRegularPacket | PacketSize::OutfoxAckPacket => MIX_PARAMS_LEN,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn payload_overhead(&self) -> usize {
|
||||
match self {
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => PAYLOAD_OVERHEAD_SIZE,
|
||||
PacketSize::OutfoxRegularPacket | PacketSize::OutfoxAckPacket => {
|
||||
OUTFOX_PACKET_OVERHEAD - MIX_PARAMS_LEN // Mix params are calculated into the total overhead so we take them out here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn plaintext_size(self) -> usize {
|
||||
self.size() - HEADER_SIZE - PAYLOAD_OVERHEAD_SIZE
|
||||
self.size() - self.header_size() - self.payload_overhead()
|
||||
}
|
||||
|
||||
pub const fn payload_size(self) -> usize {
|
||||
self.size() - HEADER_SIZE
|
||||
self.size() - self.header_size()
|
||||
}
|
||||
|
||||
pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
|
||||
@@ -162,6 +207,12 @@ impl PacketSize {
|
||||
Ok(PacketSize::ExtendedPacket16)
|
||||
} else if PacketSize::ExtendedPacket32.size() == size {
|
||||
Ok(PacketSize::ExtendedPacket32)
|
||||
} else if PacketSize::OutfoxRegularPacket.size() == size
|
||||
|| PacketSize::OutfoxRegularPacket.size() == size + 6
|
||||
{
|
||||
Ok(PacketSize::OutfoxRegularPacket)
|
||||
} else if PacketSize::OutfoxAckPacket.size() == size {
|
||||
Ok(PacketSize::OutfoxAckPacket)
|
||||
} else {
|
||||
Err(InvalidPacketSize::UnknownPacketSize { received: size })
|
||||
}
|
||||
@@ -169,7 +220,10 @@ impl PacketSize {
|
||||
|
||||
pub fn is_extended_size(&self) -> bool {
|
||||
match self {
|
||||
PacketSize::RegularPacket | PacketSize::AckPacket => false,
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::OutfoxAckPacket
|
||||
| PacketSize::OutfoxRegularPacket => false,
|
||||
PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => true,
|
||||
@@ -184,8 +238,16 @@ impl PacketSize {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type_from_plaintext(plaintext_size: usize) -> Result<Self, InvalidPacketSize> {
|
||||
let packet_size = plaintext_size + PACKET_OVERHEAD;
|
||||
pub fn get_type_from_plaintext(
|
||||
plaintext_size: usize,
|
||||
packet_type: PacketType,
|
||||
) -> Result<Self, InvalidPacketSize> {
|
||||
let overhead = match packet_type {
|
||||
PacketType::Mix => SPHINX_PACKET_OVERHEAD,
|
||||
PacketType::Vpn => SPHINX_PACKET_OVERHEAD,
|
||||
PacketType::Outfox => OUTFOX_PACKET_OVERHEAD,
|
||||
};
|
||||
let packet_size = plaintext_size + overhead;
|
||||
Self::get_type(packet_size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::PacketSize;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketType {
|
||||
received: u8,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub enum PacketType {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
#[default]
|
||||
Mix = 0,
|
||||
|
||||
/// Represents a packet that should be sent through the network as fast as possible.
|
||||
Vpn = 1,
|
||||
|
||||
/// Abusing this to add Outfox support
|
||||
Outfox = 2,
|
||||
}
|
||||
|
||||
impl fmt::Display for PacketType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PacketType::Mix => write!(f, "Mix"),
|
||||
PacketType::Vpn => write!(f, "Vpn"),
|
||||
PacketType::Outfox => write!(f, "Outfox"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketType {
|
||||
pub fn is_mix(self) -> bool {
|
||||
self == PacketType::Mix
|
||||
}
|
||||
|
||||
pub fn is_outfox(self) -> bool {
|
||||
self == PacketType::Outfox
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for PacketType {
|
||||
type Error = InvalidPacketType;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketType::Mix as u8) => Ok(Self::Mix),
|
||||
_ if value == (PacketType::Outfox as u8) => Ok(Self::Outfox),
|
||||
v => Err(InvalidPacketType { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PacketSize> for PacketType {
|
||||
fn from(s: PacketSize) -> Self {
|
||||
match s {
|
||||
PacketSize::RegularPacket => PacketType::Mix,
|
||||
PacketSize::AckPacket => PacketType::Mix,
|
||||
PacketSize::ExtendedPacket32 => PacketType::Mix,
|
||||
PacketSize::ExtendedPacket8 => PacketType::Mix,
|
||||
PacketSize::ExtendedPacket16 => PacketType::Mix,
|
||||
PacketSize::OutfoxRegularPacket => PacketType::Outfox,
|
||||
PacketSize::OutfoxAckPacket => PacketType::Outfox,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{PacketSize, CURRENT_PACKET_VERSION_NUMBER};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum PacketVersion {
|
||||
// this will allow updated mixnodes to still understand packets from before the update
|
||||
Legacy,
|
||||
|
||||
@@ -21,4 +21,4 @@ pub use nym_sphinx_types::*;
|
||||
pub use nym_sphinx_framing as framing;
|
||||
|
||||
// TEMP UNTIL FURTHER REFACTORING
|
||||
pub use preparer::payload::NymsphinxPayloadBuilder;
|
||||
pub use preparer::payload::NymPayloadBuilder;
|
||||
|
||||
@@ -11,12 +11,14 @@ use nym_sphinx_anonymous_replies::requests::{
|
||||
ReplyMessageContent,
|
||||
};
|
||||
use nym_sphinx_chunking::fragment::Fragment;
|
||||
use nym_sphinx_params::{PacketSize, ReplySurbKeyDigestAlgorithm};
|
||||
use nym_sphinx_params::{PacketSize, PacketType, ReplySurbKeyDigestAlgorithm};
|
||||
use rand::Rng;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
pub(crate) const ACK_OVERHEAD: usize = MAX_NODE_ADDRESS_UNPADDED_LEN + PacketSize::AckPacket.size();
|
||||
pub(crate) const OUTFOX_ACK_OVERHEAD: usize =
|
||||
MAX_NODE_ADDRESS_UNPADDED_LEN + PacketSize::OutfoxAckPacket.size();
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NymMessageError {
|
||||
@@ -187,8 +189,15 @@ impl NymMessage {
|
||||
NymMessage::Reply(_) => ReplySurbKeyDigestAlgorithm::output_size(),
|
||||
};
|
||||
|
||||
let packet_type = PacketType::from(packet_size);
|
||||
|
||||
// each packet will contain an ack + variant specific data (as described above)
|
||||
packet_size.plaintext_size() - ACK_OVERHEAD - variant_overhead
|
||||
match packet_type {
|
||||
PacketType::Outfox => {
|
||||
packet_size.plaintext_size() - OUTFOX_ACK_OVERHEAD - variant_overhead
|
||||
}
|
||||
_ => packet_size.plaintext_size() - ACK_OVERHEAD - variant_overhead,
|
||||
}
|
||||
}
|
||||
|
||||
/// Length of the actual (from the **message** point of view) data that is available in each packet.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::message::{NymMessage, ACK_OVERHEAD};
|
||||
use crate::NymsphinxPayloadBuilder;
|
||||
use crate::message::{NymMessage, ACK_OVERHEAD, OUTFOX_ACK_OVERHEAD};
|
||||
use crate::NymPayloadBuilder;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::Digest;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
@@ -13,9 +13,8 @@ use nym_sphinx_anonymous_replies::reply_surb::ReplySurb;
|
||||
use nym_sphinx_chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{delays, Delay};
|
||||
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::{delays, Delay, NymPacket};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::convert::TryFrom;
|
||||
@@ -77,6 +76,7 @@ pub trait FragmentPreparer {
|
||||
fragment_id: FragmentIdentifier,
|
||||
topology: &NymTopology,
|
||||
ack_key: &AckKey,
|
||||
packet_type: PacketType,
|
||||
) -> Result<SurbAck, NymTopologyError> {
|
||||
let ack_delay = self.average_ack_delay();
|
||||
|
||||
@@ -87,6 +87,7 @@ pub trait FragmentPreparer {
|
||||
fragment_id.to_bytes(),
|
||||
ack_delay,
|
||||
topology,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -107,15 +108,20 @@ pub trait FragmentPreparer {
|
||||
ack_key: &AckKey,
|
||||
reply_surb: ReplySurb,
|
||||
packet_sender: &Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
// each reply attaches the digest of the encryption key so that the recipient could
|
||||
// lookup correct key for decryption,
|
||||
let reply_overhead = ReplySurbKeyDigestAlgorithm::output_size();
|
||||
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + reply_overhead;
|
||||
let expected_plaintext = match packet_type {
|
||||
PacketType::Outfox => fragment.serialized_size() + OUTFOX_ACK_OVERHEAD + reply_overhead,
|
||||
_ => fragment.serialized_size() + ACK_OVERHEAD + reply_overhead,
|
||||
};
|
||||
|
||||
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
||||
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
||||
// reply packets are always Sphinx
|
||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext, PacketType::Mix)
|
||||
.expect("the message has been incorrectly fragmented");
|
||||
|
||||
// this is not going to be accurate by any means. but that's the best estimation we can do
|
||||
@@ -126,24 +132,34 @@ pub trait FragmentPreparer {
|
||||
let fragment_identifier = fragment.fragment_identifier();
|
||||
|
||||
// create an ack
|
||||
let surb_ack =
|
||||
self.generate_surb_ack(packet_sender, fragment_identifier, topology, ack_key)?;
|
||||
let surb_ack = self.generate_surb_ack(
|
||||
packet_sender,
|
||||
fragment_identifier,
|
||||
topology,
|
||||
ack_key,
|
||||
packet_type,
|
||||
)?;
|
||||
let ack_delay = surb_ack.expected_total_delay();
|
||||
|
||||
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_reply(reply_surb.encryption_key());
|
||||
let packet_payload = match NymPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_reply(reply_surb.encryption_key())
|
||||
{
|
||||
Ok(payload) => payload,
|
||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
||||
};
|
||||
|
||||
// the unwrap here is fine as the failures can only originate from attempting to use invalid payload lengths
|
||||
// and we just very carefully constructed a (presumably) valid one
|
||||
let (sphinx_packet, first_hop_address) =
|
||||
reply_surb.apply_surb(packet_payload, packet_size).unwrap();
|
||||
let (sphinx_packet, first_hop_address) = reply_surb
|
||||
.apply_surb(packet_payload, packet_size, packet_type)
|
||||
.unwrap();
|
||||
|
||||
Ok(PreparedFragment {
|
||||
// the round-trip delay is the sum of delays of all hops on the forward route as
|
||||
// well as the total delay of the ack packet.
|
||||
// we don't know the delays inside the reply surbs so we use best-effort estimation from our poisson distribution
|
||||
total_delay: expected_forward_delay + ack_delay,
|
||||
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, Default::default()),
|
||||
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, packet_type),
|
||||
fragment_identifier,
|
||||
})
|
||||
}
|
||||
@@ -172,27 +188,42 @@ pub trait FragmentPreparer {
|
||||
ack_key: &AckKey,
|
||||
packet_sender: &Recipient,
|
||||
packet_recipient: &Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
|
||||
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
|
||||
// the packet encryption key
|
||||
let non_reply_overhead = encryption::PUBLIC_KEY_SIZE;
|
||||
let expected_plaintext = fragment.serialized_size() + ACK_OVERHEAD + non_reply_overhead;
|
||||
let expected_plaintext = match packet_type {
|
||||
PacketType::Outfox => {
|
||||
fragment.serialized_size() + OUTFOX_ACK_OVERHEAD + non_reply_overhead
|
||||
}
|
||||
_ => fragment.serialized_size() + ACK_OVERHEAD + non_reply_overhead,
|
||||
};
|
||||
|
||||
// the reason we're unwrapping (or rather 'expecting') here rather than handling the error
|
||||
// more gracefully is that this error should never be reached as it implies incorrect chunking
|
||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext)
|
||||
let packet_size = PacketSize::get_type_from_plaintext(expected_plaintext, packet_type)
|
||||
.expect("the message has been incorrectly fragmented");
|
||||
|
||||
let fragment_identifier = fragment.fragment_identifier();
|
||||
|
||||
// create an ack
|
||||
let surb_ack =
|
||||
self.generate_surb_ack(packet_sender, fragment_identifier, topology, ack_key)?;
|
||||
let surb_ack = self.generate_surb_ack(
|
||||
packet_sender,
|
||||
fragment_identifier,
|
||||
topology,
|
||||
ack_key,
|
||||
packet_type,
|
||||
)?;
|
||||
let ack_delay = surb_ack.expected_total_delay();
|
||||
|
||||
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_regular(self.rng(), packet_recipient.encryption_key());
|
||||
let packet_payload = match NymPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_regular(self.rng(), packet_recipient.encryption_key())
|
||||
{
|
||||
Ok(payload) => payload,
|
||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
||||
};
|
||||
|
||||
// generate pseudorandom route for the packet
|
||||
let hops = self.num_mix_hops();
|
||||
@@ -206,10 +237,28 @@ pub trait FragmentPreparer {
|
||||
|
||||
// create the actual sphinx packet here. With valid route and correct payload size,
|
||||
// there's absolutely no reason for this call to fail.
|
||||
let sphinx_packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_build(
|
||||
packet_payload,
|
||||
route.as_slice(),
|
||||
&destination,
|
||||
Some(packet_size.plaintext_size()),
|
||||
)?,
|
||||
PacketType::Mix => NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
PacketType::Vpn => NymPacket::sphinx_build(
|
||||
packet_size.payload_size(),
|
||||
packet_payload,
|
||||
&route,
|
||||
&destination,
|
||||
&delays,
|
||||
)?,
|
||||
};
|
||||
|
||||
// from the previously constructed route extract the first hop
|
||||
let first_hop_address =
|
||||
@@ -220,7 +269,7 @@ pub trait FragmentPreparer {
|
||||
// well as the total delay of the ack packet.
|
||||
// note that the last hop of the packet is a gateway that does not do any delays
|
||||
total_delay: delays.iter().take(delays.len() - 1).sum::<Delay>() + ack_delay,
|
||||
mix_packet: MixPacket::new(first_hop_address, sphinx_packet, Default::default()),
|
||||
mix_packet: MixPacket::new(first_hop_address, packet, packet_type),
|
||||
fragment_identifier,
|
||||
})
|
||||
}
|
||||
@@ -317,11 +366,18 @@ where
|
||||
topology: &NymTopology,
|
||||
ack_key: &AckKey,
|
||||
reply_surb: ReplySurb,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
let sender = self.sender_address;
|
||||
|
||||
<Self as FragmentPreparer>::prepare_reply_chunk_for_sending(
|
||||
self, fragment, topology, ack_key, reply_surb, &sender,
|
||||
self,
|
||||
fragment,
|
||||
topology,
|
||||
ack_key,
|
||||
reply_surb,
|
||||
&sender,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -331,6 +387,7 @@ where
|
||||
topology: &NymTopology,
|
||||
ack_key: &AckKey,
|
||||
packet_recipient: &Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
let sender = self.sender_address;
|
||||
|
||||
@@ -341,6 +398,7 @@ where
|
||||
ack_key,
|
||||
&sender,
|
||||
packet_recipient,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -350,9 +408,17 @@ where
|
||||
fragment_id: FragmentIdentifier,
|
||||
topology: &NymTopology,
|
||||
ack_key: &AckKey,
|
||||
packet_type: PacketType,
|
||||
) -> Result<SurbAck, NymTopologyError> {
|
||||
let sender = self.sender_address;
|
||||
<Self as FragmentPreparer>::generate_surb_ack(self, &sender, fragment_id, topology, ack_key)
|
||||
<Self as FragmentPreparer>::generate_surb_ack(
|
||||
self,
|
||||
&sender,
|
||||
fragment_id,
|
||||
topology,
|
||||
ack_key,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pad_and_split_message(
|
||||
|
||||
@@ -6,7 +6,7 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||
use nym_sphinx_chunking::fragment::Fragment;
|
||||
use nym_sphinx_params::{
|
||||
@@ -14,25 +14,25 @@ use nym_sphinx_params::{
|
||||
};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
pub struct NymsphinxPayloadBuilder {
|
||||
pub struct NymPayloadBuilder {
|
||||
fragment: Fragment,
|
||||
surb_ack: SurbAck,
|
||||
}
|
||||
|
||||
impl NymsphinxPayloadBuilder {
|
||||
impl NymPayloadBuilder {
|
||||
pub fn new(fragment: Fragment, surb_ack: SurbAck) -> Self {
|
||||
NymsphinxPayloadBuilder { fragment, surb_ack }
|
||||
NymPayloadBuilder { fragment, surb_ack }
|
||||
}
|
||||
|
||||
fn build<C>(
|
||||
self,
|
||||
packet_encryption_key: &CipherKey<C>,
|
||||
variant_data: impl IntoIterator<Item = u8>,
|
||||
) -> NymsphinxPayload
|
||||
) -> Result<NymPayload, SurbAckRecoveryError>
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending();
|
||||
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending()?;
|
||||
|
||||
let mut fragment_data = self.fragment.into_bytes();
|
||||
stream_cipher::encrypt_in_place::<C>(
|
||||
@@ -46,16 +46,20 @@ impl NymsphinxPayloadBuilder {
|
||||
// where variant-specific data is as follows:
|
||||
// for replies it would be the digest of the encryption key used
|
||||
// for 'regular' messages it would be the public component used in DH later used in the KDF
|
||||
NymsphinxPayload(
|
||||
|
||||
Ok(NymPayload(
|
||||
surb_ack_bytes
|
||||
.into_iter()
|
||||
.chain(variant_data.into_iter())
|
||||
.chain(fragment_data.into_iter())
|
||||
.collect(),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn build_reply(self, packet_encryption_key: &SurbEncryptionKey) -> NymsphinxPayload {
|
||||
pub fn build_reply(
|
||||
self,
|
||||
packet_encryption_key: &SurbEncryptionKey,
|
||||
) -> Result<NymPayload, SurbAckRecoveryError> {
|
||||
let key_digest = packet_encryption_key.compute_digest();
|
||||
self.build::<ReplySurbEncryptionAlgorithm>(
|
||||
packet_encryption_key.inner(),
|
||||
@@ -67,7 +71,7 @@ impl NymsphinxPayloadBuilder {
|
||||
self,
|
||||
rng: &mut R,
|
||||
recipient_encryption_key: &encryption::PublicKey,
|
||||
) -> NymsphinxPayload
|
||||
) -> Result<NymPayload, SurbAckRecoveryError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
@@ -88,9 +92,9 @@ impl NymsphinxPayloadBuilder {
|
||||
// the actual byte data that will be put into the sphinx packet paylaod.
|
||||
// no more transformations are going to happen to it
|
||||
// TODO: use that fact for some better compile time assertions
|
||||
pub struct NymsphinxPayload(Vec<u8>);
|
||||
pub struct NymPayload(Vec<u8>);
|
||||
|
||||
impl AsRef<[u8]> for NymsphinxPayload {
|
||||
impl AsRef<[u8]> for NymPayload {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
@@ -7,8 +7,6 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::shared_key::recompute_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||
use nym_outfox::error::OutfoxError;
|
||||
use nym_outfox::lion::lion_transform_decrypt;
|
||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||
use nym_sphinx_chunking::fragment::Fragment;
|
||||
@@ -76,49 +74,6 @@ pub enum MessageRecoveryError {
|
||||
|
||||
#[error("Failed to recover message fragment - {0}")]
|
||||
FragmentRecoveryError(#[from] ChunkingError),
|
||||
|
||||
#[error("Outfox: {source}")]
|
||||
OutfoxRecoveryError {
|
||||
#[from]
|
||||
source: OutfoxError,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OutfoxMessageReceiver {
|
||||
reconstructor: MessageReconstructor,
|
||||
}
|
||||
|
||||
impl OutfoxMessageReceiver {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageReceiver for OutfoxMessageReceiver {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn reconstructor(&mut self) -> &mut MessageReconstructor {
|
||||
&mut self.reconstructor
|
||||
}
|
||||
|
||||
fn num_mix_hops(&self) -> u8 {
|
||||
DEFAULT_NUM_MIX_HOPS
|
||||
}
|
||||
|
||||
fn decrypt_raw_message<C>(
|
||||
&self,
|
||||
message: &mut [u8],
|
||||
key: &CipherKey<C>,
|
||||
) -> Result<(), MessageRecoveryError>
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
lion_transform_decrypt(message, key)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageReceiver {
|
||||
|
||||
@@ -9,6 +9,5 @@ repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
sphinx-packet = { version = "0.1.0" }
|
||||
|
||||
#[patch.crates-io]
|
||||
#sphinx-packet = { path = "../../../../sphinx" }
|
||||
nym-outfox = { path = "../../../nym-outfox" }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use nym_outfox::{
|
||||
constants::MIN_PACKET_SIZE, constants::MIX_PARAMS_LEN, constants::OUTFOX_PACKET_OVERHEAD,
|
||||
error::OutfoxError,
|
||||
};
|
||||
// re-exporting types and constants available in sphinx
|
||||
use nym_outfox::packet::{OutfoxPacket, OutfoxProcessedPacket};
|
||||
pub use sphinx_packet::{
|
||||
constants::{
|
||||
self, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, MAX_PATH_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
@@ -9,9 +14,123 @@ pub use sphinx_packet::{
|
||||
},
|
||||
crypto::{self, EphemeralSecret, PrivateKey, PublicKey, SharedSecret},
|
||||
header::{self, delays, delays::Delay, ProcessedHeader, SphinxHeader, HEADER_SIZE},
|
||||
packet::builder::{self, DEFAULT_PAYLOAD_SIZE},
|
||||
packet::builder::DEFAULT_PAYLOAD_SIZE,
|
||||
payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
|
||||
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
|
||||
surb::{SURBMaterial, SURB},
|
||||
Error, ProcessedPacket, Result, SphinxPacket,
|
||||
Error as SphinxError, ProcessedPacket,
|
||||
};
|
||||
use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
|
||||
use std::{array::TryFromSliceError, fmt};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NymPacketError {
|
||||
#[error("Sphinx error: {0}")]
|
||||
Sphinx(#[from] sphinx_packet::Error),
|
||||
|
||||
#[error("Outfox error: {0}")]
|
||||
Outfox(#[from] nym_outfox::error::OutfoxError),
|
||||
|
||||
#[error("{0}")]
|
||||
FromSlice(#[from] TryFromSliceError),
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum NymPacket {
|
||||
Sphinx(SphinxPacket),
|
||||
Outfox(OutfoxPacket),
|
||||
}
|
||||
|
||||
pub enum NymProcessedPacket {
|
||||
Sphinx(ProcessedPacket),
|
||||
Outfox(OutfoxProcessedPacket),
|
||||
}
|
||||
|
||||
impl fmt::Debug for NymPacket {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self {
|
||||
NymPacket::Sphinx(packet) => f
|
||||
.debug_struct("NymPacket::Sphinx")
|
||||
.field("len", &packet.len())
|
||||
.finish(),
|
||||
NymPacket::Outfox(packet) => f
|
||||
.debug_struct("NymPacket::Outfox")
|
||||
.field("len", &packet.len())
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NymPacket {
|
||||
pub fn sphinx_build<M: AsRef<[u8]>>(
|
||||
size: usize,
|
||||
message: M,
|
||||
route: &[Node],
|
||||
destination: &Destination,
|
||||
delays: &[Delay],
|
||||
) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(size)
|
||||
.build_packet(message, route, destination, delays)?,
|
||||
))
|
||||
}
|
||||
pub fn sphinx_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Sphinx(SphinxPacket::from_bytes(bytes)?))
|
||||
}
|
||||
|
||||
pub fn outfox_build<M: AsRef<[u8]>>(
|
||||
payload: M,
|
||||
route: &[Node],
|
||||
destination: &Destination,
|
||||
size: Option<usize>,
|
||||
) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Outfox(OutfoxPacket::build(
|
||||
payload,
|
||||
route.try_into()?,
|
||||
destination,
|
||||
size,
|
||||
)?))
|
||||
}
|
||||
|
||||
pub fn outfox_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Outfox(OutfoxPacket::try_from(bytes)?))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => packet.len(),
|
||||
NymPacket::Outfox(packet) => packet.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, NymPacketError> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => Ok(packet.to_bytes()),
|
||||
NymPacket::Outfox(packet) => Ok(packet.to_bytes()?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(
|
||||
self,
|
||||
node_secret_key: &PrivateKey,
|
||||
) -> Result<NymProcessedPacket, NymPacketError> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => {
|
||||
Ok(NymProcessedPacket::Sphinx(packet.process(node_secret_key)?))
|
||||
}
|
||||
NymPacket::Outfox(mut packet) => {
|
||||
let next_address = packet.decode_next_layer(node_secret_key)?;
|
||||
Ok(NymProcessedPacket::Outfox(OutfoxProcessedPacket::new(
|
||||
packet,
|
||||
next_address,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::config::{Config, Socks5};
|
||||
use crate::error::Socks5ClientCoreError;
|
||||
use crate::socks::{
|
||||
authentication::{AuthenticationMethods, Authenticator, User},
|
||||
server::SphinxSocksServer,
|
||||
server::NymSocksServer,
|
||||
};
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
@@ -19,6 +19,7 @@ use nym_client_core::client::replies::reply_storage::ReplyStorageBackend;
|
||||
use nym_client_core::config::DebugConfig;
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::{TaskClient, TaskManager};
|
||||
use std::error::Error;
|
||||
|
||||
@@ -64,6 +65,7 @@ where
|
||||
NymClient { config, storage }
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn start_socks5_listener(
|
||||
socks5_config: &Socks5,
|
||||
debug_config: DebugConfig,
|
||||
@@ -72,6 +74,7 @@ where
|
||||
client_status: ClientState,
|
||||
self_address: Recipient,
|
||||
shutdown: TaskClient,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
info!("Starting socks5 listener...");
|
||||
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||
@@ -97,7 +100,7 @@ where
|
||||
.unwrap_or(debug_config.traffic.primary_packet_size);
|
||||
|
||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||
let mut sphinx_socks = SphinxSocksServer::new(
|
||||
let mut sphinx_socks = NymSocksServer::new(
|
||||
socks5_config.get_listening_port(),
|
||||
authenticator,
|
||||
socks5_config.get_provider_mix_address(),
|
||||
@@ -112,6 +115,7 @@ where
|
||||
socks5_config.get_per_request_surbs(),
|
||||
),
|
||||
shutdown.clone(),
|
||||
packet_type,
|
||||
);
|
||||
nym_task::spawn_with_report_error(
|
||||
async move {
|
||||
@@ -203,12 +207,18 @@ where
|
||||
reply_storage_backend,
|
||||
);
|
||||
|
||||
let mut started_client = base_builder.start_base().await?;
|
||||
let packet_type = self.config.get_base().get_packet_type();
|
||||
let mut started_client = base_builder.start_base(packet_type).await?;
|
||||
let self_address = started_client.address;
|
||||
let client_input = started_client.client_input.register_producer();
|
||||
let client_output = started_client.client_output.register_consumer();
|
||||
let client_state = started_client.client_state;
|
||||
|
||||
info!(
|
||||
"Running with {:?} packets",
|
||||
self.config.get_base().get_packet_type()
|
||||
);
|
||||
|
||||
Self::start_socks5_listener(
|
||||
self.config.get_socks5(),
|
||||
*self.config.get_debug_settings(),
|
||||
@@ -217,6 +227,7 @@ where
|
||||
client_state,
|
||||
self_address,
|
||||
started_client.task_manager.subscribe(),
|
||||
self.config.get_base().get_packet_type(),
|
||||
);
|
||||
|
||||
info!("Client startup finished!");
|
||||
|
||||
@@ -18,6 +18,7 @@ use nym_socks5_requests::{
|
||||
};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::{LaneQueueLengths, TransmissionLane};
|
||||
use nym_task::TaskClient;
|
||||
use pin_project::pin_project;
|
||||
@@ -185,6 +186,7 @@ pub(crate) struct SocksClient {
|
||||
started_proxy: bool,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
shutdown_listener: TaskClient,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Drop for SocksClient {
|
||||
@@ -213,6 +215,7 @@ impl SocksClient {
|
||||
self_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
mut shutdown_listener: TaskClient,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
// If this task fails and exits, we don't want to send shutdown signal
|
||||
shutdown_listener.mark_as_success();
|
||||
@@ -233,6 +236,7 @@ impl SocksClient {
|
||||
started_proxy: false,
|
||||
lane_queue_lengths,
|
||||
shutdown_listener,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +353,7 @@ impl SocksClient {
|
||||
msg.into_bytes(),
|
||||
self.config.connection_start_surbs,
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -371,6 +376,7 @@ impl SocksClient {
|
||||
self.service_provider,
|
||||
msg.into_bytes(),
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -408,6 +414,7 @@ impl SocksClient {
|
||||
let request_version = self.config.request_version();
|
||||
|
||||
let recipient = self.service_provider;
|
||||
let packet_type = self.packet_type;
|
||||
let (stream, _) = ProxyRunner::new(
|
||||
stream,
|
||||
local_stream_remote,
|
||||
@@ -439,9 +446,15 @@ impl SocksClient {
|
||||
provider_message.into_bytes(),
|
||||
per_request_surbs,
|
||||
lane,
|
||||
packet_type,
|
||||
)
|
||||
} else {
|
||||
InputMessage::new_regular(recipient, provider_message.into_bytes(), lane)
|
||||
InputMessage::new_regular(
|
||||
recipient,
|
||||
provider_message.into_bytes(),
|
||||
lane,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -10,6 +10,7 @@ use nym_client_core::client::{
|
||||
};
|
||||
use nym_socks5_proxy_helpers::connection_controller::Controller;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::{ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::TaskClient;
|
||||
use std::net::SocketAddr;
|
||||
@@ -17,7 +18,7 @@ use tap::TapFallible;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
/// A Socks5 server that listens for connections.
|
||||
pub struct SphinxSocksServer {
|
||||
pub struct NymSocksServer {
|
||||
authenticator: Authenticator,
|
||||
listening_address: SocketAddr,
|
||||
service_provider: Recipient,
|
||||
@@ -25,10 +26,12 @@ pub struct SphinxSocksServer {
|
||||
client_config: client::Config,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
shutdown: TaskClient,
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl SphinxSocksServer {
|
||||
impl NymSocksServer {
|
||||
/// Create a new SphinxSocks instance
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
port: u16,
|
||||
authenticator: Authenticator,
|
||||
@@ -37,12 +40,13 @@ impl SphinxSocksServer {
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
client_config: client::Config,
|
||||
shutdown: TaskClient,
|
||||
packet_type: PacketType,
|
||||
) -> Self {
|
||||
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
|
||||
// just modify the config
|
||||
let ip = "127.0.0.1";
|
||||
info!("Listening on {}:{}", ip, port);
|
||||
SphinxSocksServer {
|
||||
NymSocksServer {
|
||||
authenticator,
|
||||
listening_address: format!("{ip}:{port}").parse().unwrap(),
|
||||
service_provider,
|
||||
@@ -50,6 +54,7 @@ impl SphinxSocksServer {
|
||||
client_config,
|
||||
lane_queue_lengths,
|
||||
shutdown,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +109,7 @@ impl SphinxSocksServer {
|
||||
&self.self_address,
|
||||
self.lane_queue_lengths.clone(),
|
||||
self.shutdown.clone(),
|
||||
Some(self.packet_type)
|
||||
);
|
||||
|
||||
tokio::spawn(async move {
|
||||
@@ -119,8 +125,8 @@ impl SphinxSocksServer {
|
||||
});
|
||||
},
|
||||
_ = self.shutdown.recv() => {
|
||||
log::trace!("SphinxSocksServer: Received shutdown");
|
||||
log::debug!("SphinxSocksServer: Exiting");
|
||||
log::trace!("NymSocksServer: Received shutdown");
|
||||
log::debug!("NymSocksServer: Exiting");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::array::TryFromSliceError;
|
||||
|
||||
use crate::MixLayer;
|
||||
use nym_sphinx_types::NymPacketError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NymTopologyError {
|
||||
#[error("The provided network topology is empty - there are no mixnodes and no gateways on it - the network request(s) probably failed")]
|
||||
EmptyNetworkTopology,
|
||||
@@ -33,4 +36,16 @@ pub enum NymTopologyError {
|
||||
total_nodes: usize,
|
||||
layer_distribution: Vec<(MixLayer, usize)>,
|
||||
},
|
||||
// We can't import SurbAckRecoveryError due to cyclic dependency, this is a bit dirty
|
||||
#[error("Could not build payload")]
|
||||
PayloadBuilder,
|
||||
|
||||
#[error("Outfox: {0}")]
|
||||
Outfox(#[from] nym_sphinx_types::OutfoxError),
|
||||
|
||||
#[error("{0}")]
|
||||
FromSlice(#[from] TryFromSliceError),
|
||||
|
||||
#[error("{0}")]
|
||||
PacketError(#[from] NymPacketError),
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ url = "2.2"
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
cosmwasm-std = { workspace = true }
|
||||
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||
cosmrs = { workspace = true }
|
||||
|
||||
nym-validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||
"nyxd-client",
|
||||
|
||||
Generated
+492
-108
File diff suppressed because it is too large
Load Diff
+14
-13
@@ -32,16 +32,17 @@ incremental = false
|
||||
overflow-checks = true
|
||||
|
||||
[workspace.dependencies]
|
||||
cosmwasm-crypto = "=1.0.0"
|
||||
cosmwasm-derive = "=1.0.0"
|
||||
cosmwasm-schema = "=1.0.0"
|
||||
cosmwasm-std = "=1.0.0"
|
||||
cosmwasm-storage = "=1.0.0"
|
||||
cw-controllers = "=0.13.4"
|
||||
cw-multi-test = "=0.13.4"
|
||||
cw-storage-plus = "=0.13.4"
|
||||
cw-utils = "=0.13.4"
|
||||
cw2 = "=0.13.4"
|
||||
cw3 = "=0.13.4"
|
||||
cw3-fixed-multisig = "=0.13.4"
|
||||
cw4 = "=0.13.4"
|
||||
cosmwasm-crypto = "=1.2.5"
|
||||
cosmwasm-derive = "=1.2.5"
|
||||
cosmwasm-schema = "=1.2.5"
|
||||
cosmwasm-std = "=1.2.5"
|
||||
cosmwasm-storage = "=1.2.5"
|
||||
cw-controllers = "=1.0.1"
|
||||
cw-multi-test = "=0.16.4"
|
||||
cw-storage-plus = "=1.0.1"
|
||||
cw-utils = "=1.0.1"
|
||||
cw2 = "=1.0.1"
|
||||
cw3 = "=1.0.1"
|
||||
cw3-fixed-multisig = "=1.0.1"
|
||||
cw4 = "=1.0.1"
|
||||
cw20 = "=1.0.1"
|
||||
|
||||
@@ -30,7 +30,7 @@ impl<'a> IndexList<ContractVKShare> for VkShareIndex<'a> {
|
||||
pub(crate) fn vk_shares<'a>() -> IndexedMap<'a, VKShareKey<'a>, ContractVKShare, VkShareIndex<'a>> {
|
||||
let indexes = VkShareIndex {
|
||||
epoch_id: MultiIndex::new(
|
||||
|d| d.epoch_id,
|
||||
|_pk, d| d.epoch_id,
|
||||
VK_SHARES_PK_NAMESPACE,
|
||||
VK_SHARES_EPOCH_ID_IDX_NAMESPACE,
|
||||
),
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmwasm_std::{entry_point, Addr, Coin, DepsMut, Empty, Env, Response};
|
||||
use cw3_flex_multisig::state::CONFIG;
|
||||
use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper};
|
||||
use nym_multisig_contract_common::error::ContractError;
|
||||
use nym_multisig_contract_common::state::CONFIG;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ fn spend_credential_creates_proposal() {
|
||||
threshold: Threshold::AbsolutePercentage {
|
||||
percentage: Decimal::from_ratio(2u128, 3u128),
|
||||
},
|
||||
executor: None,
|
||||
proposal_deposit: None,
|
||||
max_voting_period: Duration::Height(1000),
|
||||
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
|
||||
coconut_dkg_contract_address: TEST_COCONUT_DKG_CONTRACT_ADDRESS.to_string(),
|
||||
|
||||
@@ -52,6 +52,8 @@ fn dkg_proposal() {
|
||||
threshold: Threshold::AbsolutePercentage {
|
||||
percentage: Decimal::from_ratio(1u128, 1u128),
|
||||
},
|
||||
executor: None,
|
||||
proposal_deposit: None,
|
||||
max_voting_period: Duration::Time(1000),
|
||||
coconut_bandwidth_contract_address: TEST_COCONUT_BANDWIDTH_CONTRACT_ADDRESS.to_string(),
|
||||
coconut_dkg_contract_address: TEST_COCONUT_DKG_CONTRACT_ADDRESS.to_string(),
|
||||
|
||||
@@ -520,7 +520,7 @@ mod tests {
|
||||
.delegations
|
||||
.iter()
|
||||
.filter(|d| d.proxy.is_some())
|
||||
.all(|d| d.proxy.as_ref().unwrap() == &vesting_contract));
|
||||
.all(|d| d.proxy.as_ref().unwrap() == vesting_contract));
|
||||
|
||||
// now make sure that if we do it in paged manner, we'll get exactly the same result
|
||||
let per_page = Some(15);
|
||||
|
||||
@@ -27,12 +27,12 @@ impl<'a> IndexList<Delegation> for DelegationIndex<'a> {
|
||||
pub(crate) fn delegations<'a>() -> IndexedMap<'a, PrimaryKey, Delegation, DelegationIndex<'a>> {
|
||||
let indexes = DelegationIndex {
|
||||
owner: MultiIndex::new(
|
||||
|d| d.owner.clone(),
|
||||
|_pk, d| d.owner.clone(),
|
||||
DELEGATION_PK_NAMESPACE,
|
||||
DELEGATION_OWNER_IDX_NAMESPACE,
|
||||
),
|
||||
mixnode: MultiIndex::new(
|
||||
|d| d.mix_id,
|
||||
|_pk, d| d.mix_id,
|
||||
DELEGATION_PK_NAMESPACE,
|
||||
DELEGATION_MIXNODE_IDX_NAMESPACE,
|
||||
),
|
||||
|
||||
@@ -39,12 +39,12 @@ pub(crate) fn unbonded_mixnodes<'a>(
|
||||
) -> IndexedMap<'a, MixId, UnbondedMixnode, UnbondedMixnodeIndex<'a>> {
|
||||
let indexes = UnbondedMixnodeIndex {
|
||||
owner: MultiIndex::new(
|
||||
|d| d.owner.clone(),
|
||||
|_pk, d| d.owner.clone(),
|
||||
UNBONDED_MIXNODES_PK_NAMESPACE,
|
||||
UNBONDED_MIXNODES_OWNER_IDX_NAMESPACE,
|
||||
),
|
||||
identity_key: MultiIndex::new(
|
||||
|d| d.identity_key.clone(),
|
||||
|_pk, d| d.identity_key.clone(),
|
||||
UNBONDED_MIXNODES_PK_NAMESPACE,
|
||||
UNBONDED_MIXNODES_IDENTITY_IDX_NAMESPACE,
|
||||
),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user