Compare commits

...

35 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 55a87e09f0 exposed additional helpers 2024-05-08 16:40:31 +01:00
Jędrzej Stuczyński 14f57889bf removed explicit drops 2024-05-08 16:40:04 +01:00
Jędrzej Stuczyński f89fa2d1e4 fixed tests 2024-05-08 16:40:04 +01:00
Jędrzej Stuczyński b22ca5e1ef upgraded axum and related deps to the most recent version 2024-05-08 16:40:04 +01:00
benedetta davico fe7484f0f4 Merge pull request #4564 from nymtech/feature/nyxd-scraper-pruning
Feature/nyxd scraper pruning
2024-05-08 11:08:06 +02:00
Jędrzej Stuczyński b63d04b10c Merge pull request #4574 from nymtech/feature/coconut-unchecked-aggregation
[feature]: expose coconut methods for aggregation without verification
2024-05-08 09:03:43 +01:00
Jędrzej Stuczyński 5a35068c87 fixing clippy issues in the workspace 2024-05-08 08:44:09 +01:00
Jędrzej Stuczyński 4899773e61 fixed unblind call in tests 2024-05-08 08:43:14 +01:00
Jędrzej Stuczyński 996f4afaf7 [feature]: expose coconut methods for aggregation without verification 2024-05-08 08:43:13 +01:00
import this d5c2a01a34 [DOCs/operators]: 2024.4 nutella release changelog & mixnode ipv6 clarification (#4581)
* edit IPv6 mixnode info

* add mixnode ipv6 info and nuttela changelog

* syntax edit
2024-05-07 15:49:29 +00:00
benedetta davico b1c58b36fe Merge pull request #4578 from nymtech/update-sign-nym-node
updating sign commands to include nym-node
2024-05-07 14:50:51 +02:00
benedettadavico dfbcc781db extra space.. 2024-05-07 14:36:43 +02:00
benedettadavico 5026960169 linting 2024-05-07 14:10:57 +02:00
benedetta davico 7c2710b61a Merge pull request #4579 from nymtech/bugfix/exit-poisson
[fix] apply disable_poisson_rate from internal NR/IPR cfgs
2024-05-07 14:09:44 +02:00
Jędrzej Stuczyński 0af807ac92 fixed overflow subtraction 2024-05-07 12:14:20 +01:00
Jędrzej Stuczyński bf9fc2d537 external clippy 2024-05-07 11:49:25 +01:00
Jędrzej Stuczyński 4182af9199 [fix] apply disable_poisson_rate from internal NR/IPR cfgs 2024-05-07 11:41:57 +01:00
benedettadavico 408d803344 adding both options 2024-05-07 12:34:26 +02:00
benedettadavico c2a5d6c035 updating sign commands to nym-node 2024-05-07 12:20:55 +02:00
Tommy Verrall 1136901daf Merge pull request #4572 from nymtech/bugfix/change-redirects
changed nym-node redirects from 308 'Permanent Redirect' to 303: 'See Other'
2024-05-07 09:29:41 +01:00
Tommy Verrall 593a1da0ff Merge pull request #4565 from nymtech/bugfix/delegations
Bug fix: wallet delegations list is empty when RPC node doesn't hold block
2024-05-07 09:07:04 +01:00
Tommy Verrall 9c17b7c269 Merge pull request #4571 from nymtech/operators/ipv6-troubleshooting
[DOC/operators]: More troubleshooting for IPv6 & install dependencies guides
2024-05-07 08:50:55 +01:00
serinko df398dbe05 add mixnode IPv6 setup 2024-05-06 13:00:51 +02:00
Jędrzej Stuczyński fd207d4699 changed nym-node redirects from 308 'Permanent Redirect' to 303: 'See Other' 2024-05-03 15:43:49 +01:00
serinko b9126dfc0e add troubleshooting for IPv6 & install dependencies 2024-05-03 13:19:59 +02:00
Mark Sinclair 6e23322ac4 Update nym-wallet/src/components/Delegation/DelegationList.tsx 2024-05-02 14:57:00 +01:00
fmtabbara 3ba83795d4 add error dialog 2024-05-02 11:22:34 +01:00
fmtabbara 6060ce5fb8 fix error tooltip overflow 2024-05-01 23:38:06 +01:00
Mark Sinclair 8fbad9cad8 Remove test errors 2024-05-01 19:33:10 +01:00
Mark Sinclair 650865e59a Wallet delegations: slow refresh from 1 min to 5 mins 2024-05-01 18:02:34 +01:00
Mark Sinclair 08e580ec8b Wallet delegations list - add an error to each row, and display as a tooltip if present 2024-05-01 17:59:46 +01:00
Mark Sinclair ad86ec9315 Wallet delegations: add more error information 2024-05-01 15:59:45 +01:00
Mark Sinclair 53ab4c8ec9 Wallet delegations: tap errors in requests per delegation. Return an error with strings of all sub errors. 2024-05-01 15:24:29 +01:00
Jędrzej Stuczyński f827eb4242 storage pruning implementation + additional logging 2024-04-30 15:53:45 +01:00
Jędrzej Stuczyński 9323ca9339 defined basic pruning types 2024-04-30 12:32:46 +01:00
72 changed files with 1927 additions and 704 deletions
Generated
+195 -67
View File
@@ -543,11 +543,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core 0.3.4",
"bitflags 1.3.2", "bitflags 1.3.2",
"bytes", "bytes",
"futures-util", "futures-util",
"headers",
"http 0.2.9", "http 0.2.9",
"http-body 0.4.5", "http-body 0.4.5",
"hyper 0.14.27", "hyper 0.14.27",
@@ -559,14 +558,44 @@ dependencies = [
"pin-project-lite 0.2.13", "pin-project-lite 0.2.13",
"rustversion", "rustversion",
"serde", "serde",
"sync_wrapper 0.1.2",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
dependencies = [
"async-trait",
"axum-core 0.4.3",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite 0.2.13",
"rustversion",
"serde",
"serde_json", "serde_json",
"serde_path_to_error", "serde_path_to_error",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper", "sync_wrapper 1.0.1",
"tokio", "tokio",
"tower", "tower",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
@@ -586,6 +615,50 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "axum-core"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite 0.2.13",
"rustversion",
"sync_wrapper 0.1.2",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-extra"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733"
dependencies = [
"axum 0.7.5",
"axum-core 0.4.3",
"bytes",
"futures-util",
"headers",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite 0.2.13",
"serde",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.69" version = "0.3.69"
@@ -631,6 +704,12 @@ version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@@ -2569,7 +2648,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"rand_pcg 0.3.1", "rand_pcg 0.3.1",
"rand_seeder", "rand_seeder",
"reqwest", "reqwest 0.12.4",
"rocket", "rocket",
"rocket_cors", "rocket_cors",
"rocket_okapi", "rocket_okapi",
@@ -3203,14 +3282,14 @@ dependencies = [
[[package]] [[package]]
name = "headers" name = "headers"
version = "0.3.9" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
dependencies = [ dependencies = [
"base64 0.21.4", "base64 0.21.4",
"bytes", "bytes",
"headers-core", "headers-core",
"http 0.2.9", "http 1.1.0",
"httpdate", "httpdate",
"mime", "mime",
"sha1", "sha1",
@@ -3218,11 +3297,11 @@ dependencies = [
[[package]] [[package]]
name = "headers-core" name = "headers-core"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [ dependencies = [
"http 0.2.9", "http 1.1.0",
] ]
[[package]] [[package]]
@@ -3404,9 +3483,9 @@ dependencies = [
[[package]] [[package]]
name = "http-range-header" name = "http-range-header"
version = "0.3.1" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
[[package]] [[package]]
name = "httparse" name = "httparse"
@@ -3481,9 +3560,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "1.2.0" version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@@ -3496,6 +3575,7 @@ dependencies = [
"pin-project-lite 0.2.13", "pin-project-lite 0.2.13",
"smallvec", "smallvec",
"tokio", "tokio",
"want",
] ]
[[package]] [[package]]
@@ -3531,13 +3611,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel",
"futures-util", "futures-util",
"http 1.1.0", "http 1.1.0",
"http-body 1.0.0", "http-body 1.0.0",
"hyper 1.2.0", "hyper 1.3.1",
"pin-project-lite 0.2.13", "pin-project-lite 0.2.13",
"socket2 0.5.4", "socket2 0.5.4",
"tokio", "tokio",
"tower",
"tower-service",
"tracing",
] ]
[[package]] [[package]]
@@ -3805,7 +3889,7 @@ dependencies = [
"socket2 0.5.4", "socket2 0.5.4",
"widestring", "widestring",
"windows-sys 0.48.0", "windows-sys 0.48.0",
"winreg", "winreg 0.50.0",
] ]
[[package]] [[package]]
@@ -5077,7 +5161,7 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"rand_chacha 0.2.2", "rand_chacha 0.2.2",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
"reqwest", "reqwest 0.12.4",
"rocket", "rocket",
"rocket_cors", "rocket_cors",
"rocket_okapi", "rocket_okapi",
@@ -5315,7 +5399,7 @@ dependencies = [
"gloo-timers", "gloo-timers",
"http-body-util", "http-body-util",
"humantime-serde", "humantime-serde",
"hyper 1.2.0", "hyper 1.3.1",
"hyper-util", "hyper-util",
"log", "log",
"nym-bandwidth-controller", "nym-bandwidth-controller",
@@ -5649,7 +5733,7 @@ dependencies = [
name = "nym-exit-policy" name = "nym-exit-policy"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@@ -5675,7 +5759,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"log", "log",
"nym-explorer-api-requests", "nym-explorer-api-requests",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"thiserror", "thiserror",
"tokio", "tokio",
@@ -5810,7 +5894,7 @@ name = "nym-http-api-client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@@ -5823,7 +5907,7 @@ dependencies = [
name = "nym-http-api-common" name = "nym-http-api-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum 0.7.5",
"bytes", "bytes",
"mime", "mime",
"serde", "serde",
@@ -5912,7 +5996,7 @@ dependencies = [
"nym-wireguard", "nym-wireguard",
"nym-wireguard-types", "nym-wireguard-types",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"tap", "tap",
@@ -5982,7 +6066,7 @@ name = "nym-mixnode"
version = "1.1.37" version = "1.1.37"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"axum", "axum 0.7.5",
"bs58 0.5.0", "bs58 0.5.0",
"clap 4.4.7", "clap 4.4.7",
"colored", "colored",
@@ -6134,7 +6218,7 @@ dependencies = [
"publicsuffix", "publicsuffix",
"rand 0.7.3", "rand 0.7.3",
"regex", "regex",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",
@@ -6211,12 +6295,14 @@ dependencies = [
name = "nym-node-http-api" name = "nym-node-http-api"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"axum", "axum 0.7.5",
"axum-extra",
"colored", "colored",
"dashmap", "dashmap",
"fastrand 2.0.1", "fastrand 2.0.1",
"headers",
"hmac 0.12.1", "hmac 0.12.1",
"hyper 0.14.27", "hyper 1.3.1",
"ipnetwork 0.16.0", "ipnetwork 0.16.0",
"nym-crypto", "nym-crypto",
"nym-http-api-common", "nym-http-api-common",
@@ -6396,7 +6482,7 @@ dependencies = [
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pretty_env_logger", "pretty_env_logger",
"rand 0.7.3", "rand 0.7.3",
"reqwest", "reqwest 0.12.4",
"tap", "tap",
"thiserror", "thiserror",
"tokio", "tokio",
@@ -6491,7 +6577,7 @@ dependencies = [
"nym-validator-client", "nym-validator-client",
"pin-project", "pin-project",
"rand 0.7.3", "rand 0.7.3",
"reqwest", "reqwest 0.12.4",
"schemars", "schemars",
"serde", "serde",
"tap", "tap",
@@ -6708,7 +6794,7 @@ version = "1.0.1"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"log", "log",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"sqlx", "sqlx",
@@ -6797,7 +6883,7 @@ dependencies = [
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"nym-validator-client", "nym-validator-client",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"reqwest", "reqwest 0.12.4",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
@@ -6847,7 +6933,7 @@ dependencies = [
"nym-service-provider-directory-common", "nym-service-provider-directory-common",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"prost 0.12.1", "prost 0.12.1",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.9.9", "sha2 0.9.9",
@@ -6978,7 +7064,7 @@ dependencies = [
"nym-bin-common", "nym-bin-common",
"nym-config", "nym-config",
"nym-task", "nym-task",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.8",
@@ -6999,7 +7085,8 @@ dependencies = [
"cosmrs 0.15.0 (git+https://github.com/jstuczyn/cosmos-rust?branch=nym-temp/all-validator-features)", "cosmrs 0.15.0 (git+https://github.com/jstuczyn/cosmos-rust?branch=nym-temp/all-validator-features)",
"eyre", "eyre",
"futures", "futures",
"nym-bin-common", "humantime 2.1.0",
"serde",
"sha2 0.10.8", "sha2 0.10.8",
"sqlx", "sqlx",
"tendermint", "tendermint",
@@ -8327,6 +8414,41 @@ dependencies = [
"system-configuration", "system-configuration",
"tokio", "tokio",
"tokio-rustls 0.24.1", "tokio-rustls 0.24.1",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.50.0",
]
[[package]]
name = "reqwest"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite 0.2.13",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper 0.1.2",
"tokio",
"tokio-socks", "tokio-socks",
"tokio-util", "tokio-util",
"tower-service", "tower-service",
@@ -8335,7 +8457,7 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-streams", "wasm-streams",
"web-sys", "web-sys",
"winreg", "winreg 0.52.0",
] ]
[[package]] [[package]]
@@ -8576,9 +8698,9 @@ dependencies = [
[[package]] [[package]]
name = "rust-embed" name = "rust-embed"
version = "6.8.1" version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661" checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
dependencies = [ dependencies = [
"rust-embed-impl", "rust-embed-impl",
"rust-embed-utils", "rust-embed-utils",
@@ -8587,23 +8709,22 @@ dependencies = [
[[package]] [[package]]
name = "rust-embed-impl" name = "rust-embed-impl"
version = "6.8.1" version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac" checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rust-embed-utils", "rust-embed-utils",
"shellexpand",
"syn 2.0.58", "syn 2.0.58",
"walkdir", "walkdir",
] ]
[[package]] [[package]]
name = "rust-embed-utils" name = "rust-embed-utils"
version = "7.8.1" version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74" checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
dependencies = [ dependencies = [
"sha2 0.10.8", "sha2 0.10.8",
"walkdir", "walkdir",
@@ -9209,15 +9330,6 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "shellexpand"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
dependencies = [
"dirs 4.0.0",
]
[[package]] [[package]]
name = "si-scale" name = "si-scale"
version = "0.2.2" version = "0.2.2"
@@ -9730,6 +9842,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sync_wrapper"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.12.6" version = "0.12.6"
@@ -9900,7 +10018,7 @@ dependencies = [
"getrandom 0.2.10", "getrandom 0.2.10",
"peg", "peg",
"pin-project", "pin-project",
"reqwest", "reqwest 0.11.22",
"semver 1.0.22", "semver 1.0.22",
"serde", "serde",
"serde_bytes", "serde_bytes",
@@ -10262,7 +10380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum 0.6.20",
"base64 0.21.4", "base64 0.21.4",
"bytes", "bytes",
"futures-core", "futures-core",
@@ -10305,16 +10423,16 @@ dependencies = [
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.4.4" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"bytes", "bytes",
"futures-core",
"futures-util", "futures-util",
"http 0.2.9", "http 1.1.0",
"http-body 0.4.5", "http-body 1.0.0",
"http-body-util",
"http-range-header", "http-range-header",
"httpdate", "httpdate",
"mime", "mime",
@@ -10812,9 +10930,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "utoipa" name = "utoipa"
version = "3.5.0" version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a" checksum = "272ebdfbc99111033031d2f10e018836056e4d2c8e2acda76450ec7974269fa7"
dependencies = [ dependencies = [
"indexmap 2.0.2", "indexmap 2.0.2",
"serde", "serde",
@@ -10824,9 +10942,9 @@ dependencies = [
[[package]] [[package]]
name = "utoipa-gen" name = "utoipa-gen"
version = "3.5.0" version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c" checksum = "d3c9f4d08338c1bfa70dde39412a040a884c6f318b3d09aaaf3437a1e52027fc"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@@ -10837,11 +10955,11 @@ dependencies = [
[[package]] [[package]]
name = "utoipa-swagger-ui" name = "utoipa-swagger-ui"
version = "3.1.5" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653" checksum = "0b39868d43c011961e04b41623e050aedf2cc93652562ff7935ce0f819aaf2da"
dependencies = [ dependencies = [
"axum", "axum 0.7.5",
"mime_guess", "mime_guess",
"regex", "regex",
"rust-embed", "rust-embed",
@@ -11089,9 +11207,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-streams" name = "wasm-streams"
version = "0.3.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"js-sys", "js-sys",
@@ -11704,6 +11822,16 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "winreg"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "with_builtin_macros" name = "with_builtin_macros"
version = "0.0.3" version = "0.0.3"
+7 -5
View File
@@ -160,7 +160,8 @@ license = "Apache-2.0"
[workspace.dependencies] [workspace.dependencies]
anyhow = "1.0.71" anyhow = "1.0.71"
async-trait = "0.1.68" async-trait = "0.1.68"
axum = "0.6.20" axum = "0.7.5"
axum-extra = "0.9.3"
base64 = "0.21.4" base64 = "0.21.4"
bs58 = "0.5.0" bs58 = "0.5.0"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
@@ -171,15 +172,16 @@ dotenvy = "0.15.6"
futures = "0.3.28" futures = "0.3.28"
generic-array = "0.14.7" generic-array = "0.14.7"
getrandom = "0.2.10" getrandom = "0.2.10"
headers = "0.4.0"
humantime-serde = "1.1.1" humantime-serde = "1.1.1"
hyper = "0.14.27" hyper = "1.3.1"
k256 = "0.13" k256 = "0.13"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4" log = "0.4"
once_cell = "1.7.2" once_cell = "1.7.2"
parking_lot = "0.12.1" parking_lot = "0.12.1"
rand = "0.8.5" rand = "0.8.5"
reqwest = { version = "0.11.22", default-features = false } reqwest = { version = "0.12.4", default-features = false }
schemars = "0.8.1" schemars = "0.8.1"
serde = "1.0.152" serde = "1.0.152"
serde_json = "1.0.91" serde_json = "1.0.91"
@@ -193,8 +195,8 @@ tokio-tungstenite = { version = "0.20.1" }
tracing = "0.1.37" tracing = "0.1.37"
tungstenite = { version = "0.20.1", default-features = false } tungstenite = { version = "0.20.1", default-features = false }
ts-rs = "7.0.0" ts-rs = "7.0.0"
utoipa = "3.5.0" utoipa = "4.2.0"
utoipa-swagger-ui = "3.1.5" utoipa-swagger-ui = "6.0.0"
url = "2.4" url = "2.4"
zeroize = "1.6.0" zeroize = "1.6.0"
+2 -2
View File
@@ -3,7 +3,7 @@ name = "nym-client-core"
version = "1.1.15" version = "1.1.15"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021" edition = "2021"
rust-version = "1.66" rust-version = "1.70"
license.workspace = true license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -48,7 +48,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu
nym-task = { path = "../task" } nym-task = { path = "../task" }
nym-credential-storage = { path = "../credential-storage" } nym-credential-storage = { path = "../credential-storage" }
nym-network-defaults = { path = "../network-defaults" } nym-network-defaults = { path = "../network-defaults" }
nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"]} nym-client-core-config-types = { path = "./config-types", features = ["disk-persistence"] }
nym-client-core-surb-storage = { path = "./surb-storage" } nym-client-core-surb-storage = { path = "./surb-storage" }
nym-client-core-gateways-storage = { path = "./gateways-storage" } nym-client-core-gateways-storage = { path = "./gateways-storage" }
@@ -8,3 +8,12 @@ use thiserror::Error;
pub struct ConfigUpgradeFailure { pub struct ConfigUpgradeFailure {
pub current_version: String, pub current_version: String,
} }
#[derive(Error, Debug)]
pub enum InvalidTrafficModeFailure {
#[error("attempted to set medium toggle traffic mode with fast mode flag")]
MediumToggleWithFastMode,
#[error("attempted to set medium toggle traffic mode with no cover flag")]
MediumToggleWithNoCover,
}
@@ -56,6 +56,7 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6
// 24 hours // 24 hours
const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60);
use crate::error::InvalidTrafficModeFailure;
pub use nym_country_group::CountryGroup; pub use nym_country_group::CountryGroup;
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
@@ -127,6 +128,56 @@ impl Config {
self self
} }
// TODO: this should be refactored properly
// as of 12.09.23 the below is true (not sure how this comment will rot in the future)
// medium_toggle:
// - sets secondary packet size to 16kb
// - disables poisson distribution of the main traffic stream
// - sets the cover traffic stream to 1 packet / 5s (on average)
// - disables per hop delay
//
// fastmode (to be renamed to `fast-poisson`):
// - sets average per hop delay to 10ms
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
//
// no_cover:
// - disables poisson distribution of the main traffic stream
// - disables the secondary cover traffic stream
#[doc(hidden)]
pub fn try_apply_traffic_modes(
&mut self,
disable_poisson_process: bool,
medium_toggle: bool,
fast_mode: bool,
no_cover: bool,
) -> Result<(), InvalidTrafficModeFailure> {
if disable_poisson_process {
self.set_no_poisson_process()
}
if medium_toggle {
if fast_mode {
return Err(InvalidTrafficModeFailure::MediumToggleWithFastMode);
}
if no_cover {
return Err(InvalidTrafficModeFailure::MediumToggleWithNoCover);
}
self.set_experimental_medium_toggle();
}
if fast_mode {
self.set_high_default_traffic_volume()
}
if no_cover {
self.set_no_cover_traffic();
}
Ok(())
}
pub fn set_high_default_traffic_volume(&mut self) { pub fn set_high_default_traffic_volume(&mut self) {
self.debug.traffic.average_packet_delay = Duration::from_millis(10); self.debug.traffic.average_packet_delay = Duration::from_millis(10);
// basically don't really send cover messages // basically don't really send cover messages
@@ -136,6 +187,15 @@ impl Config {
self.debug.traffic.message_sending_average_delay = Duration::from_millis(4); self.debug.traffic.message_sending_average_delay = Duration::from_millis(4);
} }
/// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc.
#[doc(hidden)]
pub fn set_experimental_medium_toggle(&mut self) {
self.set_no_cover_traffic_with_keepalive();
self.set_no_per_hop_delays();
self.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
}
pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self { pub fn with_disabled_poisson_process(mut self, disabled: bool) -> Self {
if disabled { if disabled {
self.set_no_poisson_process() self.set_no_poisson_process()
@@ -157,7 +157,7 @@ async fn fetch_delegation_data(
// If a pending undelegate tx is found, remove it from delegation map // If a pending undelegate tx is found, remove it from delegation map
Undelegate { owner, mix_id, .. } => { Undelegate { owner, mix_id, .. } => {
if owner == address.as_ref() if owner == address.as_ref()
&& existing_delegation_map.get(&mix_id.to_string()).is_some() && existing_delegation_map.contains_key(&mix_id.to_string())
{ {
existing_delegation_map.remove(&mix_id.to_string()); existing_delegation_map.remove(&mix_id.to_string());
} }
@@ -328,4 +328,8 @@ impl EpochState {
pub fn is_dealing_exchange(&self) -> bool { pub fn is_dealing_exchange(&self) -> bool {
matches!(self, EpochState::DealingExchange { .. }) matches!(self, EpochState::DealingExchange { .. })
} }
pub fn is_waiting_initialisation(&self) -> bool {
matches!(self, EpochState::WaitingInitialisation)
}
} }
+2 -2
View File
@@ -8,8 +8,8 @@ use std::str::FromStr;
use thiserror::Error; use thiserror::Error;
pub use nym_coconut::{ pub use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar, keygen, aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign, hash_to_scalar,
prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58, keygen, prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair, BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair,
Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare, Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare,
VerificationKey, VerifyCredentialRequest, VerificationKey, VerifyCredentialRequest,
@@ -10,18 +10,19 @@ use crate::coconut::bandwidth::{
use crate::coconut::utils::scalar_serde_helper; use crate::coconut::utils::scalar_serde_helper;
use crate::error::Error; use crate::error::Error;
use nym_credentials_interface::{ use nym_credentials_interface::{
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSerialNumber, aggregate_signature_shares_and_verify, hash_to_scalar, prepare_blind_sign, Attribute,
BlindedSignature, Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare, BlindedSerialNumber, BlindedSignature, Parameters, PrivateAttribute, PublicAttribute,
VerificationKey, Signature, SignatureShare, VerificationKey,
}; };
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_validator_client::nym_api::EpochId; use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::{Coin, Hash};
use nym_validator_client::signing::AccountData; use nym_validator_client::signing::AccountData;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use time::OffsetDateTime; use time::OffsetDateTime;
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
pub use nym_validator_client::nyxd::{Coin, Hash};
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)] #[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub enum BandwidthCredentialIssuanceDataVariant { pub enum BandwidthCredentialIssuanceDataVariant {
Voucher(BandwidthVoucherIssuanceData), Voucher(BandwidthVoucherIssuanceData),
@@ -279,7 +280,7 @@ impl IssuanceBandwidthCredential {
attributes.extend_from_slice(&private_attributes); attributes.extend_from_slice(&private_attributes);
attributes.extend_from_slice(&public_attributes); attributes.extend_from_slice(&public_attributes);
aggregate_signature_shares(params, verification_key, &attributes, shares) aggregate_signature_shares_and_verify(params, verification_key, &attributes, shares)
.map_err(Error::SignatureAggregationError) .map_err(Error::SignatureAggregationError)
} }
@@ -6,7 +6,7 @@ use crate::coconut::utils::scalar_serde_helper;
use crate::error::Error; use crate::error::Error;
use nym_api_requests::coconut::BlindSignRequestBody; use nym_api_requests::coconut::BlindSignRequestBody;
use nym_credentials_interface::{ use nym_credentials_interface::{
hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, PublicAttribute, hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, CredentialType, PublicAttribute,
}; };
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_validator_client::nyxd::{Coin, Hash}; use nym_validator_client::nyxd::{Coin, Hash};
@@ -123,6 +123,10 @@ impl BandwidthVoucherIssuanceData {
&self.value_prehashed &self.value_prehashed
} }
pub fn typ() -> CredentialType {
CredentialType::Voucher
}
pub fn tx_hash(&self) -> Hash { pub fn tx_hash(&self) -> Hash {
self.deposit_tx_hash self.deposit_tx_hash
} }
+5 -5
View File
@@ -6,10 +6,10 @@ use criterion::{criterion_group, criterion_main, Criterion};
use ff::Field; use ff::Field;
use group::{Curve, Group}; use group::{Curve, Group};
use nym_coconut::{ use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign, aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign,
prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential, prepare_blind_sign, prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen,
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature, verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters,
SignatureShare, VerificationKey, Signature, SignatureShare, VerificationKey,
}; };
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::ops::Neg; use std::ops::Neg;
@@ -99,7 +99,7 @@ fn unblind_and_aggregate(
let mut attributes = vec![]; let mut attributes = vec![];
attributes.extend_from_slice(private_attributes); attributes.extend_from_slice(private_attributes);
attributes.extend_from_slice(public_attributes); attributes.extend_from_slice(public_attributes);
aggregate_signature_shares( aggregate_signature_shares_and_verify(
params, params,
verification_key, verification_key,
&attributes, &attributes,
+7
View File
@@ -4,14 +4,18 @@
#![warn(clippy::expect_used)] #![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)] #![warn(clippy::unwrap_used)]
pub use bls12_381::Scalar;
pub use elgamal::elgamal_keygen; pub use elgamal::elgamal_keygen;
pub use elgamal::ElGamalKeyPair; pub use elgamal::ElGamalKeyPair;
pub use elgamal::PublicKey; pub use elgamal::PublicKey;
pub use error::CoconutError; pub use error::CoconutError;
pub use scheme::aggregation::aggregate_key_shares;
pub use scheme::aggregation::aggregate_signature_shares; pub use scheme::aggregation::aggregate_signature_shares;
pub use scheme::aggregation::aggregate_signature_shares_and_verify;
pub use scheme::aggregation::aggregate_verification_keys; pub use scheme::aggregation::aggregate_verification_keys;
pub use scheme::issuance::blind_sign; pub use scheme::issuance::blind_sign;
pub use scheme::issuance::prepare_blind_sign; pub use scheme::issuance::prepare_blind_sign;
pub use scheme::issuance::sign;
pub use scheme::issuance::verify_partial_blind_signature; pub use scheme::issuance::verify_partial_blind_signature;
pub use scheme::issuance::BlindSignRequest; pub use scheme::issuance::BlindSignRequest;
pub use scheme::keygen::keygen; pub use scheme::keygen::keygen;
@@ -19,16 +23,19 @@ pub use scheme::keygen::ttp_keygen;
pub use scheme::keygen::KeyPair; pub use scheme::keygen::KeyPair;
pub use scheme::keygen::SecretKey; pub use scheme::keygen::SecretKey;
pub use scheme::keygen::VerificationKey; pub use scheme::keygen::VerificationKey;
pub use scheme::keygen::VerificationKeyShare;
pub use scheme::setup::setup; pub use scheme::setup::setup;
pub use scheme::setup::Parameters; pub use scheme::setup::Parameters;
pub use scheme::verification::check_vk_pairing; pub use scheme::verification::check_vk_pairing;
pub use scheme::verification::prove_bandwidth_credential; pub use scheme::verification::prove_bandwidth_credential;
pub use scheme::verification::verify;
pub use scheme::verification::verify_credential; pub use scheme::verification::verify_credential;
pub use scheme::verification::BlindedSerialNumber; pub use scheme::verification::BlindedSerialNumber;
pub use scheme::verification::VerifyCredentialRequest; pub use scheme::verification::VerifyCredentialRequest;
pub use scheme::BlindedSignature; pub use scheme::BlindedSignature;
pub use scheme::Signature; pub use scheme::Signature;
pub use scheme::SignatureShare; pub use scheme::SignatureShare;
pub use scheme::SignerIndex;
pub use traits::Base58; pub use traits::Base58;
pub use traits::Bytable; pub use traits::Bytable;
pub use utils::hash_to_scalar; pub use utils::hash_to_scalar;
+55 -25
View File
@@ -12,7 +12,7 @@ use crate::error::{CoconutError, Result};
use crate::scheme::verification::check_bilinear_pairing; use crate::scheme::verification::check_bilinear_pairing;
use crate::scheme::{PartialSignature, Signature, SignatureShare, SignerIndex, VerificationKey}; use crate::scheme::{PartialSignature, Signature, SignatureShare, SignerIndex, VerificationKey};
use crate::utils::perform_lagrangian_interpolation_at_origin; use crate::utils::perform_lagrangian_interpolation_at_origin;
use crate::{Attribute, Parameters}; use crate::{Attribute, Parameters, VerificationKeyShare};
pub(crate) trait Aggregatable: Sized { pub(crate) trait Aggregatable: Sized {
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>; fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
@@ -80,7 +80,23 @@ pub fn aggregate_verification_keys(
Aggregatable::aggregate(keys, indices) Aggregatable::aggregate(keys, indices)
} }
pub fn aggregate_key_shares(shares: &[VerificationKeyShare]) -> Result<VerificationKey> {
let (keys, indices): (Vec<_>, Vec<_>) = shares
.iter()
.map(|share| (share.key.clone(), share.index))
.unzip();
aggregate_verification_keys(&keys, Some(&indices))
}
pub fn aggregate_signatures( pub fn aggregate_signatures(
signatures: &[PartialSignature],
indices: Option<&[SignerIndex]>,
) -> Result<Signature> {
Aggregatable::aggregate(signatures, indices)
}
pub fn aggregate_signatures_and_verify(
params: &Parameters, params: &Parameters,
verification_key: &VerificationKey, verification_key: &VerificationKey,
attributes: &[&Attribute], attributes: &[&Attribute],
@@ -88,11 +104,7 @@ pub fn aggregate_signatures(
indices: Option<&[SignerIndex]>, indices: Option<&[SignerIndex]>,
) -> Result<Signature> { ) -> Result<Signature> {
// aggregate the signature // aggregate the signature
let signature = aggregate_signatures(signatures, indices)?;
let signature = match Aggregatable::aggregate(signatures, indices) {
Ok(res) => res,
Err(err) => return Err(err),
};
// Verify the signature // Verify the signature
let alpha = verification_key.alpha; let alpha = verification_key.alpha;
@@ -116,7 +128,16 @@ pub fn aggregate_signatures(
Ok(signature) Ok(signature)
} }
pub fn aggregate_signature_shares( pub fn aggregate_signature_shares(shares: &[SignatureShare]) -> Result<Signature> {
let (signatures, indices): (Vec<_>, Vec<_>) = shares
.iter()
.map(|share| (*share.signature(), share.index()))
.unzip();
aggregate_signatures(&signatures, Some(&indices))
}
pub fn aggregate_signature_shares_and_verify(
params: &Parameters, params: &Parameters,
verification_key: &VerificationKey, verification_key: &VerificationKey,
attributes: &[&Attribute], attributes: &[&Attribute],
@@ -127,7 +148,7 @@ pub fn aggregate_signature_shares(
.map(|share| (*share.signature(), share.index())) .map(|share| (*share.signature(), share.index()))
.unzip(); .unzip();
aggregate_signatures( aggregate_signatures_and_verify(
params, params,
verification_key, verification_key,
attributes, attributes,
@@ -210,7 +231,7 @@ mod tests {
#[test] #[test]
fn signature_aggregation_works_for_any_subset_of_signatures() { fn signature_aggregation_works_for_any_subset_of_signatures() {
let mut params = Parameters::new(2).unwrap(); let params = Parameters::new(2).unwrap();
random_scalars_refs!(attributes, params, 2); random_scalars_refs!(attributes, params, 2);
let keypairs = ttp_keygen(&params, 3, 5).unwrap(); let keypairs = ttp_keygen(&params, 3, 5).unwrap();
@@ -227,12 +248,12 @@ mod tests {
let sigs = sks let sigs = sks
.iter() .iter()
.map(|sk| sign(&mut params, sk, &attributes).unwrap()) .map(|sk| sign(&params, sk, &attributes).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// aggregating (any) threshold works // aggregating (any) threshold works
let aggr_vk_1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap(); let aggr_vk_1 = aggregate_verification_keys(&vks[..3], Some(&[1, 2, 3])).unwrap();
let aggr_sig1 = aggregate_signatures( let aggr_sig1 = aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_1, &aggr_vk_1,
&attributes, &attributes,
@@ -242,7 +263,7 @@ mod tests {
.unwrap(); .unwrap();
let aggr_vk_2 = aggregate_verification_keys(&vks[2..], Some(&[3, 4, 5])).unwrap(); let aggr_vk_2 = aggregate_verification_keys(&vks[2..], Some(&[3, 4, 5])).unwrap();
let aggr_sig2 = aggregate_signatures( let aggr_sig2 = aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_1, &aggr_vk_1,
&attributes, &attributes,
@@ -258,7 +279,7 @@ mod tests {
// aggregating threshold+1 works // aggregating threshold+1 works
let aggr_vk_more = aggregate_verification_keys(&vks[1..], Some(&[2, 3, 4, 5])).unwrap(); let aggr_vk_more = aggregate_verification_keys(&vks[1..], Some(&[2, 3, 4, 5])).unwrap();
let aggr_more = aggregate_signatures( let aggr_more = aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_more, &aggr_vk_more,
&attributes, &attributes,
@@ -270,7 +291,7 @@ mod tests {
// aggregating all // aggregating all
let aggr_vk_all = aggregate_verification_keys(&vks, Some(&[1, 2, 3, 4, 5])).unwrap(); let aggr_vk_all = aggregate_verification_keys(&vks, Some(&[1, 2, 3, 4, 5])).unwrap();
let aggr_all = aggregate_signatures( let aggr_all = aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_all, &aggr_vk_all,
&attributes, &attributes,
@@ -282,7 +303,7 @@ mod tests {
// not taking enough points (threshold was 3) should fail // not taking enough points (threshold was 3) should fail
let aggr_vk_not_enough = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap(); let aggr_vk_not_enough = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
let aggr_not_enough = aggregate_signatures( let aggr_not_enough = aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_not_enough, &aggr_vk_not_enough,
&attributes, &attributes,
@@ -294,7 +315,7 @@ mod tests {
// taking wrong index should fail // taking wrong index should fail
let aggr_vk_bad = aggregate_verification_keys(&vks[2..], Some(&[1, 2, 3])).unwrap(); let aggr_vk_bad = aggregate_verification_keys(&vks[2..], Some(&[1, 2, 3])).unwrap();
assert!(aggregate_signatures( assert!(aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_bad, &aggr_vk_bad,
&attributes, &attributes,
@@ -330,9 +351,14 @@ mod tests {
.unzip(); .unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!( assert!(aggregate_signatures_and_verify(
aggregate_signatures(&params, &aggr_vk_all, &attributes, &signatures, None).is_err() &params,
); &aggr_vk_all,
&attributes,
&signatures,
None
)
.is_err());
} }
#[test] #[test]
@@ -352,11 +378,15 @@ mod tests {
.unzip(); .unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!( assert!(aggregate_signatures_and_verify(
aggregate_signatures(&params, &aggr_vk_all, &attributes, &signatures, Some(&[])) &params,
.is_err() &aggr_vk_all,
); &attributes,
assert!(aggregate_signatures( &signatures,
Some(&[])
)
.is_err());
assert!(aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_all, &aggr_vk_all,
&attributes, &attributes,
@@ -383,7 +413,7 @@ mod tests {
.unzip(); .unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap(); let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!(aggregate_signatures( assert!(aggregate_signatures_and_verify(
&params, &params,
&aggr_vk_all, &aggr_vk_all,
&attributes, &attributes,
+7 -4
View File
@@ -13,9 +13,8 @@ use crate::scheme::setup::Parameters;
use crate::scheme::BlindedSignature; use crate::scheme::BlindedSignature;
use crate::scheme::SecretKey; use crate::scheme::SecretKey;
use crate::Attribute; use crate::Attribute;
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
#[cfg(test)]
use crate::Signature; use crate::Signature;
// TODO: possibly completely remove those two functions. // TODO: possibly completely remove those two functions.
// They only exist to have a simpler and smaller code snippets to test // They only exist to have a simpler and smaller code snippets to test
// basic functionalities. // basic functionalities.
@@ -158,6 +157,10 @@ impl BlindSignRequest {
) )
} }
pub fn verify_commitment_hash(&self, public_attributes: &[&Attribute]) -> bool {
self.commitment_hash == compute_hash(self.commitment, public_attributes)
}
pub fn get_commitment_hash(&self) -> G1Projective { pub fn get_commitment_hash(&self) -> G1Projective {
self.commitment_hash self.commitment_hash
} }
@@ -426,9 +429,9 @@ pub fn verify_partial_blind_signature(
.into() .into()
} }
#[cfg(test)] /// Creates a Coconut Signature under a given secret key on a set of public attributes only.
pub fn sign( pub fn sign(
params: &mut Parameters, params: &Parameters,
secret_key: &SecretKey, secret_key: &SecretKey,
public_attributes: &[&Attribute], public_attributes: &[&Attribute],
) -> Result<Signature> { ) -> Result<Signature> {
+28 -8
View File
@@ -151,10 +151,6 @@ impl Base58 for SecretKey {}
// TODO: perhaps change points to affine representation // TODO: perhaps change points to affine representation
// to make verification slightly more efficient? // to make verification slightly more efficient?
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(
feature = "key-zeroize",
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
)]
pub struct VerificationKey { pub struct VerificationKey {
// TODO add gen2 as per the paper or imply it from the fact library is using bls381? // TODO add gen2 as per the paper or imply it from the fact library is using bls381?
pub(crate) alpha: G2Projective, pub(crate) alpha: G2Projective,
@@ -411,12 +407,23 @@ impl Bytable for VerificationKey {
impl Base58 for VerificationKey {} impl Base58 for VerificationKey {}
#[derive(Debug, Clone)]
pub struct VerificationKeyShare {
pub key: VerificationKey,
pub index: SignerIndex,
}
impl From<(VerificationKey, SignerIndex)> for VerificationKeyShare {
fn from(value: (VerificationKey, SignerIndex)) -> Self {
VerificationKeyShare {
key: value.0,
index: value.1,
}
}
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[cfg_attr(test, derive(PartialEq, Eq, Clone))] #[cfg_attr(test, derive(PartialEq, Eq, Clone))]
#[cfg_attr(
feature = "key-zeroize",
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
)]
pub struct KeyPair { pub struct KeyPair {
secret_key: SecretKey, secret_key: SecretKey,
verification_key: VerificationKey, verification_key: VerificationKey,
@@ -425,6 +432,12 @@ pub struct KeyPair {
pub index: Option<SignerIndex>, pub index: Option<SignerIndex>,
} }
impl From<KeyPair> for (SecretKey, VerificationKey) {
fn from(value: KeyPair) -> Self {
(value.secret_key, value.verification_key)
}
}
impl PemStorableKeyPair for KeyPair { impl PemStorableKeyPair for KeyPair {
type PrivatePemKey = SecretKey; type PrivatePemKey = SecretKey;
type PublicPemKey = VerificationKey; type PublicPemKey = VerificationKey;
@@ -461,6 +474,13 @@ impl KeyPair {
&self.verification_key &self.verification_key
} }
pub fn to_verification_key_share(&self) -> Option<VerificationKeyShare> {
self.index.map(|index| VerificationKeyShare {
key: self.verification_key.clone(),
index,
})
}
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
// Schema is coconutkeypair[14]|secret_key_len[8]|secret_key[secret_key_len]|verification_key_len[8]|verification_key[verification_key_len]|signer_index[8] - optional // Schema is coconutkeypair[14]|secret_key_len[8]|secret_key[secret_key_len]|verification_key_len[8]|verification_key[verification_key_len]|signer_index[8] - optional
self.to_byte_vec() self.to_byte_vec()
+31 -13
View File
@@ -70,6 +70,11 @@ impl Signature {
&self.1 &self.1
} }
pub fn randomise_simple(&self, params: &Parameters) -> Signature {
let r = params.random_scalar();
Signature(self.0 * r, self.1 * r)
}
pub fn randomise(&self, params: &Parameters) -> (Signature, Scalar) { pub fn randomise(&self, params: &Parameters) -> (Signature, Scalar) {
let r = params.random_scalar(); let r = params.random_scalar();
let r_prime = params.random_scalar(); let r_prime = params.random_scalar();
@@ -191,7 +196,7 @@ impl BlindedSignature {
&self, &self,
partial_verification_key: &VerificationKey, partial_verification_key: &VerificationKey,
pedersen_commitments_openings: &[Scalar], pedersen_commitments_openings: &[Scalar],
) -> Result<Signature> { ) -> Signature {
// parse the signature // parse the signature
let h = &self.0; let h = &self.0;
let c = &self.1; let c = &self.1;
@@ -204,7 +209,7 @@ impl BlindedSignature {
let unblinded_c = c - blinding_removers; let unblinded_c = c - blinding_removers;
Ok(Signature(*h, unblinded_c)) Signature(*h, unblinded_c)
} }
pub fn unblind_and_verify( pub fn unblind_and_verify(
@@ -216,7 +221,7 @@ impl BlindedSignature {
commitment_hash: &G1Projective, commitment_hash: &G1Projective,
pedersen_commitments_openings: &[Scalar], pedersen_commitments_openings: &[Scalar],
) -> Result<Signature> { ) -> Result<Signature> {
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?; let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings);
unblinded.verify( unblinded.verify(
params, params,
partial_verification_key, partial_verification_key,
@@ -240,6 +245,7 @@ impl BlindedSignature {
} }
// perhaps this should take signature by reference? we'll see how it goes // perhaps this should take signature by reference? we'll see how it goes
#[derive(Clone, Copy)]
pub struct SignatureShare { pub struct SignatureShare {
signature: Signature, signature: Signature,
index: SignerIndex, index: SignerIndex,
@@ -276,7 +282,9 @@ impl SignatureShare {
mod tests { mod tests {
use super::*; use super::*;
use crate::hash_to_scalar; use crate::hash_to_scalar;
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys}; use crate::scheme::aggregation::{
aggregate_signatures_and_verify, aggregate_verification_keys,
};
use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign}; use crate::scheme::issuance::{blind_sign, compute_hash, prepare_blind_sign, sign};
use crate::scheme::keygen::{keygen, ttp_keygen}; use crate::scheme::keygen::{keygen, ttp_keygen};
use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential}; use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential};
@@ -418,13 +426,13 @@ mod tests {
#[test] #[test]
fn verification_on_two_public_attributes() { fn verification_on_two_public_attributes() {
let mut params = Parameters::new(2).unwrap(); let params = Parameters::new(2).unwrap();
random_scalars_refs!(attributes, params, 2); random_scalars_refs!(attributes, params, 2);
let keypair1 = keygen(&params); let keypair1 = keygen(&params);
let keypair2 = keygen(&params); let keypair2 = keygen(&params);
let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap(); let sig1 = sign(&params, keypair1.secret_key(), &attributes).unwrap();
let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap(); let sig2 = sign(&params, keypair2.secret_key(), &attributes).unwrap();
assert!(verify( assert!(verify(
&params, &params,
@@ -568,9 +576,14 @@ mod tests {
attributes.extend_from_slice(&public_attributes); attributes.extend_from_slice(&public_attributes);
let aggr_vk = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap(); let aggr_vk = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
let aggr_sig = let aggr_sig = aggregate_signatures_and_verify(
aggregate_signatures(&params, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2])) &params,
.unwrap(); &aggr_vk,
&attributes,
&sigs[..2],
Some(&[1, 2]),
)
.unwrap();
let theta = prove_bandwidth_credential( let theta = prove_bandwidth_credential(
&params, &params,
@@ -590,9 +603,14 @@ mod tests {
// taking different subset of keys and credentials // taking different subset of keys and credentials
let aggr_vk = aggregate_verification_keys(&vks[1..], Some(&[2, 3])).unwrap(); let aggr_vk = aggregate_verification_keys(&vks[1..], Some(&[2, 3])).unwrap();
let aggr_sig = let aggr_sig = aggregate_signatures_and_verify(
aggregate_signatures(&params, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3])) &params,
.unwrap(); &aggr_vk,
&attributes,
&sigs[1..],
Some(&[2, 3]),
)
.unwrap();
let theta = prove_bandwidth_credential( let theta = prove_bandwidth_credential(
&params, &params,
+1
View File
@@ -10,6 +10,7 @@ use crate::error::{CoconutError, Result};
use crate::utils::hash_g1; use crate::utils::hash_g1;
/// System-wide parameters used for the protocol /// System-wide parameters used for the protocol
#[derive(Clone)]
pub struct Parameters { pub struct Parameters {
/// Generator of the G1 group /// Generator of the G1 group
g1: G1Affine, g1: G1Affine,
@@ -288,7 +288,6 @@ pub fn verify_credential(
} }
// Used in tests only // Used in tests only
#[cfg(test)]
pub fn verify( pub fn verify(
params: &Parameters, params: &Parameters,
verification_key: &VerificationKey, verification_key: &VerificationKey,
+6 -2
View File
@@ -75,8 +75,12 @@ pub fn theta_from_keys_and_attributes(
attributes.extend_from_slice(public_attributes); attributes.extend_from_slice(public_attributes);
// Randomize credentials and generate any cryptographic material to verify them // Randomize credentials and generate any cryptographic material to verify them
let signature = let signature = aggregate_signature_shares_and_verify(
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?; params,
&verification_key,
&attributes,
&signature_shares,
)?;
// Generate cryptographic material to verify them // Generate cryptographic material to verify them
let theta = prove_bandwidth_credential( let theta = prove_bandwidth_credential(
+4 -2
View File
@@ -16,7 +16,9 @@ const_format = "0.2.32"
cosmrs.workspace = true cosmrs.workspace = true
eyre = "0.6.9" eyre = "0.6.9"
futures.workspace = true futures.workspace = true
humantime = "2.1.0"
sha2 = "0.10.8" sha2 = "0.10.8"
serde = { workspace = true, features = ["derive"] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] } sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] }
tendermint.workspace = true tendermint.workspace = true
tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] } tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] }
@@ -24,13 +26,13 @@ thiserror.workspace = true
time = { workspace = true } time = { workspace = true }
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
tokio-stream = "0.1.14" tokio-stream = "0.1.14"
tokio-util = { version = "0.7.10", features = ["rt"]} tokio-util = { version = "0.7.10", features = ["rt"] }
tracing.workspace = true tracing.workspace = true
url.workspace = true url.workspace = true
# TEMP # TEMP
nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]} #nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
[build-dependencies] [build-dependencies]
+23
View File
@@ -0,0 +1,23 @@
# Nyxd Scraper
## Pruning
Similarly to cosmos-sdk, we incorporate pruning into our (scraped) chain data. We attempt to follow their strategies as
closely as possible for convenience's sake. Therefore, the following are available:
### Strategies
The strategies are configured in `config.toml`, with the format `pruning = "<strategy>"` where the options are:
* `default`: only the last 362,880 states(approximately 3.5 weeks worth of state) are kept; pruning at 10 block
intervals
* `nothing`: all historic states will be saved, nothing will be deleted (i.e. archiving node)
* `everything`: 2 latest states will be kept; pruning at 10 block intervals.
* `custom`: allow pruning options to be manually specified through `pruning.keep_recent`, and `pruning.interval`
### Custom Pruning
These are applied if and only if the pruning strategy is `custom`:
* `pruning.keep_recent`: N means to keep all of the last N blocks
* `pruning.interval`: N means to delete old block data from disk every Nth block.
+75 -2
View File
@@ -8,6 +8,7 @@ use crate::error::ScraperError;
use crate::modules::{BlockModule, MsgModule, TxModule}; use crate::modules::{BlockModule, MsgModule, TxModule};
use crate::rpc_client::RpcClient; use crate::rpc_client::RpcClient;
use crate::storage::{persist_block, ScraperStorage}; use crate::storage::{persist_block, ScraperStorage};
use crate::PruningOptions;
use futures::StreamExt; use futures::StreamExt;
use std::collections::{BTreeMap, HashSet, VecDeque}; use std::collections::{BTreeMap, HashSet, VecDeque};
use std::ops::{Add, Range}; use std::ops::{Add, Range};
@@ -18,9 +19,10 @@ use tokio::sync::Notify;
use tokio::time::{interval_at, Instant}; use tokio::time::{interval_at, Instant};
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, instrument, trace, warn};
mod helpers; mod helpers;
pub(crate) mod pruning;
pub(crate) mod types; pub(crate) mod types;
const MISSING_BLOCKS_CHECK_INTERVAL: Duration = Duration::from_secs(30); const MISSING_BLOCKS_CHECK_INTERVAL: Duration = Duration::from_secs(30);
@@ -40,9 +42,11 @@ impl PendingSync {
} }
pub struct BlockProcessor { pub struct BlockProcessor {
pruning_options: PruningOptions,
cancel: CancellationToken, cancel: CancellationToken,
synced: Arc<Notify>, synced: Arc<Notify>,
last_processed_height: u32, last_processed_height: u32,
last_pruned_height: u32,
last_processed_at: Instant, last_processed_at: Instant,
pending_sync: PendingSync, pending_sync: PendingSync,
queued_blocks: BTreeMap<u32, BlockToProcess>, queued_blocks: BTreeMap<u32, BlockToProcess>,
@@ -62,6 +66,7 @@ pub struct BlockProcessor {
impl BlockProcessor { impl BlockProcessor {
pub async fn new( pub async fn new(
pruning_options: PruningOptions,
cancel: CancellationToken, cancel: CancellationToken,
synced: Arc<Notify>, synced: Arc<Notify>,
incoming: UnboundedReceiver<BlockToProcess>, incoming: UnboundedReceiver<BlockToProcess>,
@@ -70,11 +75,17 @@ impl BlockProcessor {
rpc_client: RpcClient, rpc_client: RpcClient,
) -> Result<Self, ScraperError> { ) -> Result<Self, ScraperError> {
let last_processed = storage.get_last_processed_height().await?; let last_processed = storage.get_last_processed_height().await?;
let last_processed_height = last_processed.try_into().unwrap_or_default();
let last_pruned = storage.get_pruned_height().await?;
let last_pruned_height = last_pruned.try_into().unwrap_or_default();
Ok(BlockProcessor { Ok(BlockProcessor {
pruning_options,
cancel, cancel,
synced, synced,
last_processed_height: last_processed.try_into().unwrap_or_default(), last_processed_height,
last_pruned_height,
last_processed_at: Instant::now(), last_processed_at: Instant::now(),
pending_sync: Default::default(), pending_sync: Default::default(),
queued_blocks: Default::default(), queued_blocks: Default::default(),
@@ -131,12 +142,17 @@ impl BlockProcessor {
} }
} }
let commit_start = Instant::now();
tx.commit() tx.commit()
.await .await
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?; .map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
crate::storage::log_db_operation_time("committing processing tx", commit_start);
self.last_processed_height = full_info.block.header.height.value() as u32; self.last_processed_height = full_info.block.header.height.value() as u32;
self.last_processed_at = Instant::now(); self.last_processed_at = Instant::now();
if let Err(err) = self.maybe_prune_storage().await {
error!("failed to prune the storage: {err}");
}
Ok(()) Ok(())
} }
@@ -210,6 +226,61 @@ impl BlockProcessor {
Ok(()) Ok(())
} }
#[instrument(skip(self))]
async fn prune_storage(&mut self) -> Result<(), ScraperError> {
let keep_recent = self.pruning_options.strategy_keep_recent();
let last_to_keep = self.last_processed_height - keep_recent;
info!(
keep_recent,
oldest_to_keep = last_to_keep,
"pruning the storage"
);
let lowest: u32 = self
.storage
.lowest_block_height()
.await?
.unwrap_or_default()
.try_into()
.unwrap_or_default();
let to_prune = last_to_keep.saturating_sub(lowest);
match to_prune {
v if v > 1000 => warn!("approximately {v} blocks worth of data will be pruned"),
v if v > 100 => info!("approximately {v} blocks worth of data will be pruned"),
0 => trace!("no blocks to prune"),
v => debug!("approximately {v} blocks worth of data will be pruned"),
}
if to_prune == 0 {
return Ok(());
}
self.storage
.prune_storage(last_to_keep, self.last_processed_height)
.await?;
self.last_pruned_height = self.last_processed_height;
Ok(())
}
async fn maybe_prune_storage(&mut self) -> Result<(), ScraperError> {
debug!("checking for storage pruning");
if self.pruning_options.strategy.is_nothing() {
trace!("the current pruning strategy is 'nothing'");
return Ok(());
}
let interval = self.pruning_options.strategy_interval();
if self.last_pruned_height + interval <= self.last_processed_height {
self.prune_storage().await?;
}
Ok(())
}
async fn next_incoming(&mut self, block: BlockToProcess) { async fn next_incoming(&mut self, block: BlockToProcess) {
let height = block.height; let height = block.height;
@@ -279,6 +350,8 @@ impl BlockProcessor {
async fn startup_resync(&mut self) -> Result<(), ScraperError> { async fn startup_resync(&mut self) -> Result<(), ScraperError> {
assert!(self.pending_sync.is_empty()); assert!(self.pending_sync.is_empty());
self.maybe_prune_storage().await?;
let latest_block = self.rpc_client.current_block_height().await? as u32; let latest_block = self.rpc_client.current_block_height().await? as u32;
if latest_block > self.last_processed_height && self.last_processed_height != 0 { if latest_block > self.last_processed_height && self.last_processed_height != 0 {
let request_range = self.last_processed_height + 1..latest_block + 1; let request_range = self.last_processed_height + 1..latest_block + 1;
@@ -0,0 +1,122 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::ScraperError;
use serde::{Deserialize, Serialize};
pub const DEFAULT_PRUNING_KEEP_RECENT: u32 = 362880;
pub const DEFAULT_PRUNING_INTERVAL: u32 = 10;
pub const EVERYTHING_PRUNING_KEEP_RECENT: u32 = 2;
pub const EVERYTHING_PRUNING_INTERVAL: u32 = 10;
/// We follow cosmos-sdk pruning strategies for conveniences sake.
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PruningStrategy {
/// 'Default' strategy defines a pruning strategy where the last 362880 heights are
/// kept where to-be pruned heights are pruned at every 10th height.
/// The last 362880 heights are kept(approximately 3.5 weeks worth of state) assuming the typical
/// block time is 6s. If these values do not match the applications' requirements, use the "custom" option.
#[default]
Default,
/// 'Everything' strategy defines a pruning strategy where all committed heights are
/// deleted, storing only the current height and last 2 states. To-be pruned heights are
/// pruned at every 10th height.
Everything,
/// 'Nothing' strategy defines a pruning strategy where all heights are kept on disk.
Nothing,
/// 'Custom' strategy defines a pruning strategy where the user specifies the pruning.
Custom,
}
impl PruningStrategy {
pub fn is_custom(&self) -> bool {
matches!(self, PruningStrategy::Custom)
}
pub fn is_nothing(&self) -> bool {
matches!(self, PruningStrategy::Nothing)
}
pub fn is_everything(&self) -> bool {
matches!(self, PruningStrategy::Everything)
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct PruningOptions {
/// keep_recent defines how many recent heights to keep on disk.
pub keep_recent: u32,
/// interval defines the frequency of removing the pruned heights from the disk.
pub interval: u32,
/// strategy defines the currently used kind of [PruningStrategy].
pub strategy: PruningStrategy,
}
impl PruningOptions {
pub fn validate(&self) -> Result<(), ScraperError> {
// if strategy is not set to custom, other options are meaningless since they won't be applied
if !self.strategy.is_custom() {
return Ok(());
}
if self.interval == 0 {
return Err(ScraperError::ZeroPruningInterval);
}
if self.interval < EVERYTHING_PRUNING_INTERVAL {
return Err(ScraperError::TooSmallPruningInterval {
interval: self.interval,
});
}
if self.keep_recent < EVERYTHING_PRUNING_KEEP_RECENT {
return Err(ScraperError::TooSmallKeepRecent {
keep_recent: self.keep_recent,
});
}
Ok(())
}
pub fn nothing() -> Self {
PruningOptions {
keep_recent: 0,
interval: 0,
strategy: PruningStrategy::Nothing,
}
}
pub fn strategy_interval(&self) -> u32 {
match self.strategy {
PruningStrategy::Default => DEFAULT_PRUNING_INTERVAL,
PruningStrategy::Everything => EVERYTHING_PRUNING_INTERVAL,
PruningStrategy::Nothing => 0,
PruningStrategy::Custom => self.interval,
}
}
pub fn strategy_keep_recent(&self) -> u32 {
match self.strategy {
PruningStrategy::Default => DEFAULT_PRUNING_KEEP_RECENT,
PruningStrategy::Everything => EVERYTHING_PRUNING_KEEP_RECENT,
PruningStrategy::Nothing => 0,
PruningStrategy::Custom => self.keep_recent,
}
}
}
impl Default for PruningOptions {
fn default() -> Self {
PruningOptions {
keep_recent: DEFAULT_PRUNING_KEEP_RECENT,
interval: DEFAULT_PRUNING_INTERVAL,
strategy: Default::default(),
}
}
}
+12
View File
@@ -1,6 +1,9 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::block_processor::pruning::{
EVERYTHING_PRUNING_INTERVAL, EVERYTHING_PRUNING_KEEP_RECENT,
};
use tendermint::Hash; use tendermint::Hash;
use thiserror::Error; use thiserror::Error;
use tokio::sync::mpsc::error::SendError; use tokio::sync::mpsc::error::SendError;
@@ -122,6 +125,15 @@ pub enum ScraperError {
"could not find validator information for {address}; the validator has signed a commit" "could not find validator information for {address}; the validator has signed a commit"
)] )]
MissingValidatorInfoCommitted { address: String }, MissingValidatorInfoCommitted { address: String },
#[error("pruning.interval must not be set to 0. If you want to disable pruning, select pruning.strategy = \"nothing\"")]
ZeroPruningInterval,
#[error("pruning.interval must not be smaller than {}. got: {interval}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_INTERVAL)]
TooSmallPruningInterval { interval: u32 },
#[error("pruning.keep_recent must not be smaller than {}. got: {keep_recent}. for most aggressive pruning, select pruning.strategy = \"everything\"", EVERYTHING_PRUNING_KEEP_RECENT)]
TooSmallKeepRecent { keep_recent: u32 },
} }
impl<T> From<SendError<T>> for ScraperError { impl<T> From<SendError<T>> for ScraperError {
+1
View File
@@ -14,6 +14,7 @@ pub(crate) mod rpc_client;
pub(crate) mod scraper; pub(crate) mod scraper;
pub mod storage; pub mod storage;
pub use block_processor::pruning::{PruningOptions, PruningStrategy};
pub use modules::{BlockModule, MsgModule, TxModule}; pub use modules::{BlockModule, MsgModule, TxModule};
pub use scraper::{Config, NyxdScraper}; pub use scraper::{Config, NyxdScraper};
pub use storage::models; pub use storage::models;
+6
View File
@@ -8,6 +8,7 @@ use crate::modules::{BlockModule, MsgModule, TxModule};
use crate::rpc_client::RpcClient; use crate::rpc_client::RpcClient;
use crate::scraper::subscriber::ChainSubscriber; use crate::scraper::subscriber::ChainSubscriber;
use crate::storage::ScraperStorage; use crate::storage::ScraperStorage;
use crate::PruningOptions;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::{channel, unbounded_channel}; use tokio::sync::mpsc::{channel, unbounded_channel};
@@ -27,6 +28,8 @@ pub struct Config {
pub rpc_url: Url, pub rpc_url: Url,
pub database_path: PathBuf, pub database_path: PathBuf,
pub pruning_options: PruningOptions,
} }
pub struct NyxdScraperBuilder { pub struct NyxdScraperBuilder {
@@ -54,6 +57,7 @@ impl NyxdScraperBuilder {
processing_tx.clone(), processing_tx.clone(),
); );
let mut block_processor = BlockProcessor::new( let mut block_processor = BlockProcessor::new(
scraper.config.pruning_options,
scraper.cancel_token.clone(), scraper.cancel_token.clone(),
scraper.startup_sync.clone(), scraper.startup_sync.clone(),
processing_rx, processing_rx,
@@ -119,6 +123,7 @@ impl NyxdScraper {
} }
pub async fn new(config: Config) -> Result<Self, ScraperError> { pub async fn new(config: Config) -> Result<Self, ScraperError> {
config.pruning_options.validate()?;
let storage = ScraperStorage::init(&config.database_path).await?; let storage = ScraperStorage::init(&config.database_path).await?;
Ok(NyxdScraper { Ok(NyxdScraper {
@@ -160,6 +165,7 @@ impl NyxdScraper {
processing_tx.clone(), processing_tx.clone(),
); );
let block_processor = BlockProcessor::new( let block_processor = BlockProcessor::new(
self.config.pruning_options,
self.cancel_token.clone(), self.cancel_token.clone(),
self.startup_sync.clone(), self.startup_sync.clone(),
processing_rx, processing_rx,
+191 -11
View File
@@ -1,9 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::storage::log_db_operation_time;
use crate::storage::models::{CommitSignature, Validator}; use crate::storage::models::{CommitSignature, Validator};
use sqlx::types::time::OffsetDateTime; use sqlx::types::time::OffsetDateTime;
use sqlx::{Executor, Sqlite}; use sqlx::{Executor, Sqlite};
use tokio::time::Instant;
use tracing::{instrument, trace}; use tracing::{instrument, trace};
#[derive(Clone)] #[derive(Clone)]
@@ -25,10 +27,36 @@ impl StorageManager {
Ok(()) Ok(())
} }
pub(crate) async fn get_lowest_block(&self) -> Result<Option<i64>, sqlx::Error> {
trace!("get_lowest_block");
let start = Instant::now();
let maybe_record = sqlx::query!(
r#"
SELECT height
FROM block
ORDER BY height ASC
LIMIT 1
"#,
)
.fetch_optional(&self.connection_pool)
.await?;
log_db_operation_time("get_lowest_block", start);
if let Some(row) = maybe_record {
Ok(row.height)
} else {
Ok(None)
}
}
pub(crate) async fn get_first_block_height_after( pub(crate) async fn get_first_block_height_after(
&self, &self,
time: OffsetDateTime, time: OffsetDateTime,
) -> Result<Option<i64>, sqlx::Error> { ) -> Result<Option<i64>, sqlx::Error> {
trace!("get_first_block_height_after");
let start = Instant::now();
let maybe_record = sqlx::query!( let maybe_record = sqlx::query!(
r#" r#"
SELECT height SELECT height
@@ -41,6 +69,7 @@ impl StorageManager {
) )
.fetch_optional(&self.connection_pool) .fetch_optional(&self.connection_pool)
.await?; .await?;
log_db_operation_time("get_first_block_height_after", start);
if let Some(row) = maybe_record { if let Some(row) = maybe_record {
Ok(row.height) Ok(row.height)
@@ -53,6 +82,9 @@ impl StorageManager {
&self, &self,
time: OffsetDateTime, time: OffsetDateTime,
) -> Result<Option<i64>, sqlx::Error> { ) -> Result<Option<i64>, sqlx::Error> {
trace!("get_last_block_height_before");
let start = Instant::now();
let maybe_record = sqlx::query!( let maybe_record = sqlx::query!(
r#" r#"
SELECT height SELECT height
@@ -65,6 +97,7 @@ impl StorageManager {
) )
.fetch_optional(&self.connection_pool) .fetch_optional(&self.connection_pool)
.await?; .await?;
log_db_operation_time("get_last_block_height_before", start);
if let Some(row) = maybe_record { if let Some(row) = maybe_record {
Ok(row.height) Ok(row.height)
@@ -79,6 +112,9 @@ impl StorageManager {
start_height: i64, start_height: i64,
end_height: i64, end_height: i64,
) -> Result<i32, sqlx::Error> { ) -> Result<i32, sqlx::Error> {
trace!("get_signed_between");
let start = Instant::now();
let count = sqlx::query!( let count = sqlx::query!(
r#" r#"
SELECT COUNT(*) as count FROM pre_commit SELECT COUNT(*) as count FROM pre_commit
@@ -94,6 +130,7 @@ impl StorageManager {
.fetch_one(&self.connection_pool) .fetch_one(&self.connection_pool)
.await? .await?
.count; .count;
log_db_operation_time("get_signed_between", start);
Ok(count) Ok(count)
} }
@@ -103,7 +140,10 @@ impl StorageManager {
consensus_address: &str, consensus_address: &str,
height: i64, height: i64,
) -> Result<Option<CommitSignature>, sqlx::Error> { ) -> Result<Option<CommitSignature>, sqlx::Error> {
sqlx::query_as( trace!("get_precommit");
let start = Instant::now();
let res = sqlx::query_as(
r#" r#"
SELECT * FROM pre_commit SELECT * FROM pre_commit
WHERE validator_address = ? WHERE validator_address = ?
@@ -113,14 +153,20 @@ impl StorageManager {
.bind(consensus_address) .bind(consensus_address)
.bind(height) .bind(height)
.fetch_optional(&self.connection_pool) .fetch_optional(&self.connection_pool)
.await .await?;
log_db_operation_time("get_precommit", start);
Ok(res)
} }
pub(crate) async fn get_block_validators( pub(crate) async fn get_block_validators(
&self, &self,
height: i64, height: i64,
) -> Result<Vec<Validator>, sqlx::Error> { ) -> Result<Vec<Validator>, sqlx::Error> {
sqlx::query_as!( trace!("get_block_validators");
let start = Instant::now();
let res = sqlx::query_as!(
Validator, Validator,
r#" r#"
SELECT * FROM validator SELECT * FROM validator
@@ -133,16 +179,28 @@ impl StorageManager {
height height
) )
.fetch_all(&self.connection_pool) .fetch_all(&self.connection_pool)
.await .await?;
log_db_operation_time("get_block_validators", start);
Ok(res)
} }
pub(crate) async fn get_validators(&self) -> Result<Vec<Validator>, sqlx::Error> { pub(crate) async fn get_validators(&self) -> Result<Vec<Validator>, sqlx::Error> {
sqlx::query_as("SELECT * FROM validator") trace!("get_validators");
let start = Instant::now();
let res = sqlx::query_as("SELECT * FROM validator")
.fetch_all(&self.connection_pool) .fetch_all(&self.connection_pool)
.await .await?;
log_db_operation_time("get_validators", start);
Ok(res)
} }
pub(crate) async fn get_last_processed_height(&self) -> Result<i64, sqlx::Error> { pub(crate) async fn get_last_processed_height(&self) -> Result<i64, sqlx::Error> {
trace!("get_last_processed_height");
let start = Instant::now();
let maybe_record = sqlx::query!( let maybe_record = sqlx::query!(
r#" r#"
SELECT last_processed_height FROM metadata SELECT last_processed_height FROM metadata
@@ -150,6 +208,7 @@ impl StorageManager {
) )
.fetch_optional(&self.connection_pool) .fetch_optional(&self.connection_pool)
.await?; .await?;
log_db_operation_time("get_last_processed_height", start);
if let Some(row) = maybe_record { if let Some(row) = maybe_record {
Ok(row.last_processed_height) Ok(row.last_processed_height)
@@ -157,6 +216,27 @@ impl StorageManager {
Ok(-1) Ok(-1)
} }
} }
pub(crate) async fn get_pruned_height(&self) -> Result<i64, sqlx::Error> {
trace!("get_pruned_height");
let start = Instant::now();
let maybe_record = sqlx::query!(
r#"
SELECT last_pruned_height FROM pruning
"#
)
.fetch_optional(&self.connection_pool)
.await?;
log_db_operation_time("get_pruned_height", start);
if let Some(row) = maybe_record {
Ok(row.last_pruned_height)
} else {
Ok(-1)
}
}
} }
// make those generic over executor so that they could be performed over connection pool and a tx // make those generic over executor so that they could be performed over connection pool and a tx
@@ -170,7 +250,8 @@ pub(crate) async fn insert_validator<'a, E>(
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("insert validator"); trace!("insert_validator");
let start = Instant::now();
sqlx::query!( sqlx::query!(
r#" r#"
@@ -183,6 +264,7 @@ where
) )
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("insert_validator", start);
Ok(()) Ok(())
} }
@@ -200,7 +282,8 @@ pub(crate) async fn insert_block<'a, E>(
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("insert block"); trace!("insert_block");
let start = Instant::now();
sqlx::query!( sqlx::query!(
r#" r#"
@@ -217,6 +300,7 @@ where
) )
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("insert_block", start);
Ok(()) Ok(())
} }
@@ -233,7 +317,8 @@ pub(crate) async fn insert_precommit<'a, E>(
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("insert precommit"); trace!("insert_precommit");
let start = Instant::now();
sqlx::query!( sqlx::query!(
r#" r#"
@@ -249,6 +334,7 @@ where
) )
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("insert_precommit", start);
Ok(()) Ok(())
} }
@@ -270,7 +356,8 @@ pub(crate) async fn insert_transaction<'a, E>(
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("insert transaction"); trace!("insert_transaction");
let start = Instant::now();
sqlx::query!( sqlx::query!(
r#" r#"
@@ -298,6 +385,7 @@ where
) )
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("insert_transaction", start);
Ok(()) Ok(())
} }
@@ -313,7 +401,8 @@ pub(crate) async fn insert_message<'a, E>(
where where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("insert message"); trace!("insert_message");
let start = Instant::now();
sqlx::query!( sqlx::query!(
r#" r#"
@@ -330,6 +419,7 @@ where
) )
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("insert_message", start);
Ok(()) Ok(())
} }
@@ -343,10 +433,100 @@ where
E: Executor<'a, Database = Sqlite>, E: Executor<'a, Database = Sqlite>,
{ {
trace!("update_last_processed"); trace!("update_last_processed");
let start = Instant::now();
sqlx::query!("UPDATE metadata SET last_processed_height = ?", height) sqlx::query!("UPDATE metadata SET last_processed_height = ?", height)
.execute(executor) .execute(executor)
.await?; .await?;
log_db_operation_time("update_last_processed", start);
Ok(())
}
#[instrument(skip(executor))]
pub(crate) async fn update_last_pruned<'a, E>(height: i64, executor: E) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = Sqlite>,
{
trace!("update_last_pruned");
let start = Instant::now();
sqlx::query!("UPDATE pruning SET last_pruned_height = ?", height)
.execute(executor)
.await?;
log_db_operation_time("update_last_pruned", start);
Ok(())
}
pub(crate) async fn prune_blocks<'a, E>(oldest_to_keep: i64, executor: E) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = Sqlite>,
{
trace!("prune_blocks");
let start = Instant::now();
sqlx::query!("DELETE FROM block WHERE height < ?", oldest_to_keep)
.execute(executor)
.await?;
log_db_operation_time("prune_blocks", start);
Ok(())
}
pub(crate) async fn prune_pre_commits<'a, E>(
oldest_to_keep: i64,
executor: E,
) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = Sqlite>,
{
trace!("prune_pre_commits");
let start = Instant::now();
sqlx::query!("DELETE FROM pre_commit WHERE height < ?", oldest_to_keep)
.execute(executor)
.await?;
log_db_operation_time("prune_pre_commits", start);
Ok(())
}
pub(crate) async fn prune_transactions<'a, E>(
oldest_to_keep: i64,
executor: E,
) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = Sqlite>,
{
trace!("prune_transactions");
let start = Instant::now();
sqlx::query!(
"DELETE FROM \"transaction\" WHERE height < ?",
oldest_to_keep
)
.execute(executor)
.await?;
log_db_operation_time("prune_transactions", start);
Ok(())
}
pub(crate) async fn prune_messages<'a, E>(
oldest_to_keep: i64,
executor: E,
) -> Result<(), sqlx::Error>
where
E: Executor<'a, Database = Sqlite>,
{
trace!("prune_messages");
let start = Instant::now();
sqlx::query!("DELETE FROM message WHERE height < ?", oldest_to_keep)
.execute(executor)
.await?;
log_db_operation_time("prune_messages", start);
Ok(()) Ok(())
} }
+50 -1
View File
@@ -5,7 +5,8 @@ use crate::block_processor::types::{FullBlockInformation, ParsedTransactionRespo
use crate::error::ScraperError; use crate::error::ScraperError;
use crate::storage::manager::{ use crate::storage::manager::{
insert_block, insert_message, insert_precommit, insert_transaction, insert_validator, insert_block, insert_message, insert_precommit, insert_transaction, insert_validator,
update_last_processed, StorageManager, prune_blocks, prune_messages, prune_pre_commits, prune_transactions, update_last_processed,
update_last_pruned, StorageManager,
}; };
use crate::storage::models::{CommitSignature, Validator}; use crate::storage::models::{CommitSignature, Validator};
use sqlx::types::time::OffsetDateTime; use sqlx::types::time::OffsetDateTime;
@@ -15,6 +16,7 @@ use std::path::Path;
use tendermint::block::{Commit, CommitSig}; use tendermint::block::{Commit, CommitSig};
use tendermint::Block; use tendermint::Block;
use tendermint_rpc::endpoint::validators; use tendermint_rpc::endpoint::validators;
use tokio::time::Instant;
use tracing::{debug, error, info, instrument, trace, warn}; use tracing::{debug, error, info, instrument, trace, warn};
mod helpers; mod helpers;
@@ -28,6 +30,19 @@ pub struct ScraperStorage {
pub(crate) manager: StorageManager, pub(crate) manager: StorageManager,
} }
pub(crate) fn log_db_operation_time(op_name: &str, start_time: Instant) {
let elapsed = start_time.elapsed();
let formatted = humantime::format_duration(elapsed);
match elapsed.as_millis() {
v if v > 10000 => error!("{op_name} took {formatted} to execute"),
v if v > 1000 => warn!("{op_name} took {formatted} to execute"),
v if v > 100 => info!("{op_name} took {formatted} to execute"),
v if v > 10 => debug!("{op_name} took {formatted} to execute"),
_ => trace!("{op_name} took {formatted} to execute"),
}
}
impl ScraperStorage { impl ScraperStorage {
#[instrument] #[instrument]
pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> { pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> {
@@ -65,6 +80,32 @@ impl ScraperStorage {
Ok(storage) Ok(storage)
} }
#[instrument(skip(self))]
pub async fn prune_storage(
&self,
oldest_to_keep: u32,
current_height: u32,
) -> Result<(), ScraperError> {
let start = Instant::now();
let mut tx = self.begin_processing_tx().await?;
prune_messages(oldest_to_keep.into(), &mut tx).await?;
prune_transactions(oldest_to_keep.into(), &mut tx).await?;
prune_pre_commits(oldest_to_keep.into(), &mut tx).await?;
prune_blocks(oldest_to_keep.into(), &mut tx).await?;
update_last_pruned(current_height.into(), &mut tx).await?;
let commit_start = Instant::now();
tx.commit()
.await
.map_err(|source| ScraperError::StorageTxCommitFailure { source })?;
log_db_operation_time("committing pruning tx", commit_start);
log_db_operation_time("pruning storage", start);
Ok(())
}
#[instrument(skip_all)] #[instrument(skip_all)]
pub async fn begin_processing_tx(&self) -> Result<StorageTransaction, ScraperError> { pub async fn begin_processing_tx(&self) -> Result<StorageTransaction, ScraperError> {
debug!("starting storage tx"); debug!("starting storage tx");
@@ -75,6 +116,10 @@ impl ScraperStorage {
.map_err(|source| ScraperError::StorageTxBeginFailure { source }) .map_err(|source| ScraperError::StorageTxBeginFailure { source })
} }
pub async fn lowest_block_height(&self) -> Result<Option<i64>, ScraperError> {
Ok(self.manager.get_lowest_block().await?)
}
pub async fn get_first_block_height_after( pub async fn get_first_block_height_after(
&self, &self,
time: OffsetDateTime, time: OffsetDateTime,
@@ -155,6 +200,10 @@ impl ScraperStorage {
pub async fn get_last_processed_height(&self) -> Result<i64, ScraperError> { pub async fn get_last_processed_height(&self) -> Result<i64, ScraperError> {
Ok(self.manager.get_last_processed_height().await?) Ok(self.manager.get_last_processed_height().await?)
} }
pub async fn get_pruned_height(&self) -> Result<i64, ScraperError> {
Ok(self.manager.get_pruned_height().await?)
}
} }
pub async fn persist_block( pub async fn persist_block(
+1 -1
View File
@@ -159,7 +159,7 @@ impl TunDevice {
"add", "add",
&format!("{}/{}", ipv6, netmaskv6), &format!("{}/{}", ipv6, netmaskv6),
"dev", "dev",
&tun.name(), (tun.name()),
]) ])
.output()?; .output()?;
Ok(tun) Ok(tun)
+3 -1
View File
@@ -50,7 +50,7 @@ pub struct DelegationWithEverything {
pub accumulated_by_delegates: Option<DecCoin>, pub accumulated_by_delegates: Option<DecCoin>,
pub accumulated_by_operator: Option<DecCoin>, pub accumulated_by_operator: Option<DecCoin>,
pub block_height: u64, pub block_height: u64,
pub delegated_on_iso_datetime: String, pub delegated_on_iso_datetime: Option<String>,
pub cost_params: Option<MixNodeCostParams>, pub cost_params: Option<MixNodeCostParams>,
pub avg_uptime_percent: Option<u8>, pub avg_uptime_percent: Option<u8>,
@@ -60,6 +60,8 @@ pub struct DelegationWithEverything {
pub uses_vesting_contract_tokens: bool, pub uses_vesting_contract_tokens: bool,
pub unclaimed_rewards: Option<DecCoin>, pub unclaimed_rewards: Option<DecCoin>,
pub errors: Option<String>,
// DEPRECATED, IF POSSIBLE TRY TO DISCONTINUE USE OF IT! // DEPRECATED, IF POSSIBLE TRY TO DISCONTINUE USE OF IT!
pub pending_events: Vec<DelegationEvent>, pub pending_events: Vec<DelegationEvent>,
pub mixnode_is_unbonding: Option<bool>, pub mixnode_is_unbonding: Option<bool>,
+12
View File
@@ -2,6 +2,18 @@
This page displays a full list of all the changes during our release cycle from [`v2024.3-eclipse`](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md) onwards. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first. This page displays a full list of all the changes during our release cycle from [`v2024.3-eclipse`](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md) onwards. Operators can find here the newest updates together with links to relevant documentation. The list is sorted so that the newest changes appear first.
## `v2024.4-nutella`
- [Merged PRs](https://github.com/nymtech/nym/milestone/59?closed=1)
- [`nym-node`](nodes/nym-node.md) version `1.1.1`
- This release also contains: `nym-gateway` and `nym-network-requester` binaries
- core improvements on nym-node configuration
- Nym wallet changes:
- Adding `nym-node` command to bonding screens
- Fixed the delegation issues with fixing RPC
- [Network configuration](nodes/configuration.md#connectivity-test-and-configuration) section updates, in particular for `--mode mixnode` operators
- [VPS IPv6 troubleshooting](troubleshooting/vps-isp.md#ipv6-troubleshooting) updates
## `v2024.3-eclipse` ## `v2024.3-eclipse`
- Release [Changelog.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md) - Release [Changelog.md](https://github.com/nymtech/nym/blob/nym-binaries-v2024.3-eclipse/CHANGELOG.md)
@@ -161,15 +161,49 @@ This lets your operating system know it's ok to reload the service configuration
## Connectivity Test and Configuration ## Connectivity Test and Configuration
```admonish info
**This chapter is relevant only for operators running an `exit-gateway` mode.** If this is not your case, please proceed to [bonding](bonding.md).
```
During our ongoing testing events [Fast and Furious](https://nymtech.net/events/fast-and-furious) we found out, that after introducing IP Packet Router (IPR) and [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) on embedded Network Requester (NR) by default, only a fragment of Gateways routes correctly through IPv4 and IPv6. We built a useful monitor to check out your Gateway (`nym-node --mode exit-gateway`) at [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/). During our ongoing testing events [Fast and Furious](https://nymtech.net/events/fast-and-furious) we found out, that after introducing IP Packet Router (IPR) and [Nym exit policy](https://nymtech.net/.wellknown/network-requester/exit-policy.txt) on embedded Network Requester (NR) by default, only a fragment of Gateways routes correctly through IPv4 and IPv6. We built a useful monitor to check out your Gateway (`nym-node --mode exit-gateway`) at [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net/).
IPv6 routing is not only a case for gateways. Imagine a rare occassion when you run a `mixnode` without IPv6 enabled and a client will sent IPv6 packets through the Mixnet through such route:
```ascii
[client] -> [entry-gateway] -> [mixnode layer 1] -> [your mixnode] -> [IPv6 mixnode layer3] -> [exit-gateway]
```
In this (unusual) case your `mixnode` will not be able to route the packets. The node will drop the packets and its performance would go down. For that reason it's befetial to have IPv6 enabled when running a `mixnode` functionality.
### Quick IPv6 Check
```admonish caution
Make sure to keep your IPv4 address enabled while setting up IPv6, as the majority of routing goes through that one!
```
You can always check IPv6 address and connectivity by using some of these methods:
```sh
# locally listed IPv6 addresses
ip -6 addr
# globally reachable IPv6 addresses
ip -6 addr show scope global
# with DNS
dig -6 TXT +short o-o.myaddr.l.google.com @ns1.google.com
dig -t aaaa +short myip.opendns.com @resolver1.opendns.com
# https check
curl -6 https://ifconfig.co
curl -6 https://ipv6.icanhazip.com
# using telnet
telnet -6 ipv6.telnetmyip.com
```
### IPv6 Configuration
While we're working on Rust implementation to have these settings as a part of the binary build, we wrote a script to solve these connectivity requirements in the meantime we wrote a script [`network_tunnel_manager.sh`](https://gist.github.com/tommyv1987/ccf6ca00ffb3d7e13192edda61bb2a77) to support the operators to configure their servers and address all the connectivity requirements. While we're working on Rust implementation to have these settings as a part of the binary build, we wrote a script to solve these connectivity requirements in the meantime we wrote a script [`network_tunnel_manager.sh`](https://gist.github.com/tommyv1987/ccf6ca00ffb3d7e13192edda61bb2a77) to support the operators to configure their servers and address all the connectivity requirements.
Networking configuration across different ISPs and various operation systems does not have a generic solution. If the provided configuration setup doesn't solve your problem check out [IPv6 troubleshooting](../troubleshooting/vps-isp.md#ipv6-troubleshooting) page. Be aware that you may have to do more research and customised adjustments.
#### Mode: `exit-gateway`
The `nymtun0` interface is dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated. The `nymtun0` interface is dynamically managed by the `exit-gateway` service. When the service is stopped, `nymtun0` disappears, and when started, `nymtun0` is recreated.
The script should be used in a context where `nym-node --mode exit-gateway` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` interface. The script should be used in a context where `nym-node --mode exit-gateway` is running to fully utilise its capabilities, particularly for fetching IPv6 addresses or applying network rules that depend on the `nymtun0` interface.
@@ -265,11 +299,11 @@ operation fetch_ipv6_address_nym_tun completed successfully.
sudo ./network_tunnel_manager.sh apply_iptables_rules sudo ./network_tunnel_manager.sh apply_iptables_rules
``` ```
- The process may prompt you if you want to save current IPv4 rules, choose yes. - The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes.
![](../images/ip_table_prompt.png) ![](../images/ip_table_prompt.png)
- and check them again like in point 3 - check IPv6 again like in point 3
6. At this point your node needs to be [bonded](bonding.md) to the API for `nymtun0` to interact with the network. After bonding please follow up with the remaining streps below to ensure that your Exit Gateway is routing properly. 6. At this point your node needs to be [bonded](bonding.md) to the API for `nymtun0` to interact with the network. After bonding please follow up with the remaining streps below to ensure that your Exit Gateway is routing properly.
@@ -298,6 +332,75 @@ sudo ./network_tunnel_manager.sh joke_through_the_mixnet
Make sure that you get the validation of IPv4 and IPv6 connectivity. If there are still any problems, please refer to [troubleshooting section](../troubleshooting/vps-isp.md#incorrect-gateway-network-check). Make sure that you get the validation of IPv4 and IPv6 connectivity. If there are still any problems, please refer to [troubleshooting section](../troubleshooting/vps-isp.md#incorrect-gateway-network-check).
#### Mode: `mixnode`
```admonish caution title=""
Most of the time the packets sent through the Mixnet are IPv4 based. The IPv6 packets are still pretty rare and therefore it's not mandatory from operational point of view. If you preparing to run a `nym-node` with all modes enabled once this option is implemented, then the IPv6 setup on your VPS is required.
```
1. Download `network_tunnel_manager.sh`, make executable and run:
```sh
curl -o network_tunnel_manager.sh -L https://gist.githubusercontent.com/tommyv1987/ccf6ca00ffb3d7e13192edda61bb2a77/raw/9d785d6ee3aa2970553633eccbd89a827f49fab5/network_tunnel_manager.sh && chmod +x network_tunnel_manager.sh && ./network_tunnel_manager.sh
```
Here is a quick command explanation, for more details on the `network_tunnel_manager.sh` script, refer to the [overview](https://gist.github.com/tommyv1987/ccf6ca00ffb3d7e13192edda61bb2a77) under the code block. Mind that for `mixnode` VPS setup we will use only a few of the commands.
~~~admonish example collapsible=true title="A summarized usage of `network_tunnel_manager.sh`"
```sh
summary:
This is a comprehensive script for configuring network packet forwarding and iptables rules,
aimed at ensuring smooth operation of a tunnel interface.
It includes functionality for both setup and tear-down of nymtun network configurations,
alongside diagnostics for verifying system settings and network connectivity.
* fetch_ipv6_address_nym_tun - Fetches the IPv6 address assigned to the 'nymtun0'.
* fetch_and_display_ipv6 - Displays the IPv6 address on the default network device.
* apply_iptables_rules - Applies necessary IPv4 and IPv6 iptables rules.
* remove_iptables_rules - Removes applied IPv4 and IPv6 iptables rules.
* check_ipv6_ipv4_forwarding - Checks if IPv4 and IPv6 forwarding are enabled.
* check_nymtun_iptables - Check nymtun0 device
* perform_ipv4_ipv6_pings - Perform ipv4 and ipv6 pings to google
* check_ip6_ipv4_routing - Check ipv6 and ipv4 routing
* joke_through_the_mixnet - Run a joke through the mixnet via ipv4 and ipv6
```
~~~
- To run the script next time, just enter `./network_tunnel_manager <ARG>`
2. Display IPv6:
```sh
sudo ./network_tunnel_manager.sh fetch_and_display_ipv6
```
- if you have a `global ipv6` address this is good
~~~admonish example collapsible=true title="Correct `./network_tunnel_manager.sh fetch_and_display_ipv6` output:"
```sh
iptables-persistent is already installed.
Using IPv6 address: 2001:db8:a160::1/112 #the address will be different for you
operation fetch_ipv6_address_nym_tun completed successfully.
```
~~~
3. Apply the rules:
```sh
sudo ./network_tunnel_manager.sh apply_iptables_rules
```
- The process may prompt you if you want to save current IPv4 and IPv6 rules, choose yes.
![](../images/ip_table_prompt.png)
- check IPv6 again like in point 2
4. Check connectivity
```sh
telnet -6 ipv6.telnetmyip.com
```
Make sure that you get the validation of IPv4 and IPv6 connectivity. If there are still any problems, please refer to [troubleshooting section](../troubleshooting/vps-isp.md#incorrect-gateway-network-check).
## Next Steps ## Next Steps
There are a few more good suggestions for `nym-node` VPS configuration, especially to be considered for `exit-gateway` functionality, like Web Secure Socket or Reversed Proxy setup. Visit [Proxy configuration](proxy-configuration.md) page to see the guides. There are a few more good suggestions for `nym-node` VPS configuration, especially to be considered for `exit-gateway` functionality, like Web Secure Socket or Reversed Proxy setup. Visit [Proxy configuration](proxy-configuration.md) page to see the guides.
+24 -8
View File
@@ -58,6 +58,22 @@ To install a full node from scratch, refer to the [validator setup guide](valida
Before node or validator setup, the VPS needs to be configured and tested, to verify your connectivity and make sure that your provider wasn't dishonest with the offered services. Before node or validator setup, the VPS needs to be configured and tested, to verify your connectivity and make sure that your provider wasn't dishonest with the offered services.
### Install Dependencies
SSH to your server as `root` or become one running `sudo -i` or `su`. If you prefer to administrate your VPS from a user environment, supply the commands with prefix `sudo`.
Start with setting up the essential tools on your server.
```sh
# get your system up to date
apt update -y && apt --fix-broken install
# install dependencies
apt -y install ca-certificates jq curl wget ufw jq tmux pkg-config build-essential libssl-dev git
# double check ufw is installed correctly
apt install ufw --fix-missing
```
### Configure your Firewall ### Configure your Firewall
For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server. The following commands will allow you to set up a firewall using `ufw`. For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on the server. The following commands will allow you to set up a firewall using `ufw`.
@@ -68,33 +84,33 @@ For a `nym-node` or Nyx validator to recieve traffic, you need to open ports on
ufw version ufw version
# if it is not installed, install with # if it is not installed, install with
sudo apt install ufw -y apt install ufw -y
# enable ufw # enable ufw
sudo ufw enable ufw enable
# check the status of the firewall # check the status of the firewall
sudo ufw status ufw status
``` ```
2. Open all needed ports to have your firewall working correctly: 2. Open all needed ports to have your firewall working correctly:
```sh ```sh
# for nym-node # for nym-node
sudo ufw allow 1789,1790,8000,9000,9001,22/tcp ufw allow 1789,1790,8000,9000,9001,22/tcp
# in case of planning to setup a WSS (for Gateway functionality) # in case of planning to setup a WSS (for Gateway functionality)
sudo ufw allow 9001/tcp ufw allow 9001/tcp
# in case of reverse proxy for the swagger page (for Gateway optionality) # in case of reverse proxy for the swagger page (for Gateway optionality)
sudo ufw allow 8080,80,443 ufw allow 8080,80,443
# for validator # for validator
sudo ufw allow 1317,26656,26660,22,80,443/tcp ufw allow 1317,26656,26660,22,80,443/tcp
``` ```
3. Check the status of the firewall: 3. Check the status of the firewall:
```sh ```sh
sudo ufw status ufw status
``` ```
For more information about your node's port configuration, check the [port reference table](#ports-reference-table) below. For more information about your node's port configuration, check the [port reference table](#ports-reference-table) below.
@@ -191,14 +191,38 @@ If you are still unable to see your node on the dashboard, or your node is decla
- The firewall on your host machine is not configured properly. Checkout the [instructions](../nodes/vps-setup.md#configure-your-firewall). - The firewall on your host machine is not configured properly. Checkout the [instructions](../nodes/vps-setup.md#configure-your-firewall).
- You provided incorrect information when bonding your node. - You provided incorrect information when bonding your node.
- You are running your node from a VPS without IPv6 support. - You are running your node from a VPS without IPv6 support.
<!-- You did not use the `--announce-host` flag while running the Mix Node from your local machine behind NAT. -->
- You did not configure your router firewall while running the node from your local machine behind NAT, or you are lacking IPv6 support - You did not configure your router firewall while running the node from your local machine behind NAT, or you are lacking IPv6 support
- Your Mix Node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](../nodes/configuration.md#automating-your-node-with-tmux-and-systemd). - Your Mix Node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](../nodes/configuration.md#automating-your-node-with-tmux-and-systemd).
```admonish caution ```admonish caution title=""
Your Nym Node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! Your Nym Node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this!
``` ```
#### Check IPv6 Connectivity
You can always check IPv6 address and connectivity by using some of these methods:
```sh
# locally listed IPv6 addresses
ip -6 addr
# globally reachable IPv6 addresses
ip -6 addr show scope global
# with DNS
dig -6 TXT +short o-o.myaddr.l.google.com @ns1.google.com
dig -t aaaa +short myip.opendns.com @resolver1.opendns.com
# https check
curl -6 https://ifconfig.co
curl -6 https://ipv6.icanhazip.com
# using telnet
telnet -6 ipv6.telnetmyip.com
```
If your connection doesn't work make sure to follow [VPS IPv6 setup](../nodes/configuration.md#connectivity-test-and-configuration). If there is more troubleshooting needed, check out [VPS IPv6 troubleshooting](vps-isp.md#ipv6-troubleshooting) page.
#### Incorrect bonding information #### Incorrect bonding information
Check that you have provided the correct information when bonding your Nym Node in the web wallet interface. When in doubt, un-bond and then re-bond your node! Check that you have provided the correct information when bonding your Nym Node in the web wallet interface. When in doubt, un-bond and then re-bond your node!
@@ -211,33 +235,6 @@ On certain cloud providers such as AWS and Google Cloud, you need to do some add
If the difference between the two is unclear, contact the help desk of your VPS provider. If the difference between the two is unclear, contact the help desk of your VPS provider.
#### No IPv6 connectivity
Make sure that your VPS has IPv6 connectivity available with whatever provider you are using.
To get all ip addresses of your host, try following commands:
```
hostname -i
```
Will return your **local ip** address.
```
hostname -I
```
Will return all of the ip addresses of your host. This output should look something like this:
```
bob@nym:~$ hostname -I
88.36.11.23 172.18.0.1 2a01:28:ca:102::1:641
```
- The first **ipv4** is the public ip you need to use for the `--announce-host` flag.
- The second **ipv4** is the local ip you need to use for the `--host` flag.
- The 3rd output should confirm if your machine has ipv6 available.
### Running on a local machine behind NAT with no fixed IP address ### Running on a local machine behind NAT with no fixed IP address
Your ISP has to be IPv6 ready if you want to run a Nym Node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. Your ISP has to be IPv6 ready if you want to run a Nym Node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it.
@@ -274,7 +271,7 @@ thread 'tokio-runtime-worker' panicked at 'Failed to create TCP listener: Os { c
``` ```
Then you need to `--announce-host <PUBLIC_IP>` and `--host <LOCAL_IP>` on startup. This issue is addressed [above](#missing-`announce-host`-flag) Then you need to `--announce-host <PUBLIC_IP>` and `--host <LOCAL_IP>` on startup. This issue is addressed [above](#missing-`announce-host`-flag)
<!-- NEEDS TO BE REWORKED AND ADD WARNING TO NOT CHANGE OTHER PORTS FOR API
### Can I use a port other than 1789? ### Can I use a port other than 1789?
Yes! Here is what you will need to do: Yes! Here is what you will need to do:
@@ -301,7 +298,7 @@ nano ~/.nym/nym-nodes/alice-node/config/config.toml
You will need to edit two parts of the file. `announce_address` and `listening_address` in the `config.toml` file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. You will need to edit two parts of the file. `announce_address` and `listening_address` in the `config.toml` file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address.
Finally, restart your node. You should see if the Mix Node is using the port you have changed in the config.toml file right after you run the node. Finally, restart your node. You should see if the Mix Node is using the port you have changed in the config.toml file right after you run the node.
-->
### What is `verloc` and do I have to configure my Nym Node to implement it? ### What is `verloc` and do I have to configure my Nym Node to implement it?
`verloc` is short for _verifiable location_. Mix Nodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner. `verloc` is short for _verifiable location_. Mix Nodes and Gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fake-able and trustworthy manner.
@@ -1,8 +1,16 @@
# Troubleshooting VPS Setup # Troubleshooting VPS Setup
## Incorrect Gateway Network Check ```admonish info
To monitor the connectivity of your Exit Gateway, use results of probe testing displayed in [harbourmaster.nymtech.net](https://harbourmaster.nymtech.net).
```
If you followed all the steps listed in [Connectivity Test and Configuration](../nodes/vps-setup.md#connectivity-test-and-configuration) chapter of VPS Setup and you still have a problem with a correct connectivity for page in ## IPv6 troubleshooting
### Incorrect Gateway Network Check
Nym operators community is working on a Nym version of tors [good bad ISP table](https://community.torproject.org/relay/community-resources/good-bad-isps/). There is no one solution fits all when it comes to connectivity setup. The operation of `nym-node` will vary depending on your ISP and chosen system/distribution. While few machines will work out of the box, most will work after uisng our connectivity configuration guide, some need more adjustments.
Begin with the steps listed in [*Connectivity Test and Configuration*](../nodes/vps-setup.md#connectivity-test-and-configuration) chapter of VPS Setup page. If you still have a problem with the IPv6 connectivity try:
1. Tor community created a helpful [table of ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/). Make sure your one is listed there as a *"good ISP"*. If not, consider migrating! 1. Tor community created a helpful [table of ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/). Make sure your one is listed there as a *"good ISP"*. If not, consider migrating!
2. Checkout your VPS dashboard and make sure your IPv6-public enabled. 2. Checkout your VPS dashboard and make sure your IPv6-public enabled.
@@ -10,8 +18,15 @@ If you followed all the steps listed in [Connectivity Test and Configuration](..
![](../images/ipv6_64.png) ![](../images/ipv6_64.png)
4. Search or ask your ISP for additional documentation related to IPv6 routing and ask them to provide you with `IPv6 IP address` and `IPv6 IP gateway address`
- For example Digital Ocean setup isn't the most straight forward, but it's [well documented](https://docs.digitalocean.com/products/networking/ipv6/how-to/enable/#on-existing-droplets) and it works.
## Virtual IPs and hosting via Google & AWS 5. Search for guides regarding your particular system and distribution. For Debian based distributions using systemd, some generic guides such as [this one](https://cloudzy.com/blog/configure-ipv6-on-ubuntu/) work as well.
## Other VPS troubleshooting
### Virtual IPs and hosting via Google & AWS
For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `<NODE>` there, please read the following. For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `<NODE>` there, please read the following.
+4 -6
View File
@@ -316,12 +316,10 @@ mod tests {
&pub_attrs, &pub_attrs,
) )
.unwrap(); .unwrap();
let sig = blind_sig let sig = blind_sig.unblind(
.unblind( keypair.verification_key(),
keypair.verification_key(), &sig_req.pedersen_commitments_openings,
&sig_req.pedersen_commitments_openings, );
)
.unwrap();
let issued = issuance.into_issued_credential(sig, 42); let issued = issuance.into_issued_credential(sig, 42);
let spending = issued let spending = issued
+11 -36
View File
@@ -6,7 +6,6 @@ use crate::node::helpers::load_keypair;
use crate::GatewayError; use crate::GatewayError;
use nym_config::OptionalSet; use nym_config::OptionalSet;
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_ip_packet_router::config::BaseClientConfig;
use nym_pemstore::traits::PemStorableKey; use nym_pemstore::traits::PemStorableKey;
use nym_pemstore::KeyPairPath; use nym_pemstore::KeyPairPath;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
@@ -43,48 +42,24 @@ pub struct OverrideIpPacketRouterConfig {
// TODO // TODO
} }
// NOTE: make sure this is in sync with service-providers/network-requester/src/cli/mod.rs::override_config
pub fn override_network_requester_config( pub fn override_network_requester_config(
mut cfg: nym_network_requester::Config, mut cfg: nym_network_requester::Config,
opts: Option<OverrideNetworkRequesterConfig>, opts: Option<OverrideNetworkRequesterConfig>,
) -> nym_network_requester::Config { ) -> nym_network_requester::Config {
let Some(opts) = opts else { return cfg }; let Some(opts) = opts else { return cfg };
// as of 12.09.23 the below is true (not sure how this comment will rot in the future) // in the old code we had calls to `assert` thus panicking
// medium_toggle: #[allow(clippy::expect_used)]
// - sets secondary packet size to 16kb cfg.base
// - disables poisson distribution of the main traffic stream .try_apply_traffic_modes(
// - sets the cover traffic stream to 1 packet / 5s (on average) cfg.network_requester.disable_poisson_rate,
// - disables per hop delay opts.medium_toggle,
// opts.fastmode,
// fastmode (to be renamed to `fast-poisson`): opts.no_cover,
// - sets average per hop delay to 10ms )
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream .expect("failed to apply traffic modes");
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
//
// no_cover:
// - disables poisson distribution of the main traffic stream
// - disables the secondary cover traffic stream
// disable poisson rate in the BASE client if the NR option is enabled cfg.with_optional(
if cfg.network_requester.disable_poisson_rate {
cfg.set_no_poisson_process();
}
// those should be enforced by `clap` when parsing the arguments
if opts.medium_toggle {
assert!(!opts.fastmode);
assert!(!opts.no_cover);
cfg.set_medium_toggle();
}
cfg.with_base(
BaseClientConfig::with_high_default_traffic_volume,
opts.fastmode,
)
.with_base(BaseClientConfig::with_disabled_cover_traffic, opts.no_cover)
.with_optional(
nym_network_requester::Config::with_open_proxy, nym_network_requester::Config::with_open_proxy,
opts.open_proxy, opts.open_proxy,
) )
+12 -5
View File
@@ -5,7 +5,7 @@ use crate::config::Config;
use crate::error::GatewayError; use crate::error::GatewayError;
use crate::helpers::load_public_key; use crate::helpers::load_public_key;
use ipnetwork::IpNetwork; use ipnetwork::IpNetwork;
use log::{debug, warn}; use log::{debug, error, warn};
use nym_bin_common::bin_info_owned; use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_network_requester::RequestFilter; use nym_network_requester::RequestFilter;
@@ -295,12 +295,19 @@ impl<'a> HttpApiBuilder<'a> {
.ok() .ok()
}); });
let bind_address = self.gateway_config.http.bind_address;
let router = nym_node_http_api::NymNodeRouter::new(config, None, wg_state); let router = nym_node_http_api::NymNodeRouter::new(config, None, wg_state);
let server = router tokio::spawn(async move {
.build_server(&self.gateway_config.http.bind_address)? let server = match router.build_server(&bind_address).await {
.with_task_client(task_client); Ok(server) => server.with_task_client(task_client),
tokio::spawn(async move { server.run().await }); Err(err) => {
error!("failed to create http server: {err}");
return;
}
};
server.run().await
});
Ok(()) Ok(())
} }
} }
+12 -6
View File
@@ -4,7 +4,7 @@
use crate::config::Config; use crate::config::Config;
use crate::error::MixnodeError; use crate::error::MixnodeError;
use crate::node::node_description::NodeDescription; use crate::node::node_description::NodeDescription;
use log::info; use log::{error, info};
use nym_bin_common::bin_info_owned; use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_node_http_api::api::api_requests; use nym_node_http_api::api::api_requests;
@@ -104,11 +104,17 @@ impl<'a> HttpApiBuilder<'a> {
.with_landing_page_assets(self.mixnode_config.http.landing_page_assets_path.as_ref()); .with_landing_page_assets(self.mixnode_config.http.landing_page_assets_path.as_ref());
let router = nym_node_http_api::NymNodeRouter::new(config, None, None); let router = nym_node_http_api::NymNodeRouter::new(config, None, None);
let server = router
// .with_merged(legacy::routes(self.legacy_mixnode, self.legacy_descriptor)) tokio::spawn(async move {
.build_server(&bind_address)? let server = match router.build_server(&bind_address).await {
.with_task_client(task_client); Ok(server) => server.with_task_client(task_client),
tokio::spawn(async move { server.run().await }); Err(err) => {
error!("failed to create http server: {err}");
return;
}
};
server.run().await
});
Ok(()) Ok(())
} }
} }
+4 -6
View File
@@ -1752,12 +1752,10 @@ mod credential_tests {
&pub_attrs, &pub_attrs,
) )
.unwrap(); .unwrap();
let sig = blind_sig let sig = blind_sig.unblind(
.unblind( key_pair.verification_key(),
key_pair.verification_key(), &sig_req.pedersen_commitments_openings,
&sig_req.pedersen_commitments_openings, );
)
.unwrap();
let issued = issuance.into_issued_credential(sig, epoch); let issued = issuance.into_issued_credential(sig, epoch);
let spending = issued let spending = issued
+221 -271
View File
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -7,18 +7,16 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
axum = { workspace = true, features = ["headers"] } axum.workspace = true
# \/ will be needed once we update axum to 0.7 axum-extra = { axum.workspace = true, features = ["typed-header"] }
#axum-extra = { version = "0.9.3", features = ["typed-header"] } headers.workspace = true
#headers = "0.4"
# useful for `#[axum_macros::debug_handler]` # useful for `#[axum_macros::debug_handler]`
#axum-macros = "0.3.8" #axum-macros = "0.3.8"
hyper.workspace = true
thiserror.workspace = true thiserror.workspace = true
time = { workspace = true, features = ["serde"] } time = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["macros"] } tokio = { workspace = true, features = ["macros"] }
tower-http = { version = "0.4.4", features = ["fs"] } tower-http = { version = "0.5.2", features = ["fs"] }
tracing.workspace = true tracing.workspace = true
utoipa = { workspace = true, features = ["axum_extras", "time"] } utoipa = { workspace = true, features = ["axum_extras", "time"] }
utoipa-swagger-ui = { workspace = true, features = ["axum"] } utoipa-swagger-ui = { workspace = true, features = ["axum"] }
@@ -40,6 +38,7 @@ nym-wireguard = { path = "../../common/wireguard" }
nym-wireguard-types = { path = "../../common/wireguard-types", features = ["verify"] } nym-wireguard-types = { path = "../../common/wireguard-types", features = ["verify"] }
[dev-dependencies] [dev-dependencies]
hyper.workspace = true
dashmap.workspace = true dashmap.workspace = true
serde_json.workspace = true serde_json.workspace = true
+2 -1
View File
@@ -1,6 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net> // Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use thiserror::Error; use thiserror::Error;
@@ -9,7 +10,7 @@ pub enum NymNodeHttpError {
#[error("failed to bind the HTTP API to {bind_address}: {source}")] #[error("failed to bind the HTTP API to {bind_address}: {source}")]
HttpBindFailure { HttpBindFailure {
bind_address: SocketAddr, bind_address: SocketAddr,
source: hyper::Error, source: io::Error,
}, },
#[error("failed to use nym-node requests: {source}")] #[error("failed to use nym-node requests: {source}")]
+12 -11
View File
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo; use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
use axum::extract::ConnectInfo;
use axum::middleware::AddExtension;
use axum::serve::Serve;
use axum::Router; use axum::Router;
use hyper::server::conn::AddrIncoming;
use hyper::Server;
use nym_task::TaskClient; use nym_task::TaskClient;
use std::net::SocketAddr; use std::net::SocketAddr;
use tracing::{debug, error, info}; use tracing::{debug, error};
pub mod error; pub mod error;
pub mod middleware; pub mod middleware;
@@ -17,15 +18,18 @@ pub mod state;
pub use error::NymNodeHttpError; pub use error::NymNodeHttpError;
pub use router::{api, landing_page, Config, NymNodeRouter}; pub use router::{api, landing_page, Config, NymNodeRouter};
// I guess this wasn't really meant to be extracted into separate type haha
type InnerService = IntoMakeServiceWithConnectInfo<Router, SocketAddr>;
type ConnectInfoExt = AddExtension<Router, ConnectInfo<SocketAddr>>;
pub type ServeService = Serve<InnerService, ConnectInfoExt>;
pub struct NymNodeHTTPServer { pub struct NymNodeHTTPServer {
task_client: Option<TaskClient>, task_client: Option<TaskClient>,
inner: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>, inner: ServeService,
} }
impl NymNodeHTTPServer { impl NymNodeHTTPServer {
pub(crate) fn new( pub(crate) fn new(inner: ServeService) -> Self {
inner: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>,
) -> Self {
NymNodeHTTPServer { NymNodeHTTPServer {
task_client: None, task_client: None,
inner, inner,
@@ -38,9 +42,7 @@ impl NymNodeHTTPServer {
self self
} }
async fn run_server_forever( async fn run_server_forever(server: ServeService) {
server: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>,
) {
if let Err(err) = server.await { if let Err(err) = server.await {
error!("the HTTP server has terminated with the error: {err}"); error!("the HTTP server has terminated with the error: {err}");
} else { } else {
@@ -49,7 +51,6 @@ impl NymNodeHTTPServer {
} }
pub async fn run(self) { pub async fn run(self) {
info!("Started NymNodeHTTPServer on {}", self.inner.local_addr());
if let Some(mut task_client) = self.task_client { if let Some(mut task_client) = self.task_client {
tokio::select! { tokio::select! {
_ = task_client.recv_with_delay() => { _ = task_client.recv_with_delay() => {
@@ -1,22 +1,24 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use axum::{ use axum::{
extract::ConnectInfo, extract::{ConnectInfo, Request},
http::{HeaderValue, Request}, http::{
header::{HOST, USER_AGENT},
HeaderValue,
},
middleware::Next, middleware::Next,
response::IntoResponse, response::IntoResponse,
}; };
use colored::*; use colored::*;
use hyper::header::{HOST, USER_AGENT};
use std::net::SocketAddr; use std::net::SocketAddr;
use tracing::info; use tracing::info;
/// Simple logger for requests /// Simple logger for requests
pub async fn logger<B>( pub async fn logger(
ConnectInfo(addr): ConnectInfo<SocketAddr>, ConnectInfo(addr): ConnectInfo<SocketAddr>,
req: Request<B>, req: Request,
next: Next<B>, next: Next,
) -> impl IntoResponse { ) -> impl IntoResponse {
let method = req.method().to_string().green(); let method = req.method().to_string().green();
let uri = req.uri().to_string().blue(); let uri = req.uri().to_string().blue();
@@ -104,6 +104,7 @@ mod test {
use crate::api::v1::gateway::client_interfaces::wireguard::{ use crate::api::v1::gateway::client_interfaces::wireguard::{
routes, WireguardAppState, WireguardAppStateInner, routes, WireguardAppState, WireguardAppStateInner,
}; };
use axum::body::to_bytes;
use axum::body::Body; use axum::body::Body;
use axum::http::Request; use axum::http::Request;
use axum::http::StatusCode; use axum::http::StatusCode;
@@ -203,7 +204,7 @@ mod test {
nonce, nonce,
gateway_data, gateway_data,
wg_port: 8080, wg_port: 8080,
} = serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap()) } = serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
.unwrap() .unwrap()
else { else {
panic!("invalid response") panic!("invalid response")
@@ -257,7 +258,7 @@ mod test {
assert_eq!(response.status(), StatusCode::OK); assert_eq!(response.status(), StatusCode::OK);
let clients: Vec<PeerPublicKey> = let clients: Vec<PeerPublicKey> =
serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap()) serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
.unwrap(); .unwrap();
assert!(!clients.is_empty()); assert!(!clients.is_empty());
@@ -3,10 +3,10 @@
use crate::state::metrics::MetricsAppState; use crate::state::metrics::MetricsAppState;
use axum::extract::State; use axum::extract::State;
use axum::headers::authorization::Bearer;
use axum::headers::Authorization;
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::TypedHeader; use axum_extra::TypedHeader;
use headers::authorization::Bearer;
use headers::Authorization;
use nym_metrics::metrics; use nym_metrics::metrics;
/// Returns `prometheus` compatible metrics /// Returns `prometheus` compatible metrics
+15 -16
View File
@@ -161,28 +161,24 @@ impl NymNodeRouter {
// redirection for old legacy mixnode routes // redirection for old legacy mixnode routes
.route( .route(
"/hardware", "/hardware",
get(|| async { Redirect::permanent(&routes::api::v1::system_info_absolute()) }), get(|| async { Redirect::to(&routes::api::v1::system_info_absolute()) }),
) )
.route( .route(
"/description", "/description",
get(|| async { Redirect::permanent(&routes::api::v1::description_absolute()) }), get(|| async { Redirect::to(&routes::api::v1::description_absolute()) }),
) )
.route( .route(
"/stats", "/stats",
get(|| async { get(|| async { Redirect::to(&routes::api::v1::metrics::mixing_absolute()) }),
Redirect::permanent(&routes::api::v1::metrics::mixing_absolute())
}),
) )
.route( .route(
"/verloc", "/verloc",
get(|| async { get(|| async { Redirect::to(&routes::api::v1::metrics::verloc_absolute()) }),
Redirect::permanent(&routes::api::v1::metrics::verloc_absolute())
}),
) )
.route( .route(
"/metrics", "/metrics",
get(|| async { get(|| async {
Redirect::permanent(&routes::api::v1::metrics::prometheus_absolute()) Redirect::to(&routes::api::v1::metrics::prometheus_absolute())
}), }),
) )
.nest(routes::LANDING_PAGE, landing_page::routes(config.landing)) .nest(routes::LANDING_PAGE, landing_page::routes(config.landing))
@@ -208,19 +204,22 @@ impl NymNodeRouter {
self self
} }
pub fn build_server( pub async fn build_server(
self, self,
bind_address: &SocketAddr, bind_address: &SocketAddr,
) -> Result<NymNodeHTTPServer, NymNodeHttpError> { ) -> Result<NymNodeHTTPServer, NymNodeHttpError> {
let axum_server = axum::Server::try_bind(bind_address) let listener = tokio::net::TcpListener::bind(bind_address)
.await
.map_err(|source| NymNodeHttpError::HttpBindFailure { .map_err(|source| NymNodeHttpError::HttpBindFailure {
bind_address: *bind_address, bind_address: *bind_address,
source, source,
})? })?;
.serve(
self.inner let axum_server = axum::serve(
.into_make_service_with_connect_info::<SocketAddr>(), listener,
); self.inner
.into_make_service_with_connect_info::<SocketAddr>(),
);
Ok(NymNodeHTTPServer::new(axum_server)) Ok(NymNodeHTTPServer::new(axum_server))
} }
+19 -2
View File
@@ -154,7 +154,7 @@ pub fn ephemeral_exit_gateway_config(
config: Config, config: Config,
mnemonic: &bip39::Mnemonic, mnemonic: &bip39::Mnemonic,
) -> Result<EphemeralConfig, ExitGatewayError> { ) -> Result<EphemeralConfig, ExitGatewayError> {
let nr_opts = LocalNetworkRequesterOpts { let mut nr_opts = LocalNetworkRequesterOpts {
config: nym_network_requester::Config { config: nym_network_requester::Config {
base: nym_client_core_config_types::Config { base: nym_client_core_config_types::Config {
client: base_client_config(&config), client: base_client_config(&config),
@@ -186,7 +186,20 @@ pub fn ephemeral_exit_gateway_config(
custom_mixnet_path: None, custom_mixnet_path: None,
}; };
let ipr_opts = LocalIpPacketRouterOpts { // SAFETY: this function can only fail if fastmode or nocover is set alongside medium_toggle which is not the case here
#[allow(clippy::unwrap_used)]
nr_opts
.config
.base
.try_apply_traffic_modes(
nr_opts.config.network_requester.disable_poisson_rate,
false,
false,
false,
)
.unwrap();
let mut ipr_opts = LocalIpPacketRouterOpts {
config: nym_ip_packet_router::Config { config: nym_ip_packet_router::Config {
base: nym_client_core_config_types::Config { base: nym_client_core_config_types::Config {
client: base_client_config(&config), client: base_client_config(&config),
@@ -216,6 +229,10 @@ pub fn ephemeral_exit_gateway_config(
custom_mixnet_path: None, custom_mixnet_path: None,
}; };
if ipr_opts.config.ip_packet_router.disable_poisson_rate {
ipr_opts.config.base.set_no_poisson_process()
}
let pub_id_path = config let pub_id_path = config
.storage_paths .storage_paths
.keys .keys
+12 -4
View File
@@ -455,7 +455,7 @@ impl NymNode {
Ok(()) Ok(())
} }
pub(crate) fn build_http_server(&self) -> Result<NymNodeHTTPServer, NymNodeError> { pub(crate) async fn build_http_server(&self) -> Result<NymNodeHTTPServer, NymNodeError> {
let host_details = sign_host_details( let host_details = sign_host_details(
&self.config, &self.config,
self.x25519_sphinx_keys.public_key(), self.x25519_sphinx_keys.public_key(),
@@ -559,15 +559,23 @@ impl NymNode {
.with_metrics_key(self.config.http.access_token.clone()); .with_metrics_key(self.config.http.access_token.clone());
Ok(NymNodeRouter::new(config, Some(app_state), Some(wg_state)) Ok(NymNodeRouter::new(config, Some(app_state), Some(wg_state))
.build_server(&self.config.http.bind_address)?) .build_server(&self.config.http.bind_address)
.await?)
} }
pub(crate) async fn run(self) -> Result<(), NymNodeError> { pub(crate) async fn run(self) -> Result<(), NymNodeError> {
let mut task_manager = TaskManager::default().named("NymNode"); let mut task_manager = TaskManager::default().named("NymNode");
let http_server = self let http_server = self
.build_http_server()? .build_http_server()
.await?
.with_task_client(task_manager.subscribe_named("http-server")); .with_task_client(task_manager.subscribe_named("http-server"));
tokio::spawn(async move { http_server.run().await }); let bind_address = self.config.http.bind_address;
tokio::spawn(async move {
{
info!("Started NymNodeHTTPServer on {bind_address}");
http_server.run().await
}
});
match self.config.mode { match self.config.mode {
NodeMode::Mixnode => { NodeMode::Mixnode => {
+3 -3
View File
@@ -31,7 +31,7 @@ humantime = "2.1.0"
humantime-serde.workspace = true humantime-serde.workspace = true
# internal # internal
nym-bin-common = { path = "../common/bin-common", features = ["output_format"] } nym-bin-common = { path = "../common/bin-common", features = ["output_format", "basic_tracing"] }
nym-config = { path = "../common/config" } nym-config = { path = "../common/config" }
nym-coconut = { path = "../common/nymcoconut" } nym-coconut = { path = "../common/nymcoconut" }
nym-crypto = { path = "../common/crypto", features = ["asymmetric"] } nym-crypto = { path = "../common/crypto", features = ["asymmetric"] }
@@ -39,8 +39,8 @@ nym-credentials = { path = "../common/credentials" }
nym-network-defaults = { path = "../common/network-defaults" } nym-network-defaults = { path = "../common/network-defaults" }
nym-task = { path = "../common/task" } nym-task = { path = "../common/task" }
nym-validator-client = { path = "../common/client-libs/validator-client" } nym-validator-client = { path = "../common/client-libs/validator-client" }
nym-coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg"} nym-coconut-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg" }
nym-coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract"} nym-coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
nyxd-scraper = { path = "../common/nyxd-scraper" } nyxd-scraper = { path = "../common/nyxd-scraper" }
[build-dependencies] [build-dependencies]
+1 -1
View File
@@ -50,7 +50,7 @@ pub(crate) fn execute(args: Args) -> Result<(), NymRewarderError> {
}; };
let config = Config::new(args.mnemonic, websocket, nyxd).with_override(args.config_override); let config = Config::new(args.mnemonic, websocket, nyxd).with_override(args.config_override);
config.ensure_is_valid()?; config.validate()?;
config config
.save_to_path(&path) .save_to_path(&path)
+2 -2
View File
@@ -110,7 +110,7 @@ fn try_load_current_config(custom_path: &Option<PathBuf>) -> Result<Config, NymR
); );
if let Ok(cfg) = Config::read_from_toml_file(&config_path) { if let Ok(cfg) = Config::read_from_toml_file(&config_path) {
cfg.ensure_is_valid()?; cfg.validate()?;
return Ok(cfg); return Ok(cfg);
} }
@@ -122,7 +122,7 @@ fn try_load_current_config(custom_path: &Option<PathBuf>) -> Result<Config, NymR
); );
err err
})?; })?;
config.ensure_is_valid()?; config.validate()?;
Ok(config) Ok(config)
} }
+49 -5
View File
@@ -10,6 +10,7 @@ use nym_config::{
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
}; };
use nym_validator_client::nyxd::{AccountId, Coin}; use nym_validator_client::nyxd::{AccountId, Coin};
use nyxd_scraper::PruningOptions;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr}; use serde_with::{serde_as, DisplayFromStr};
use std::io; use std::io;
@@ -34,6 +35,9 @@ const DEFAULT_MONITOR_RUN_INTERVAL: Duration = Duration::from_secs(10 * 60);
const DEFAULT_MONITOR_MIN_VALIDATE: usize = 10; const DEFAULT_MONITOR_MIN_VALIDATE: usize = 10;
const DEFAULT_MONITOR_SAMPLING_RATE: f64 = 0.10; const DEFAULT_MONITOR_SAMPLING_RATE: f64 = 0.10;
// 'worst' case scenario
pub const TYPICAL_BLOCK_TIME: f32 = 5.;
/// Get default path to rewarder's config directory. /// Get default path to rewarder's config directory.
/// It should get resolved to `$HOME/.nym/validators-rewarder/config` /// It should get resolved to `$HOME/.nym/validators-rewarder/config`
pub fn default_config_directory() -> PathBuf { pub fn default_config_directory() -> PathBuf {
@@ -100,7 +104,10 @@ impl Config {
rewarding: Rewarding::default(), rewarding: Rewarding::default(),
block_signing: Default::default(), block_signing: Default::default(),
issuance_monitor: IssuanceMonitor::default(), issuance_monitor: IssuanceMonitor::default(),
nyxd_scraper: NyxdScraper { websocket_url }, nyxd_scraper: NyxdScraper {
websocket_url,
pruning: Default::default(),
},
base: Base { base: Base {
upstream_nyxd: nyxd_url, upstream_nyxd: nyxd_url,
mnemonic, mnemonic,
@@ -114,11 +121,13 @@ impl Config {
websocket_url: self.nyxd_scraper.websocket_url.clone(), websocket_url: self.nyxd_scraper.websocket_url.clone(),
rpc_url: self.base.upstream_nyxd.clone(), rpc_url: self.base.upstream_nyxd.clone(),
database_path: self.storage_paths.nyxd_scraper.clone(), database_path: self.storage_paths.nyxd_scraper.clone(),
pruning_options: self.nyxd_scraper.pruning,
} }
} }
pub fn ensure_is_valid(&self) -> Result<(), NymRewarderError> { pub fn validate(&self) -> Result<(), NymRewarderError> {
self.rewarding.ratios.ensure_is_valid()?; self.rewarding.ratios.validate()?;
self.nyxd_scraper.validate(self.rewarding.epoch_duration)?;
Ok(()) Ok(())
} }
@@ -140,7 +149,7 @@ impl Config {
source, source,
} }
})?; })?;
loaded.ensure_is_valid()?; loaded.validate()?;
loaded.save_path = Some(path.to_path_buf()); loaded.save_path = Some(path.to_path_buf());
debug!("loaded config file from {}", path.display()); debug!("loaded config file from {}", path.display());
Ok(loaded) Ok(loaded)
@@ -223,7 +232,7 @@ impl Default for RewardingRatios {
} }
impl RewardingRatios { impl RewardingRatios {
pub fn ensure_is_valid(&self) -> Result<(), NymRewarderError> { pub fn validate(&self) -> Result<(), NymRewarderError> {
if self.block_signing + self.credential_verification + self.credential_issuance != 1.0 { if self.block_signing + self.credential_verification + self.credential_issuance != 1.0 {
return Err(NymRewarderError::InvalidRewardingRatios { ratios: *self }); return Err(NymRewarderError::InvalidRewardingRatios { ratios: *self });
} }
@@ -235,9 +244,44 @@ impl RewardingRatios {
pub struct NyxdScraper { pub struct NyxdScraper {
/// Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket` /// Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket`
pub websocket_url: Url, pub websocket_url: Url,
/// Defines the pruning options, if applicable, to be used by the underlying scraper.
// if the value is missing, use `nothing` pruning as this was the past behaviour
#[serde(default = "PruningOptions::nothing")]
pub pruning: PruningOptions,
// TODO: debug with everything that's currently hardcoded in the scraper // TODO: debug with everything that's currently hardcoded in the scraper
} }
impl NyxdScraper {
pub fn validate(&self, epoch_duration: Duration) -> Result<(), NymRewarderError> {
// basic, sanity check, of pruning
self.pruning.validate()?;
if self.pruning.strategy.is_nothing() {
return Ok(());
}
// rewarder-specific validation:
if self.pruning.strategy.is_everything() {
return Err(NymRewarderError::EverythingPruningStrategy);
}
if self.pruning.strategy.is_custom() {
let min_to_keep =
(epoch_duration.as_secs_f32() / TYPICAL_BLOCK_TIME * 1.5).ceil() as u32;
if self.pruning.strategy_keep_recent() < min_to_keep {
return Err(NymRewarderError::TooSmallKeepRecent {
min_to_keep,
keep_recent: self.pruning.strategy_keep_recent(),
});
}
}
Ok(())
}
}
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BlockSigning { pub struct BlockSigning {
/// Specifies whether rewards for block signing is enabled. /// Specifies whether rewards for block signing is enabled.
@@ -74,4 +74,14 @@ whitelist = [
[nyxd_scraper] [nyxd_scraper]
# Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket` # Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket`
websocket_url = '{{ nyxd_scraper.websocket_url }}' websocket_url = '{{ nyxd_scraper.websocket_url }}'
# default: the last 362880 states are kept, pruning at 10 block intervals
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving)
# everything: 2 latest states will be kept; pruning at 10 block intervals.
# custom: allow pruning options to be manually specified through 'pruning.keep_recent' and 'pruning.interval'
pruning.strategy = '{{ nyxd_scraper.pruning.strategy }}'
# These are applied if and only if the pruning strategy is custom.
pruning.keep_recent = {{ nyxd_scraper.pruning.keep_recent }}
pruning.interval = {{ nyxd_scraper.pruning.interval }}
"#; "#;
+6
View File
@@ -166,6 +166,12 @@ pub enum NymRewarderError {
#[error("there were no validators to reward in this epoch")] #[error("there were no validators to reward in this epoch")]
NoValidatorsToReward, NoValidatorsToReward,
#[error("the current pruning strategy is set to 'everything' - we won't have any block data for rewarding")]
EverythingPruningStrategy,
#[error("pruning.keep_recent must not be smaller than {min_to_keep}. got: {keep_recent}")]
TooSmallKeepRecent { min_to_keep: u32, keep_recent: u32 },
} }
#[derive(Debug)] #[derive(Debug)]
+1 -1
View File
@@ -20,7 +20,7 @@ mod rewarder;
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
// std::env::set_var( // std::env::set_var(
// "RUST_LOG", // "RUST_LOG",
// "debug,tendermint_rpc=warn,h2=warn,hyper=warn,rustls=warn,reqwest=warn,tungstenite=warn,async_tungstenite=warn", // "trace,handlebars=warn,tendermint_rpc=warn,h2=warn,hyper=warn,rustls=warn,reqwest=warn,tungstenite=warn,async_tungstenite=warn,tokio_util=warn,tokio_tungstenite=warn,tokio-util=warn",
// ); // );
let args = Cli::parse(); let args = Cli::parse();
@@ -11,7 +11,7 @@ use nyxd_scraper::NyxdScraper;
use std::cmp::min; use std::cmp::min;
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::Range; use std::ops::Range;
use tracing::{debug, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
pub(crate) mod types; pub(crate) mod types;
@@ -28,7 +28,7 @@ impl EpochSigning {
height_range: Range<i64>, height_range: Range<i64>,
) -> Result<Option<i64>, NymRewarderError> { ) -> Result<Option<i64>, NymRewarderError> {
for height in height_range { for height in height_range {
trace!("attempting to get precommit for {address} at height {height}"); trace!("attempting to get pre-commit for {address} at height {height}");
if let Some(precommit) = self if let Some(precommit) = self
.nyxd_scraper .nyxd_scraper
.storage .storage
@@ -121,7 +121,7 @@ impl EpochSigning {
.get_voting_power(&validator.consensus_address, vp_range.clone()) .get_voting_power(&validator.consensus_address, vp_range.clone())
.await? .await?
else { else {
warn!("failed to obtain voting power of {addr}"); error!("failed to obtain voting power for validator {addr} for any block between heights {vp_range:?} - there were no stored pre-commits for that validator.");
continue; continue;
}; };
+176 -21
View File
@@ -220,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7"
dependencies = [ dependencies = [
"flate2", "flate2",
"http", "http 0.2.9",
"log", "log",
"native-tls", "native-tls",
"serde", "serde",
@@ -279,6 +279,12 @@ version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@@ -2178,7 +2184,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http 0.2.9",
"indexmap 1.9.3", "indexmap 1.9.3",
"slab", "slab",
"tokio", "tokio",
@@ -2311,6 +2317,17 @@ dependencies = [
"itoa 1.0.9", "itoa 1.0.9",
] ]
[[package]]
name = "http"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
dependencies = [
"bytes",
"fnv",
"itoa 1.0.9",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.5" version = "0.4.5"
@@ -2318,7 +2335,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 0.2.9",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http 1.1.0",
]
[[package]]
name = "http-body-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d"
dependencies = [
"bytes",
"futures-core",
"http 1.1.0",
"http-body 1.0.0",
"pin-project-lite", "pin-project-lite",
] ]
@@ -2376,8 +2416,8 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.9",
"http-body", "http-body 0.4.5",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa 1.0.9", "itoa 1.0.9",
@@ -2389,6 +2429,25 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"httparse",
"itoa 1.0.9",
"pin-project-lite",
"smallvec",
"tokio",
"want",
]
[[package]] [[package]]
name = "hyper-rustls" name = "hyper-rustls"
version = "0.24.2" version = "0.24.2"
@@ -2396,8 +2455,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"http", "http 0.2.9",
"hyper", "hyper 0.14.27",
"rustls", "rustls",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
@@ -2410,12 +2469,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [ dependencies = [
"bytes", "bytes",
"hyper", "hyper 0.14.27",
"native-tls", "native-tls",
"tokio", "tokio",
"tokio-native-tls", "tokio-native-tls",
] ]
[[package]]
name = "hyper-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"hyper 1.3.1",
"pin-project-lite",
"socket2 0.5.5",
"tokio",
"tower",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "ico" name = "ico"
version = "0.2.0" version = "0.2.0"
@@ -3005,6 +3084,7 @@ dependencies = [
"schemars", "schemars",
"serde", "serde",
"tendermint", "tendermint",
"time",
] ]
[[package]] [[package]]
@@ -3173,7 +3253,7 @@ name = "nym-http-api-client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@@ -3320,7 +3400,7 @@ dependencies = [
"nym-mixnet-contract-common", "nym-mixnet-contract-common",
"nym-validator-client", "nym-validator-client",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"reqwest", "reqwest 0.12.4",
"schemars", "schemars",
"serde", "serde",
"serde_json", "serde_json",
@@ -3369,7 +3449,7 @@ dependencies = [
"nym-service-provider-directory-common", "nym-service-provider-directory-common",
"nym-vesting-contract-common", "nym-vesting-contract-common",
"prost", "prost",
"reqwest", "reqwest 0.12.4",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.9.9", "sha2 0.9.9",
@@ -3442,7 +3522,7 @@ dependencies = [
[[package]] [[package]]
name = "nym_wallet" name = "nym_wallet"
version = "1.2.12" version = "1.2.13"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"base64 0.13.1", "base64 0.13.1",
@@ -3471,11 +3551,12 @@ dependencies = [
"once_cell", "once_cell",
"pretty_env_logger", "pretty_env_logger",
"rand_chacha 0.2.2", "rand_chacha 0.2.2",
"reqwest", "reqwest 0.11.22",
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
"strum 0.23.0", "strum 0.23.0",
"tap",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-codegen", "tauri-codegen",
@@ -4318,9 +4399,9 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.9",
"http-body", "http-body 0.4.5",
"hyper", "hyper 0.14.27",
"hyper-rustls", "hyper-rustls",
"hyper-tls", "hyper-tls",
"ipnet", "ipnet",
@@ -4346,7 +4427,42 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"winreg", "winreg 0.50.0",
]
[[package]]
name = "reqwest"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-util",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"hyper 1.3.1",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg 0.52.0",
] ]
[[package]] [[package]]
@@ -5114,6 +5230,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@@ -5249,7 +5371,7 @@ dependencies = [
"glob", "glob",
"gtk", "gtk",
"heck 0.4.1", "heck 0.4.1",
"http", "http 0.2.9",
"ignore", "ignore",
"minisign-verify", "minisign-verify",
"objc", "objc",
@@ -5346,7 +5468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c507d954d08ac8705d235bc70ec6975b9054fb95ff7823af72dbb04186596f3b" checksum = "c507d954d08ac8705d235bc70ec6975b9054fb95ff7823af72dbb04186596f3b"
dependencies = [ dependencies = [
"gtk", "gtk",
"http", "http 0.2.9",
"http-range", "http-range",
"rand 0.8.5", "rand 0.8.5",
"raw-window-handle", "raw-window-handle",
@@ -5496,7 +5618,7 @@ dependencies = [
"getrandom 0.2.10", "getrandom 0.2.10",
"peg", "peg",
"pin-project", "pin-project",
"reqwest", "reqwest 0.11.22",
"semver 1.0.22", "semver 1.0.22",
"serde", "serde",
"serde_bytes", "serde_bytes",
@@ -5724,6 +5846,28 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"pin-project",
"pin-project-lite",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.2"
@@ -5737,6 +5881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@@ -6473,6 +6618,16 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "winreg"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "winres" name = "winres"
version = "0.1.12" version = "0.1.12"
@@ -6499,7 +6654,7 @@ dependencies = [
"glib", "glib",
"gtk", "gtk",
"html5ever", "html5ever",
"http", "http 0.2.9",
"kuchiki", "kuchiki",
"libc", "libc",
"log", "log",
+1
View File
@@ -37,6 +37,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
serde_repr = "0.1" serde_repr = "0.1"
strum = { version = "0.23", features = ["derive"] } strum = { version = "0.23", features = ["derive"] }
tap = "1"
tauri = { version = "=1.2.3", features = ["clipboard-all", "shell-open", "updater", "window-maximize", "window-print"] } tauri = { version = "=1.2.3", features = ["clipboard-all", "shell-open", "updater", "window-maximize", "window-print"] }
#tendermint-rpc = "0.23.0" #tendermint-rpc = "0.23.0"
time = { version = "0.3.17", features = ["local-offset"] } time = { version = "0.3.17", features = ["local-offset"] }
@@ -4,6 +4,7 @@
use crate::error::BackendError; use crate::error::BackendError;
use crate::state::WalletState; use crate::state::WalletState;
use crate::vesting::delegate::vesting_undelegate_from_mixnode; use crate::vesting::delegate::vesting_undelegate_from_mixnode;
use nym_mixnet_contract_common::mixnode::StakeSaturationResponse;
use nym_mixnet_contract_common::MixId; use nym_mixnet_contract_common::MixId;
use nym_types::currency::DecCoin; use nym_types::currency::DecCoin;
use nym_types::delegation::{Delegation, DelegationWithEverything, DelegationsSummaryResponse}; use nym_types::delegation::{Delegation, DelegationWithEverything, DelegationsSummaryResponse};
@@ -18,6 +19,7 @@ use nym_validator_client::nyxd::contract_traits::{
MixnetQueryClient, MixnetSigningClient, NymContractsProvider, PagedMixnetQueryClient, MixnetQueryClient, MixnetSigningClient, NymContractsProvider, PagedMixnetQueryClient,
}; };
use nym_validator_client::nyxd::Fee; use nym_validator_client::nyxd::Fee;
use tap::TapFallible;
#[tauri::command] #[tauri::command]
pub async fn get_pending_delegation_events( pub async fn get_pending_delegation_events(
@@ -165,10 +167,21 @@ pub async fn get_all_mix_delegations(
.expect("vesting contract address is not available"); .expect("vesting contract address is not available");
log::info!(" >>> Get delegations"); log::info!(" >>> Get delegations");
let delegations = client.nyxd.get_all_delegator_delegations(&address).await?; let delegations = client
.nyxd
.get_all_delegator_delegations(&address)
.await
.tap_err(|err| {
log::error!(" <<< Failed to get delegations. Error: {}", err);
})?;
log::info!(" <<< {} delegations", delegations.len()); log::info!(" <<< {} delegations", delegations.len());
let pending_events_for_account = get_pending_delegation_events(state.clone()).await?; let pending_events_for_account =
get_pending_delegation_events(state.clone())
.await
.tap_err(|err| {
log::error!(" <<< Failed to get pending delegations. Error: {}", err);
})?;
log::info!( log::info!(
" <<< {} pending delegation events for account", " <<< {} pending delegation events for account",
@@ -178,7 +191,16 @@ pub async fn get_all_mix_delegations(
let mut with_everything: Vec<DelegationWithEverything> = Vec::with_capacity(delegations.len()); let mut with_everything: Vec<DelegationWithEverything> = Vec::with_capacity(delegations.len());
for delegation in delegations { for delegation in delegations {
let d = Delegation::from_mixnet_contract(delegation, reg)?; let mut error_strings: Vec<String> = vec![];
let d = Delegation::from_mixnet_contract(delegation.clone(), reg).tap_err(|err| {
log::error!(
" <<< Failed to get delegation for mix id {} from contract. Error: {}",
delegation.mix_id,
err
);
})?;
let uses_vesting_contract_tokens = d let uses_vesting_contract_tokens = d
.proxy .proxy
.as_ref() .as_ref()
@@ -194,7 +216,15 @@ pub async fn get_all_mix_delegations(
let mixnode = client let mixnode = client
.nyxd .nyxd
.get_mixnode_details(d.mix_id) .get_mixnode_details(d.mix_id)
.await? .await
.tap_err(|err| {
let str_err = format!(
"Failed to get mixnode details for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})?
.mixnode_details; .mixnode_details;
let accumulated_by_operator = mixnode let accumulated_by_operator = mixnode
@@ -202,14 +232,32 @@ pub async fn get_all_mix_delegations(
.map(|m| { .map(|m| {
guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.operator) guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.operator)
}) })
.transpose()?; .transpose()
.tap_err(|err| {
let str_err = format!(
"Failed to get operator rewards as a display coin for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.unwrap_or_default();
let accumulated_by_delegates = mixnode let accumulated_by_delegates = mixnode
.as_ref() .as_ref()
.map(|m| { .map(|m| {
guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.delegates) guard.display_coin_from_base_decimal(&base_mix_denom, m.rewarding_details.delegates)
}) })
.transpose()?; .transpose()
.tap_err(|err| {
let str_err = format!(
"Failed to get delegator rewards as a display coin for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.unwrap_or_default();
let cost_params = mixnode let cost_params = mixnode
.as_ref() .as_ref()
@@ -219,19 +267,48 @@ pub async fn get_all_mix_delegations(
reg, reg,
) )
}) })
.transpose()?; .transpose()
.tap_err(|err| {
let str_err = format!(
"Failed to mixnode cost params for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.unwrap_or_default();
log::trace!(" >>> Get accumulated rewards: address = {}", address); log::trace!(" >>> Get accumulated rewards: address = {}", address);
let pending_reward = client let pending_reward = client
.nyxd .nyxd
.get_pending_delegator_reward(&address, d.mix_id, d.proxy.clone()) .get_pending_delegator_reward(&address, d.mix_id, d.proxy.clone())
.await?; .await
.tap_err(|err| {
let str_err = format!(
"Failed to get accumulated rewards for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.unwrap_or_default();
let accumulated_rewards = match &pending_reward.amount_earned { let accumulated_rewards = match &pending_reward.amount_earned {
Some(reward) => { Some(reward) => {
let amount = guard.attempt_convert_to_display_dec_coin(reward.clone().into())?; let amount = guard
log::trace!(" <<< rewards = {:?}, amount = {}", pending_reward, amount); .attempt_convert_to_display_dec_coin(reward.clone().into())
Some(amount) .tap_err(|err| {
let str_err = format!("Failed to get convert reward to a display coin for mix_id = {}. Error: {}", d.mix_id, err);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.ok();
log::trace!(
" <<< rewards = {:?}, amount = {:?}",
pending_reward,
amount
);
amount
} }
None => { None => {
log::trace!(" <<< no rewards waiting"); log::trace!(" <<< no rewards waiting");
@@ -240,7 +317,23 @@ pub async fn get_all_mix_delegations(
}; };
log::trace!(" >>> Get stake saturation: mix_id = {}", d.mix_id); log::trace!(" >>> Get stake saturation: mix_id = {}", d.mix_id);
let stake_saturation = client.nyxd.get_mixnode_stake_saturation(d.mix_id).await?; let stake_saturation = client
.nyxd
.get_mixnode_stake_saturation(d.mix_id)
.await
.tap_err(|err| {
let str_err = format!(
"Failed to get stake saturation for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.unwrap_or(StakeSaturationResponse {
mix_id: d.mix_id,
uncapped_saturation: None,
current_saturation: None,
});
log::trace!(" <<< {:?}", stake_saturation); log::trace!(" <<< {:?}", stake_saturation);
log::trace!( log::trace!(
@@ -251,6 +344,14 @@ pub async fn get_all_mix_delegations(
.nym_api .nym_api
.get_mixnode_avg_uptime(d.mix_id) .get_mixnode_avg_uptime(d.mix_id)
.await .await
.tap_err(|err| {
let str_err = format!(
"Failed to get average uptime percentage for mix_id = {}. Error: {}",
d.mix_id, err
);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
})
.ok() .ok()
.map(|r| r.avg_uptime); .map(|r| r.avg_uptime);
log::trace!(" <<< {:?}", avg_uptime_percent); log::trace!(" <<< {:?}", avg_uptime_percent);
@@ -262,8 +363,13 @@ pub async fn get_all_mix_delegations(
let timestamp = client let timestamp = client
.nyxd .nyxd
.get_block_timestamp(Some(d.height as u32)) .get_block_timestamp(Some(d.height as u32))
.await?; .await
let delegated_on_iso_datetime = timestamp.to_rfc3339(); .tap_err(|err| {
let str_err = format!("Failed to get block timestamp for height = {} for delegation to mix_id = {}. Error: {}", d.height, d.mix_id, err);
log::error!(" <<< {}", str_err);
error_strings.push(str_err);
}).ok();
let delegated_on_iso_datetime = timestamp.map(|ts| ts.to_rfc3339());
log::trace!( log::trace!(
" <<< timestamp = {:?}, delegated_on_iso_datetime = {:?}", " <<< timestamp = {:?}, delegated_on_iso_datetime = {:?}",
timestamp, timestamp,
@@ -301,6 +407,11 @@ pub async fn get_all_mix_delegations(
unclaimed_rewards: accumulated_rewards, unclaimed_rewards: accumulated_rewards,
pending_events, pending_events,
mixnode_is_unbonding, mixnode_is_unbonding,
errors: if error_strings.is_empty() {
None
} else {
Some(error_strings.join("\n"))
},
}) })
} }
log::trace!("<<< {:?}", with_everything); log::trace!("<<< {:?}", with_everything);
@@ -60,10 +60,16 @@ const GatewaySignatureForm = ({
return ( return (
<Stack gap={3} mb={3}> <Stack gap={3} mb={3}>
<Typography variant="body1"> <Typography variant="body1">
Copy below message and sign it with your gateway using the following command Copy the message below and sign it:
<br />
If you are using a nym-gateway:
<br /> <br />
<code>nym-gateway sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code> <code>nym-gateway sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code>
<br /> <br />
If you are using a nym-node:
<br />
<code>nym-node sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code>
<br />
Then paste the signature in the next field. Then paste the signature in the next field.
</Typography> </Typography>
<TextField id="outlined-multiline-static" multiline rows={7} value={message} fullWidth disabled /> <TextField id="outlined-multiline-static" multiline rows={7} value={message} fullWidth disabled />
@@ -61,10 +61,16 @@ const MixnodeSignatureForm = ({
return ( return (
<Stack gap={3} mb={3}> <Stack gap={3} mb={3}>
<Typography variant="body1"> <Typography variant="body1">
Copy below message and sign it with your mix node using the following command Copy the message below and sign it:
<br />
If you are using a nym-mixnode:
<br /> <br />
<code>nym-mixnode sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code> <code>nym-mixnode sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code>
<br /> <br />
If you are using a nym-node:
<br />
<code>nym-node sign --id &lt;your-node-id&gt; --contract-msg &lt;payload-generated-by-the-wallet&gt;</code>
<br />
Then paste the signature in the next field. Then paste the signature in the next field.
</Typography> </Typography>
<TextField id="outlined-multiline-static" multiline rows={7} value={message} fullWidth disabled /> <TextField id="outlined-multiline-static" multiline rows={7} value={message} fullWidth disabled />
@@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { Chip, IconButton, TableCell, TableRow, Tooltip, Typography } from '@mui/material'; import { Box, Chip, IconButton, TableCell, TableRow, Tooltip, Typography } from '@mui/material';
import { Link } from '@nymproject/react/link/Link'; import { Link } from '@nymproject/react/link/Link';
import { decimalToPercentage, DelegationWithEverything } from '@nymproject/types'; import { decimalToPercentage, DelegationWithEverything } from '@nymproject/types';
import { LockOutlined } from '@mui/icons-material'; import { LockOutlined, WarningAmberOutlined } from '@mui/icons-material';
import { isDelegation } from 'src/context/delegations'; import { isDelegation, useDelegationContext } from 'src/context/delegations';
import { toPercentIntegerString } from 'src/utils'; import { toPercentIntegerString } from 'src/utils';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { Undelegate } from 'src/svg-icons'; import { Undelegate } from 'src/svg-icons';
@@ -29,6 +29,8 @@ export const DelegationItem = ({
nodeIsUnbonded: boolean; nodeIsUnbonded: boolean;
onItemActionClick?: (item: DelegationWithEverything, action: DelegationListItemActions) => void; onItemActionClick?: (item: DelegationWithEverything, action: DelegationListItemActions) => void;
}) => { }) => {
const { setDelegationItemErrors } = useDelegationContext();
const operatingCost = isDelegation(item) && item.cost_params?.interval_operating_cost; const operatingCost = isDelegation(item) && item.cost_params?.interval_operating_cost;
const tooltipText = () => { const tooltipText = () => {
@@ -45,13 +47,26 @@ export const DelegationItem = ({
{nodeIsUnbonded ? ( {nodeIsUnbonded ? (
'-' '-'
) : ( ) : (
<Link <Box sx={{ display: 'flex', alignItems: 'center' }}>
target="_blank" {item.errors && (
href={`${explorerUrl}/network-components/mixnode/${item.mix_id}`} <Tooltip title="Open to view a list of errors that occurred">
text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`} <IconButton
color="text.primary" sx={{ mr: 1 }}
noIcon size="small"
/> onClick={() => setDelegationItemErrors({ nodeId: item.node_identity, errors: item.errors! })}
>
<WarningAmberOutlined color="warning" fontSize="small" />
</IconButton>
</Tooltip>
)}
<Link
target="_blank"
href={`${explorerUrl}/network-components/mixnode/${item.mix_id}`}
text={`${item.node_identity.slice(0, 6)}...${item.node_identity.slice(-6)}`}
color="text.primary"
noIcon
/>
</Box>
)} )}
</TableCell> </TableCell>
<TableCell sx={{ color: 'inherit' }}> <TableCell sx={{ color: 'inherit' }}>
@@ -70,7 +85,7 @@ export const DelegationItem = ({
</TableCell> </TableCell>
<TableCell sx={{ color: 'inherit' }}>{getStakeSaturation(item)}</TableCell> <TableCell sx={{ color: 'inherit' }}>{getStakeSaturation(item)}</TableCell>
<TableCell sx={{ color: 'inherit' }}> <TableCell sx={{ color: 'inherit' }}>
{format(new Date(item.delegated_on_iso_datetime), 'dd/MM/yyyy')} {item.delegated_on_iso_datetime && format(new Date(item.delegated_on_iso_datetime), 'dd/MM/yyyy')}
</TableCell> </TableCell>
<TableCell sx={{ color: 'inherit' }}> <TableCell sx={{ color: 'inherit' }}>
<Typography style={{ textTransform: 'uppercase', fontSize: 'inherit' }}> <Typography style={{ textTransform: 'uppercase', fontSize: 'inherit' }}>
@@ -34,6 +34,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: false, uses_vesting_contract_tokens: false,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 2, mix_id: 2,
@@ -57,6 +58,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 3, mix_id: 3,
@@ -80,6 +82,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 4, mix_id: 4,
@@ -103,6 +106,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 5, mix_id: 5,
@@ -126,6 +130,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 6, mix_id: 6,
@@ -149,6 +154,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 7, mix_id: 7,
@@ -172,6 +178,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: false, uses_vesting_contract_tokens: false,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 8, mix_id: 8,
@@ -195,6 +202,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 9, mix_id: 9,
@@ -218,6 +226,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 10, mix_id: 10,
@@ -241,6 +250,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 11, mix_id: 11,
@@ -264,6 +274,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
{ {
mix_id: 12, mix_id: 12,
@@ -287,6 +298,7 @@ export const items: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: true, mixnode_is_unbonding: true,
errors: null,
}, },
]; ];
@@ -8,7 +8,8 @@ import { DelegationListItemActions } from './DelegationActions';
import { DelegationItem } from './DelegationItem'; import { DelegationItem } from './DelegationItem';
import { PendingDelegationItem } from './PendingDelegationItem'; import { PendingDelegationItem } from './PendingDelegationItem';
import { LoadingModal } from '../Modals/LoadingModal'; import { LoadingModal } from '../Modals/LoadingModal';
import { isDelegation, isPendingDelegation, TDelegations } from '../../context/delegations'; import { isDelegation, isPendingDelegation, TDelegations, useDelegationContext } from '../../context/delegations';
import { ErrorModal } from '../Modals/ErrorModal';
export type Order = 'asc' | 'desc'; export type Order = 'asc' | 'desc';
type AdditionalTypes = { profit_margin_percent: number; operating_cost: number }; type AdditionalTypes = { profit_margin_percent: number; operating_cost: number };
@@ -94,6 +95,8 @@ export const DelegationList: FCWithChildren<{
const [order, setOrder] = React.useState<Order>('asc'); const [order, setOrder] = React.useState<Order>('asc');
const [orderBy, setOrderBy] = React.useState<SortingKeys>('delegated_on_iso_datetime'); const [orderBy, setOrderBy] = React.useState<SortingKeys>('delegated_on_iso_datetime');
const { delegationItemErrors, setDelegationItemErrors } = useDelegationContext();
const handleRequestSort = (_: React.MouseEvent<unknown>, property: any) => { const handleRequestSort = (_: React.MouseEvent<unknown>, property: any) => {
const isAsc = orderBy === property && order === 'asc'; const isAsc = orderBy === property && order === 'asc';
setOrder(isAsc ? 'desc' : 'asc'); setOrder(isAsc ? 'desc' : 'asc');
@@ -105,6 +108,12 @@ export const DelegationList: FCWithChildren<{
return ( return (
<TableContainer> <TableContainer>
{isLoading && <LoadingModal text="Please wait. Refreshing..." />} {isLoading && <LoadingModal text="Please wait. Refreshing..." />}
<ErrorModal
open={Boolean(delegationItemErrors)}
title={`Delegation errors for Node ID ${delegationItemErrors?.nodeId || 'unknown'}`}
message={delegationItemErrors?.errors || 'oops'}
onClose={() => setDelegationItemErrors(undefined)}
/>
<Table sx={{ width: '100%' }}> <Table sx={{ width: '100%' }}>
<EnhancedTableHead order={order} orderBy={orderBy} onRequestSort={handleRequestSort} /> <EnhancedTableHead order={order} orderBy={orderBy} onRequestSort={handleRequestSort} />
<TableBody> <TableBody>
+15 -1
View File
@@ -20,6 +20,7 @@ import { decCoinToDisplay } from 'src/utils';
import { Console } from 'src/utils/console'; import { Console } from 'src/utils/console';
export type TDelegationContext = { export type TDelegationContext = {
delegationItemErrors?: { nodeId: string; errors: string };
isLoading: boolean; isLoading: boolean;
delegations?: TDelegations; delegations?: TDelegations;
pendingDelegations?: WrappedDelegationEvent[]; pendingDelegations?: WrappedDelegationEvent[];
@@ -34,6 +35,7 @@ export type TDelegationContext = {
) => Promise<TransactionExecuteResult>; ) => Promise<TransactionExecuteResult>;
undelegate: (mix_id: number, fee?: Fee) => Promise<TransactionExecuteResult>; undelegate: (mix_id: number, fee?: Fee) => Promise<TransactionExecuteResult>;
undelegateVesting: (mix_id: number) => Promise<TransactionExecuteResult>; undelegateVesting: (mix_id: number) => Promise<TransactionExecuteResult>;
setDelegationItemErrors: (data: { nodeId: string; errors: string } | undefined) => void;
}; };
export type TDelegationTransaction = { export type TDelegationTransaction = {
@@ -61,6 +63,7 @@ export const DelegationContext = createContext<TDelegationContext>({
undelegateVesting: () => { undelegateVesting: () => {
throw new Error('Not implemented'); throw new Error('Not implemented');
}, },
setDelegationItemErrors: () => undefined,
}); });
export const DelegationContextProvider: FC<{ export const DelegationContextProvider: FC<{
@@ -69,6 +72,7 @@ export const DelegationContextProvider: FC<{
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
}> = ({ network, children }) => { }> = ({ network, children }) => {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [delegationItemErrors, setDelegationItemErrors] = useState<{ nodeId: string; errors: string }>();
const [delegations, setDelegations] = useState<undefined | TDelegations>(); const [delegations, setDelegations] = useState<undefined | TDelegations>();
const [totalDelegations, setTotalDelegations] = useState<undefined | string>(); const [totalDelegations, setTotalDelegations] = useState<undefined | string>();
const [totalRewards, setTotalRewards] = useState<undefined | string>(); const [totalRewards, setTotalRewards] = useState<undefined | string>();
@@ -130,6 +134,7 @@ export const DelegationContextProvider: FC<{
const memoizedValue = useMemo( const memoizedValue = useMemo(
() => ({ () => ({
delegationItemErrors,
isLoading, isLoading,
delegations, delegations,
pendingDelegations, pendingDelegations,
@@ -137,11 +142,20 @@ export const DelegationContextProvider: FC<{
totalRewards, totalRewards,
totalDelegationsAndRewards, totalDelegationsAndRewards,
refresh, refresh,
setDelegationItemErrors,
addDelegation, addDelegation,
undelegate: undelegateFromMixnode, undelegate: undelegateFromMixnode,
undelegateVesting: vestingUndelegateFromMixnode, undelegateVesting: vestingUndelegateFromMixnode,
}), }),
[isLoading, delegations, pendingDelegations, totalDelegations, totalRewards, totalDelegationsAndRewards], [
isLoading,
delegations,
delegationItemErrors,
pendingDelegations,
totalDelegations,
totalRewards,
totalDelegationsAndRewards,
],
); );
return <DelegationContext.Provider value={memoizedValue}>{children}</DelegationContext.Provider>; return <DelegationContext.Provider value={memoizedValue}>{children}</DelegationContext.Provider>;
@@ -37,6 +37,7 @@ let mockDelegations: DelegationWithEverything[] = [
uses_vesting_contract_tokens: false, uses_vesting_contract_tokens: false,
pending_events: [], pending_events: [],
mixnode_is_unbonding: false, mixnode_is_unbonding: false,
errors: null,
}, },
{ {
mix_id: 5678, mix_id: 5678,
@@ -60,6 +61,7 @@ let mockDelegations: DelegationWithEverything[] = [
uses_vesting_contract_tokens: true, uses_vesting_contract_tokens: true,
pending_events: [], pending_events: [],
mixnode_is_unbonding: false, mixnode_is_unbonding: false,
errors: null,
}, },
]; ];
@@ -69,6 +71,7 @@ export const MockDelegationContextProvider: FCWithChildren = ({ children }) => {
const [error, setError] = useState<string>(); const [error, setError] = useState<string>();
const [delegations, setDelegations] = useState<undefined | DelegationWithEverything[]>(); const [delegations, setDelegations] = useState<undefined | DelegationWithEverything[]>();
const [totalDelegations, setTotalDelegations] = useState<undefined | string>(); const [totalDelegations, setTotalDelegations] = useState<undefined | string>();
const [delegationItemErrors, setDelegationItemErrors] = useState<{ nodeId: string; errors: string }>();
const triggerStateUpdate = () => setTrigger(new Date()); const triggerStateUpdate = () => setTrigger(new Date());
@@ -230,6 +233,8 @@ export const MockDelegationContextProvider: FCWithChildren = ({ children }) => {
const memoizedValue = useMemo( const memoizedValue = useMemo(
() => ({ () => ({
delegationItemErrors,
setDelegationItemErrors,
isLoading, isLoading,
error, error,
delegations, delegations,
+1 -1
View File
@@ -101,7 +101,7 @@ export const Delegation: FC<{ isStorybook?: boolean }> = ({ isStorybook }) => {
// Refresh the rewards and delegations periodically when page is mounted // Refresh the rewards and delegations periodically when page is mounted
useEffect(() => { useEffect(() => {
const timer = setInterval(refreshWithIntervalUpdate, 1 * 60 * 1000); // every 1 minute const timer = setInterval(refreshWithIntervalUpdate, 5 * 60 * 1000); // every 5 minutes
return () => clearInterval(timer); return () => clearInterval(timer);
}, []); }, []);
@@ -112,41 +112,18 @@ pub(crate) struct OverrideConfig {
// NOTE: make sure this is in sync with `gateway/src/helpers.rs::override_network_requester_config` // NOTE: make sure this is in sync with `gateway/src/helpers.rs::override_network_requester_config`
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config { pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
// as of 12.09.23 the below is true (not sure how this comment will rot in the future) // in the old code we had calls to `assert` thus panicking
// medium_toggle: config
// - sets secondary packet size to 16kb .base
// - disables poisson distribution of the main traffic stream .try_apply_traffic_modes(
// - sets the cover traffic stream to 1 packet / 5s (on average) config.network_requester.disable_poisson_rate,
// - disables per hop delay args.medium_toggle,
// args.fastmode,
// fastmode (to be renamed to `fast-poisson`): args.no_cover,
// - sets average per hop delay to 10ms )
// - sets the cover traffic stream to 1 packet / 2000s (on average); for all intents and purposes it disables the stream .expect("failed to apply traffic modes");
// - sets the poisson distribution of the main traffic stream to 4ms, i.e. 250 packets / s on average
//
// no_cover:
// - disables poisson distribution of the main traffic stream
// - disables the secondary cover traffic stream
// disable poisson rate in the BASE client if the NR option is enabled
if config.network_requester.disable_poisson_rate {
config.set_no_poisson_process();
}
// those should be enforced by `clap` when parsing the arguments
if args.medium_toggle {
assert!(!args.fastmode);
assert!(!args.no_cover);
config.set_medium_toggle();
}
config config
.with_base(
BaseClientConfig::with_high_default_traffic_volume,
args.fastmode,
)
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_optional_base_custom_env( .with_optional_base_custom_env(
BaseClientConfig::with_custom_nym_apis, BaseClientConfig::with_custom_nym_apis,
args.nym_apis, args.nym_apis,
@@ -12,7 +12,6 @@ use nym_config::{
}; };
use nym_network_defaults::mainnet; use nym_network_defaults::mainnet;
use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR; use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
use nym_sphinx::params::PacketSize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -149,20 +148,6 @@ impl Config {
self.base.validate() self.base.validate()
} }
/// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc.
#[doc(hidden)]
pub fn set_medium_toggle(&mut self) {
self.base.set_no_cover_traffic_with_keepalive();
self.base.set_no_per_hop_delays();
self.base.debug.traffic.secondary_packet_size = Some(PacketSize::ExtendedPacket16);
}
#[doc(hidden)]
pub fn set_no_poisson_process(&mut self) {
self.base.set_no_poisson_process()
}
#[must_use] #[must_use]
pub fn with_open_proxy(mut self, open_proxy: bool) -> Self { pub fn with_open_proxy(mut self, open_proxy: bool) -> Self {
self.network_requester.open_proxy = open_proxy; self.network_requester.open_proxy = open_proxy;
@@ -182,6 +167,7 @@ impl Config {
} }
// poor man's 'builder' method // poor man's 'builder' method
#[allow(unused)]
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
where where
F: Fn(BaseClientConfig, T) -> BaseClientConfig, F: Fn(BaseClientConfig, T) -> BaseClientConfig,
@@ -11,7 +11,7 @@ export interface DelegationWithEverything {
accumulated_by_delegates: DecCoin | null; accumulated_by_delegates: DecCoin | null;
accumulated_by_operator: DecCoin | null; accumulated_by_operator: DecCoin | null;
block_height: bigint; block_height: bigint;
delegated_on_iso_datetime: string; delegated_on_iso_datetime: string | null;
cost_params: MixNodeCostParams | null; cost_params: MixNodeCostParams | null;
avg_uptime_percent: number | null; avg_uptime_percent: number | null;
stake_saturation: string | null; stake_saturation: string | null;
@@ -19,4 +19,5 @@ export interface DelegationWithEverything {
unclaimed_rewards: DecCoin | null; unclaimed_rewards: DecCoin | null;
pending_events: Array<DelegationEvent>; pending_events: Array<DelegationEvent>;
mixnode_is_unbonding: boolean | null; mixnode_is_unbonding: boolean | null;
errors: string | null;
} }