Compare commits

...

12 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
Jędrzej Stuczyński 0af807ac92 fixed overflow subtraction 2024-05-07 12:14:20 +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
49 changed files with 1404 additions and 527 deletions
Generated
+195 -67
View File
@@ -543,11 +543,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
"axum-core",
"axum-core 0.3.4",
"bitflags 1.3.2",
"bytes",
"futures-util",
"headers",
"http 0.2.9",
"http-body 0.4.5",
"hyper 0.14.27",
@@ -559,14 +558,44 @@ dependencies = [
"pin-project-lite 0.2.13",
"rustversion",
"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_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"sync_wrapper 1.0.1",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
@@ -586,6 +615,50 @@ dependencies = [
"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]]
name = "backtrace"
version = "0.3.69"
@@ -631,6 +704,12 @@ version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -2569,7 +2648,7 @@ dependencies = [
"rand 0.8.5",
"rand_pcg 0.3.1",
"rand_seeder",
"reqwest",
"reqwest 0.12.4",
"rocket",
"rocket_cors",
"rocket_okapi",
@@ -3203,14 +3282,14 @@ dependencies = [
[[package]]
name = "headers"
version = "0.3.9"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
dependencies = [
"base64 0.21.4",
"bytes",
"headers-core",
"http 0.2.9",
"http 1.1.0",
"httpdate",
"mime",
"sha1",
@@ -3218,11 +3297,11 @@ dependencies = [
[[package]]
name = "headers-core"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
"http 0.2.9",
"http 1.1.0",
]
[[package]]
@@ -3404,9 +3483,9 @@ dependencies = [
[[package]]
name = "http-range-header"
version = "0.3.1"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a"
[[package]]
name = "httparse"
@@ -3481,9 +3560,9 @@ dependencies = [
[[package]]
name = "hyper"
version = "1.2.0"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a"
checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d"
dependencies = [
"bytes",
"futures-channel",
@@ -3496,6 +3575,7 @@ dependencies = [
"pin-project-lite 0.2.13",
"smallvec",
"tokio",
"want",
]
[[package]]
@@ -3531,13 +3611,17 @@ 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.2.0",
"hyper 1.3.1",
"pin-project-lite 0.2.13",
"socket2 0.5.4",
"tokio",
"tower",
"tower-service",
"tracing",
]
[[package]]
@@ -3805,7 +3889,7 @@ dependencies = [
"socket2 0.5.4",
"widestring",
"windows-sys 0.48.0",
"winreg",
"winreg 0.50.0",
]
[[package]]
@@ -5077,7 +5161,7 @@ dependencies = [
"rand 0.8.5",
"rand_chacha 0.2.2",
"rand_chacha 0.3.1",
"reqwest",
"reqwest 0.12.4",
"rocket",
"rocket_cors",
"rocket_okapi",
@@ -5315,7 +5399,7 @@ dependencies = [
"gloo-timers",
"http-body-util",
"humantime-serde",
"hyper 1.2.0",
"hyper 1.3.1",
"hyper-util",
"log",
"nym-bandwidth-controller",
@@ -5649,7 +5733,7 @@ dependencies = [
name = "nym-exit-policy"
version = "0.1.0"
dependencies = [
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"thiserror",
@@ -5675,7 +5759,7 @@ version = "0.1.0"
dependencies = [
"log",
"nym-explorer-api-requests",
"reqwest",
"reqwest 0.12.4",
"serde",
"thiserror",
"tokio",
@@ -5810,7 +5894,7 @@ name = "nym-http-api-client"
version = "0.1.0"
dependencies = [
"async-trait",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"thiserror",
@@ -5823,7 +5907,7 @@ dependencies = [
name = "nym-http-api-common"
version = "0.1.0"
dependencies = [
"axum",
"axum 0.7.5",
"bytes",
"mime",
"serde",
@@ -5912,7 +5996,7 @@ dependencies = [
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"tap",
@@ -5982,7 +6066,7 @@ name = "nym-mixnode"
version = "1.1.37"
dependencies = [
"anyhow",
"axum",
"axum 0.7.5",
"bs58 0.5.0",
"clap 4.4.7",
"colored",
@@ -6134,7 +6218,7 @@ dependencies = [
"publicsuffix",
"rand 0.7.3",
"regex",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"sqlx",
@@ -6211,12 +6295,14 @@ dependencies = [
name = "nym-node-http-api"
version = "0.1.0"
dependencies = [
"axum",
"axum 0.7.5",
"axum-extra",
"colored",
"dashmap",
"fastrand 2.0.1",
"headers",
"hmac 0.12.1",
"hyper 0.14.27",
"hyper 1.3.1",
"ipnetwork 0.16.0",
"nym-crypto",
"nym-http-api-common",
@@ -6396,7 +6482,7 @@ dependencies = [
"parking_lot 0.12.1",
"pretty_env_logger",
"rand 0.7.3",
"reqwest",
"reqwest 0.12.4",
"tap",
"thiserror",
"tokio",
@@ -6491,7 +6577,7 @@ dependencies = [
"nym-validator-client",
"pin-project",
"rand 0.7.3",
"reqwest",
"reqwest 0.12.4",
"schemars",
"serde",
"tap",
@@ -6708,7 +6794,7 @@ version = "1.0.1"
dependencies = [
"async-trait",
"log",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"sqlx",
@@ -6797,7 +6883,7 @@ dependencies = [
"nym-mixnet-contract-common",
"nym-validator-client",
"nym-vesting-contract-common",
"reqwest",
"reqwest 0.12.4",
"schemars",
"serde",
"serde_json",
@@ -6847,7 +6933,7 @@ dependencies = [
"nym-service-provider-directory-common",
"nym-vesting-contract-common",
"prost 0.12.1",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"sha2 0.9.9",
@@ -6978,7 +7064,7 @@ dependencies = [
"nym-bin-common",
"nym-config",
"nym-task",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"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)",
"eyre",
"futures",
"nym-bin-common",
"humantime 2.1.0",
"serde",
"sha2 0.10.8",
"sqlx",
"tendermint",
@@ -8327,6 +8414,41 @@ dependencies = [
"system-configuration",
"tokio",
"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-util",
"tower-service",
@@ -8335,7 +8457,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"winreg",
"winreg 0.52.0",
]
[[package]]
@@ -8576,9 +8698,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "6.8.1"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661"
checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@@ -8587,23 +8709,22 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "6.8.1"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac"
checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"shellexpand",
"syn 2.0.58",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "7.8.1"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74"
checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581"
dependencies = [
"sha2 0.10.8",
"walkdir",
@@ -9209,15 +9330,6 @@ dependencies = [
"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]]
name = "si-scale"
version = "0.2.2"
@@ -9730,6 +9842,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sync_wrapper"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "synstructure"
version = "0.12.6"
@@ -9900,7 +10018,7 @@ dependencies = [
"getrandom 0.2.10",
"peg",
"pin-project",
"reqwest",
"reqwest 0.11.22",
"semver 1.0.22",
"serde",
"serde_bytes",
@@ -10262,7 +10380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
dependencies = [
"async-trait",
"axum",
"axum 0.6.20",
"base64 0.21.4",
"bytes",
"futures-core",
@@ -10305,16 +10423,16 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.4.4"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
dependencies = [
"bitflags 2.4.1",
"bytes",
"futures-core",
"futures-util",
"http 0.2.9",
"http-body 0.4.5",
"http 1.1.0",
"http-body 1.0.0",
"http-body-util",
"http-range-header",
"httpdate",
"mime",
@@ -10812,9 +10930,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "utoipa"
version = "3.5.0"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a"
checksum = "272ebdfbc99111033031d2f10e018836056e4d2c8e2acda76450ec7974269fa7"
dependencies = [
"indexmap 2.0.2",
"serde",
@@ -10824,9 +10942,9 @@ dependencies = [
[[package]]
name = "utoipa-gen"
version = "3.5.0"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c"
checksum = "d3c9f4d08338c1bfa70dde39412a040a884c6f318b3d09aaaf3437a1e52027fc"
dependencies = [
"proc-macro-error",
"proc-macro2",
@@ -10837,11 +10955,11 @@ dependencies = [
[[package]]
name = "utoipa-swagger-ui"
version = "3.1.5"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653"
checksum = "0b39868d43c011961e04b41623e050aedf2cc93652562ff7935ce0f819aaf2da"
dependencies = [
"axum",
"axum 0.7.5",
"mime_guess",
"regex",
"rust-embed",
@@ -11089,9 +11207,9 @@ dependencies = [
[[package]]
name = "wasm-streams"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
@@ -11704,6 +11822,16 @@ dependencies = [
"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]]
name = "with_builtin_macros"
version = "0.0.3"
+7 -5
View File
@@ -160,7 +160,8 @@ license = "Apache-2.0"
[workspace.dependencies]
anyhow = "1.0.71"
async-trait = "0.1.68"
axum = "0.6.20"
axum = "0.7.5"
axum-extra = "0.9.3"
base64 = "0.21.4"
bs58 = "0.5.0"
bip39 = { version = "2.0.0", features = ["zeroize"] }
@@ -171,15 +172,16 @@ dotenvy = "0.15.6"
futures = "0.3.28"
generic-array = "0.14.7"
getrandom = "0.2.10"
headers = "0.4.0"
humantime-serde = "1.1.1"
hyper = "0.14.27"
hyper = "1.3.1"
k256 = "0.13"
lazy_static = "1.4.0"
log = "0.4"
once_cell = "1.7.2"
parking_lot = "0.12.1"
rand = "0.8.5"
reqwest = { version = "0.11.22", default-features = false }
reqwest = { version = "0.12.4", default-features = false }
schemars = "0.8.1"
serde = "1.0.152"
serde_json = "1.0.91"
@@ -193,8 +195,8 @@ tokio-tungstenite = { version = "0.20.1" }
tracing = "0.1.37"
tungstenite = { version = "0.20.1", default-features = false }
ts-rs = "7.0.0"
utoipa = "3.5.0"
utoipa-swagger-ui = "3.1.5"
utoipa = "4.2.0"
utoipa-swagger-ui = "6.0.0"
url = "2.4"
zeroize = "1.6.0"
+2 -2
View File
@@ -3,7 +3,7 @@ name = "nym-client-core"
version = "1.1.15"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.66"
rust-version = "1.70"
license.workspace = true
# 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-credential-storage = { path = "../credential-storage" }
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-gateways-storage = { path = "./gateways-storage" }
@@ -157,7 +157,7 @@ async fn fetch_delegation_data(
// If a pending undelegate tx is found, remove it from delegation map
Undelegate { owner, mix_id, .. } => {
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());
}
@@ -328,4 +328,8 @@ impl EpochState {
pub fn is_dealing_exchange(&self) -> bool {
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;
pub use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, hash_to_scalar, keygen,
prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign, hash_to_scalar,
keygen, prepare_blind_sign, prove_bandwidth_credential, verify_credential, Attribute, Base58,
BlindSignRequest, BlindedSerialNumber, BlindedSignature, Bytable, CoconutError, KeyPair,
Parameters, PrivateAttribute, PublicAttribute, SecretKey, Signature, SignatureShare,
VerificationKey, VerifyCredentialRequest,
@@ -10,18 +10,19 @@ use crate::coconut::bandwidth::{
use crate::coconut::utils::scalar_serde_helper;
use crate::error::Error;
use nym_credentials_interface::{
aggregate_signature_shares, hash_to_scalar, prepare_blind_sign, Attribute, BlindedSerialNumber,
BlindedSignature, Parameters, PrivateAttribute, PublicAttribute, Signature, SignatureShare,
VerificationKey,
aggregate_signature_shares_and_verify, hash_to_scalar, prepare_blind_sign, Attribute,
BlindedSerialNumber, BlindedSignature, Parameters, PrivateAttribute, PublicAttribute,
Signature, SignatureShare, VerificationKey,
};
use nym_crypto::asymmetric::{encryption, identity};
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::{Coin, Hash};
use nym_validator_client::signing::AccountData;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use zeroize::{Zeroize, ZeroizeOnDrop};
pub use nym_validator_client::nyxd::{Coin, Hash};
#[derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub enum BandwidthCredentialIssuanceDataVariant {
Voucher(BandwidthVoucherIssuanceData),
@@ -279,7 +280,7 @@ impl IssuanceBandwidthCredential {
attributes.extend_from_slice(&private_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)
}
@@ -6,7 +6,7 @@ use crate::coconut::utils::scalar_serde_helper;
use crate::error::Error;
use nym_api_requests::coconut::BlindSignRequestBody;
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_validator_client::nyxd::{Coin, Hash};
@@ -123,6 +123,10 @@ impl BandwidthVoucherIssuanceData {
&self.value_prehashed
}
pub fn typ() -> CredentialType {
CredentialType::Voucher
}
pub fn tx_hash(&self) -> Hash {
self.deposit_tx_hash
}
+5 -5
View File
@@ -6,10 +6,10 @@ use criterion::{criterion_group, criterion_main, Criterion};
use ff::Field;
use group::{Curve, Group};
use nym_coconut::{
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen, verify_credential,
verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature,
SignatureShare, VerificationKey,
aggregate_signature_shares_and_verify, aggregate_verification_keys, blind_sign,
prepare_blind_sign, prove_bandwidth_credential, random_scalars_refs, setup, ttp_keygen,
verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters,
Signature, SignatureShare, VerificationKey,
};
use rand::seq::SliceRandom;
use std::ops::Neg;
@@ -99,7 +99,7 @@ fn unblind_and_aggregate(
let mut attributes = vec![];
attributes.extend_from_slice(private_attributes);
attributes.extend_from_slice(public_attributes);
aggregate_signature_shares(
aggregate_signature_shares_and_verify(
params,
verification_key,
&attributes,
+7
View File
@@ -4,14 +4,18 @@
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
pub use bls12_381::Scalar;
pub use elgamal::elgamal_keygen;
pub use elgamal::ElGamalKeyPair;
pub use elgamal::PublicKey;
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_and_verify;
pub use scheme::aggregation::aggregate_verification_keys;
pub use scheme::issuance::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::BlindSignRequest;
pub use scheme::keygen::keygen;
@@ -19,16 +23,19 @@ pub use scheme::keygen::ttp_keygen;
pub use scheme::keygen::KeyPair;
pub use scheme::keygen::SecretKey;
pub use scheme::keygen::VerificationKey;
pub use scheme::keygen::VerificationKeyShare;
pub use scheme::setup::setup;
pub use scheme::setup::Parameters;
pub use scheme::verification::check_vk_pairing;
pub use scheme::verification::prove_bandwidth_credential;
pub use scheme::verification::verify;
pub use scheme::verification::verify_credential;
pub use scheme::verification::BlindedSerialNumber;
pub use scheme::verification::VerifyCredentialRequest;
pub use scheme::BlindedSignature;
pub use scheme::Signature;
pub use scheme::SignatureShare;
pub use scheme::SignerIndex;
pub use traits::Base58;
pub use traits::Bytable;
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::{PartialSignature, Signature, SignatureShare, SignerIndex, VerificationKey};
use crate::utils::perform_lagrangian_interpolation_at_origin;
use crate::{Attribute, Parameters};
use crate::{Attribute, Parameters, VerificationKeyShare};
pub(crate) trait Aggregatable: Sized {
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
@@ -80,7 +80,23 @@ pub fn aggregate_verification_keys(
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(
signatures: &[PartialSignature],
indices: Option<&[SignerIndex]>,
) -> Result<Signature> {
Aggregatable::aggregate(signatures, indices)
}
pub fn aggregate_signatures_and_verify(
params: &Parameters,
verification_key: &VerificationKey,
attributes: &[&Attribute],
@@ -88,11 +104,7 @@ pub fn aggregate_signatures(
indices: Option<&[SignerIndex]>,
) -> Result<Signature> {
// aggregate the signature
let signature = match Aggregatable::aggregate(signatures, indices) {
Ok(res) => res,
Err(err) => return Err(err),
};
let signature = aggregate_signatures(signatures, indices)?;
// Verify the signature
let alpha = verification_key.alpha;
@@ -116,7 +128,16 @@ pub fn aggregate_signatures(
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,
verification_key: &VerificationKey,
attributes: &[&Attribute],
@@ -127,7 +148,7 @@ pub fn aggregate_signature_shares(
.map(|share| (*share.signature(), share.index()))
.unzip();
aggregate_signatures(
aggregate_signatures_and_verify(
params,
verification_key,
attributes,
@@ -210,7 +231,7 @@ mod tests {
#[test]
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);
let keypairs = ttp_keygen(&params, 3, 5).unwrap();
@@ -227,12 +248,12 @@ mod tests {
let sigs = sks
.iter()
.map(|sk| sign(&mut params, sk, &attributes).unwrap())
.map(|sk| sign(&params, sk, &attributes).unwrap())
.collect::<Vec<_>>();
// aggregating (any) threshold works
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,
&aggr_vk_1,
&attributes,
@@ -242,7 +263,7 @@ mod tests {
.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,
&aggr_vk_1,
&attributes,
@@ -258,7 +279,7 @@ mod tests {
// aggregating threshold+1 works
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,
&aggr_vk_more,
&attributes,
@@ -270,7 +291,7 @@ mod tests {
// aggregating all
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,
&aggr_vk_all,
&attributes,
@@ -282,7 +303,7 @@ mod tests {
// 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_not_enough = aggregate_signatures(
let aggr_not_enough = aggregate_signatures_and_verify(
&params,
&aggr_vk_not_enough,
&attributes,
@@ -294,7 +315,7 @@ mod tests {
// taking wrong index should fail
let aggr_vk_bad = aggregate_verification_keys(&vks[2..], Some(&[1, 2, 3])).unwrap();
assert!(aggregate_signatures(
assert!(aggregate_signatures_and_verify(
&params,
&aggr_vk_bad,
&attributes,
@@ -330,9 +351,14 @@ mod tests {
.unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!(
aggregate_signatures(&params, &aggr_vk_all, &attributes, &signatures, None).is_err()
);
assert!(aggregate_signatures_and_verify(
&params,
&aggr_vk_all,
&attributes,
&signatures,
None
)
.is_err());
}
#[test]
@@ -352,11 +378,15 @@ mod tests {
.unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!(
aggregate_signatures(&params, &aggr_vk_all, &attributes, &signatures, Some(&[]))
.is_err()
);
assert!(aggregate_signatures(
assert!(aggregate_signatures_and_verify(
&params,
&aggr_vk_all,
&attributes,
&signatures,
Some(&[])
)
.is_err());
assert!(aggregate_signatures_and_verify(
&params,
&aggr_vk_all,
&attributes,
@@ -383,7 +413,7 @@ mod tests {
.unzip();
let aggr_vk_all = aggregate_verification_keys(&vks, None).unwrap();
assert!(aggregate_signatures(
assert!(aggregate_signatures_and_verify(
&params,
&aggr_vk_all,
&attributes,
+7 -4
View File
@@ -13,9 +13,8 @@ use crate::scheme::setup::Parameters;
use crate::scheme::BlindedSignature;
use crate::scheme::SecretKey;
use crate::Attribute;
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
#[cfg(test)]
use crate::Signature;
// TODO: possibly completely remove those two functions.
// They only exist to have a simpler and smaller code snippets to test
// 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 {
self.commitment_hash
}
@@ -426,9 +429,9 @@ pub fn verify_partial_blind_signature(
.into()
}
#[cfg(test)]
/// Creates a Coconut Signature under a given secret key on a set of public attributes only.
pub fn sign(
params: &mut Parameters,
params: &Parameters,
secret_key: &SecretKey,
public_attributes: &[&Attribute],
) -> Result<Signature> {
+28 -8
View File
@@ -151,10 +151,6 @@ impl Base58 for SecretKey {}
// TODO: perhaps change points to affine representation
// to make verification slightly more efficient?
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(
feature = "key-zeroize",
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
)]
pub struct VerificationKey {
// TODO add gen2 as per the paper or imply it from the fact library is using bls381?
pub(crate) alpha: G2Projective,
@@ -411,12 +407,23 @@ impl Bytable 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)]
#[cfg_attr(test, derive(PartialEq, Eq, Clone))]
#[cfg_attr(
feature = "key-zeroize",
derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop)
)]
pub struct KeyPair {
secret_key: SecretKey,
verification_key: VerificationKey,
@@ -425,6 +432,12 @@ pub struct KeyPair {
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 {
type PrivatePemKey = SecretKey;
type PublicPemKey = VerificationKey;
@@ -461,6 +474,13 @@ impl KeyPair {
&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> {
// 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()
+31 -13
View File
@@ -70,6 +70,11 @@ impl Signature {
&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) {
let r = params.random_scalar();
let r_prime = params.random_scalar();
@@ -191,7 +196,7 @@ impl BlindedSignature {
&self,
partial_verification_key: &VerificationKey,
pedersen_commitments_openings: &[Scalar],
) -> Result<Signature> {
) -> Signature {
// parse the signature
let h = &self.0;
let c = &self.1;
@@ -204,7 +209,7 @@ impl BlindedSignature {
let unblinded_c = c - blinding_removers;
Ok(Signature(*h, unblinded_c))
Signature(*h, unblinded_c)
}
pub fn unblind_and_verify(
@@ -216,7 +221,7 @@ impl BlindedSignature {
commitment_hash: &G1Projective,
pedersen_commitments_openings: &[Scalar],
) -> Result<Signature> {
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings)?;
let unblinded = self.unblind(partial_verification_key, pedersen_commitments_openings);
unblinded.verify(
params,
partial_verification_key,
@@ -240,6 +245,7 @@ impl BlindedSignature {
}
// perhaps this should take signature by reference? we'll see how it goes
#[derive(Clone, Copy)]
pub struct SignatureShare {
signature: Signature,
index: SignerIndex,
@@ -276,7 +282,9 @@ impl SignatureShare {
mod tests {
use super::*;
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::keygen::{keygen, ttp_keygen};
use crate::scheme::verification::{prove_bandwidth_credential, verify, verify_credential};
@@ -418,13 +426,13 @@ mod tests {
#[test]
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);
let keypair1 = keygen(&params);
let keypair2 = keygen(&params);
let sig1 = sign(&mut params, keypair1.secret_key(), &attributes).unwrap();
let sig2 = sign(&mut params, keypair2.secret_key(), &attributes).unwrap();
let sig1 = sign(&params, keypair1.secret_key(), &attributes).unwrap();
let sig2 = sign(&params, keypair2.secret_key(), &attributes).unwrap();
assert!(verify(
&params,
@@ -568,9 +576,14 @@ mod tests {
attributes.extend_from_slice(&public_attributes);
let aggr_vk = aggregate_verification_keys(&vks[..2], Some(&[1, 2])).unwrap();
let aggr_sig =
aggregate_signatures(&params, &aggr_vk, &attributes, &sigs[..2], Some(&[1, 2]))
.unwrap();
let aggr_sig = aggregate_signatures_and_verify(
&params,
&aggr_vk,
&attributes,
&sigs[..2],
Some(&[1, 2]),
)
.unwrap();
let theta = prove_bandwidth_credential(
&params,
@@ -590,9 +603,14 @@ mod tests {
// taking different subset of keys and credentials
let aggr_vk = aggregate_verification_keys(&vks[1..], Some(&[2, 3])).unwrap();
let aggr_sig =
aggregate_signatures(&params, &aggr_vk, &attributes, &sigs[1..], Some(&[2, 3]))
.unwrap();
let aggr_sig = aggregate_signatures_and_verify(
&params,
&aggr_vk,
&attributes,
&sigs[1..],
Some(&[2, 3]),
)
.unwrap();
let theta = prove_bandwidth_credential(
&params,
+1
View File
@@ -10,6 +10,7 @@ use crate::error::{CoconutError, Result};
use crate::utils::hash_g1;
/// System-wide parameters used for the protocol
#[derive(Clone)]
pub struct Parameters {
/// Generator of the G1 group
g1: G1Affine,
@@ -288,7 +288,6 @@ pub fn verify_credential(
}
// Used in tests only
#[cfg(test)]
pub fn verify(
params: &Parameters,
verification_key: &VerificationKey,
+6 -2
View File
@@ -75,8 +75,12 @@ pub fn theta_from_keys_and_attributes(
attributes.extend_from_slice(public_attributes);
// Randomize credentials and generate any cryptographic material to verify them
let signature =
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?;
let signature = aggregate_signature_shares_and_verify(
params,
&verification_key,
&attributes,
&signature_shares,
)?;
// Generate cryptographic material to verify them
let theta = prove_bandwidth_credential(
+4 -2
View File
@@ -16,7 +16,9 @@ const_format = "0.2.32"
cosmrs.workspace = true
eyre = "0.6.9"
futures.workspace = true
humantime = "2.1.0"
sha2 = "0.10.8"
serde = { workspace = true, features = ["derive"] }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] }
tendermint.workspace = true
tendermint-rpc = { workspace = true, features = ["websocket-client", "http-client"] }
@@ -24,13 +26,13 @@ thiserror.workspace = true
time = { workspace = true }
tokio = { workspace = true, features = ["full"] }
tokio-stream = "0.1.14"
tokio-util = { version = "0.7.10", features = ["rt"]}
tokio-util = { version = "0.7.10", features = ["rt"] }
tracing.workspace = true
url.workspace = true
# TEMP
nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
#nym-bin-common = { path = "../bin-common", features = ["basic_tracing"]}
[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::rpc_client::RpcClient;
use crate::storage::{persist_block, ScraperStorage};
use crate::PruningOptions;
use futures::StreamExt;
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::ops::{Add, Range};
@@ -18,9 +19,10 @@ use tokio::sync::Notify;
use tokio::time::{interval_at, Instant};
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_util::sync::CancellationToken;
use tracing::{debug, error, info, warn};
use tracing::{debug, error, info, instrument, trace, warn};
mod helpers;
pub(crate) mod pruning;
pub(crate) mod types;
const MISSING_BLOCKS_CHECK_INTERVAL: Duration = Duration::from_secs(30);
@@ -40,9 +42,11 @@ impl PendingSync {
}
pub struct BlockProcessor {
pruning_options: PruningOptions,
cancel: CancellationToken,
synced: Arc<Notify>,
last_processed_height: u32,
last_pruned_height: u32,
last_processed_at: Instant,
pending_sync: PendingSync,
queued_blocks: BTreeMap<u32, BlockToProcess>,
@@ -62,6 +66,7 @@ pub struct BlockProcessor {
impl BlockProcessor {
pub async fn new(
pruning_options: PruningOptions,
cancel: CancellationToken,
synced: Arc<Notify>,
incoming: UnboundedReceiver<BlockToProcess>,
@@ -70,11 +75,17 @@ impl BlockProcessor {
rpc_client: RpcClient,
) -> Result<Self, ScraperError> {
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 {
pruning_options,
cancel,
synced,
last_processed_height: last_processed.try_into().unwrap_or_default(),
last_processed_height,
last_pruned_height,
last_processed_at: Instant::now(),
pending_sync: Default::default(),
queued_blocks: Default::default(),
@@ -131,12 +142,17 @@ impl BlockProcessor {
}
}
let commit_start = Instant::now();
tx.commit()
.await
.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_at = Instant::now();
if let Err(err) = self.maybe_prune_storage().await {
error!("failed to prune the storage: {err}");
}
Ok(())
}
@@ -210,6 +226,61 @@ impl BlockProcessor {
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) {
let height = block.height;
@@ -279,6 +350,8 @@ impl BlockProcessor {
async fn startup_resync(&mut self) -> Result<(), ScraperError> {
assert!(self.pending_sync.is_empty());
self.maybe_prune_storage().await?;
let latest_block = self.rpc_client.current_block_height().await? as u32;
if latest_block > self.last_processed_height && self.last_processed_height != 0 {
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>
// SPDX-License-Identifier: Apache-2.0
use crate::block_processor::pruning::{
EVERYTHING_PRUNING_INTERVAL, EVERYTHING_PRUNING_KEEP_RECENT,
};
use tendermint::Hash;
use thiserror::Error;
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"
)]
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 {
+1
View File
@@ -14,6 +14,7 @@ pub(crate) mod rpc_client;
pub(crate) mod scraper;
pub mod storage;
pub use block_processor::pruning::{PruningOptions, PruningStrategy};
pub use modules::{BlockModule, MsgModule, TxModule};
pub use scraper::{Config, NyxdScraper};
pub use storage::models;
+6
View File
@@ -8,6 +8,7 @@ use crate::modules::{BlockModule, MsgModule, TxModule};
use crate::rpc_client::RpcClient;
use crate::scraper::subscriber::ChainSubscriber;
use crate::storage::ScraperStorage;
use crate::PruningOptions;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::mpsc::{channel, unbounded_channel};
@@ -27,6 +28,8 @@ pub struct Config {
pub rpc_url: Url,
pub database_path: PathBuf,
pub pruning_options: PruningOptions,
}
pub struct NyxdScraperBuilder {
@@ -54,6 +57,7 @@ impl NyxdScraperBuilder {
processing_tx.clone(),
);
let mut block_processor = BlockProcessor::new(
scraper.config.pruning_options,
scraper.cancel_token.clone(),
scraper.startup_sync.clone(),
processing_rx,
@@ -119,6 +123,7 @@ impl NyxdScraper {
}
pub async fn new(config: Config) -> Result<Self, ScraperError> {
config.pruning_options.validate()?;
let storage = ScraperStorage::init(&config.database_path).await?;
Ok(NyxdScraper {
@@ -160,6 +165,7 @@ impl NyxdScraper {
processing_tx.clone(),
);
let block_processor = BlockProcessor::new(
self.config.pruning_options,
self.cancel_token.clone(),
self.startup_sync.clone(),
processing_rx,
+191 -11
View File
@@ -1,9 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::storage::log_db_operation_time;
use crate::storage::models::{CommitSignature, Validator};
use sqlx::types::time::OffsetDateTime;
use sqlx::{Executor, Sqlite};
use tokio::time::Instant;
use tracing::{instrument, trace};
#[derive(Clone)]
@@ -25,10 +27,36 @@ impl StorageManager {
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(
&self,
time: OffsetDateTime,
) -> Result<Option<i64>, sqlx::Error> {
trace!("get_first_block_height_after");
let start = Instant::now();
let maybe_record = sqlx::query!(
r#"
SELECT height
@@ -41,6 +69,7 @@ impl StorageManager {
)
.fetch_optional(&self.connection_pool)
.await?;
log_db_operation_time("get_first_block_height_after", start);
if let Some(row) = maybe_record {
Ok(row.height)
@@ -53,6 +82,9 @@ impl StorageManager {
&self,
time: OffsetDateTime,
) -> Result<Option<i64>, sqlx::Error> {
trace!("get_last_block_height_before");
let start = Instant::now();
let maybe_record = sqlx::query!(
r#"
SELECT height
@@ -65,6 +97,7 @@ impl StorageManager {
)
.fetch_optional(&self.connection_pool)
.await?;
log_db_operation_time("get_last_block_height_before", start);
if let Some(row) = maybe_record {
Ok(row.height)
@@ -79,6 +112,9 @@ impl StorageManager {
start_height: i64,
end_height: i64,
) -> Result<i32, sqlx::Error> {
trace!("get_signed_between");
let start = Instant::now();
let count = sqlx::query!(
r#"
SELECT COUNT(*) as count FROM pre_commit
@@ -94,6 +130,7 @@ impl StorageManager {
.fetch_one(&self.connection_pool)
.await?
.count;
log_db_operation_time("get_signed_between", start);
Ok(count)
}
@@ -103,7 +140,10 @@ impl StorageManager {
consensus_address: &str,
height: i64,
) -> Result<Option<CommitSignature>, sqlx::Error> {
sqlx::query_as(
trace!("get_precommit");
let start = Instant::now();
let res = sqlx::query_as(
r#"
SELECT * FROM pre_commit
WHERE validator_address = ?
@@ -113,14 +153,20 @@ impl StorageManager {
.bind(consensus_address)
.bind(height)
.fetch_optional(&self.connection_pool)
.await
.await?;
log_db_operation_time("get_precommit", start);
Ok(res)
}
pub(crate) async fn get_block_validators(
&self,
height: i64,
) -> Result<Vec<Validator>, sqlx::Error> {
sqlx::query_as!(
trace!("get_block_validators");
let start = Instant::now();
let res = sqlx::query_as!(
Validator,
r#"
SELECT * FROM validator
@@ -133,16 +179,28 @@ impl StorageManager {
height
)
.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> {
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)
.await
.await?;
log_db_operation_time("get_validators", start);
Ok(res)
}
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!(
r#"
SELECT last_processed_height FROM metadata
@@ -150,6 +208,7 @@ impl StorageManager {
)
.fetch_optional(&self.connection_pool)
.await?;
log_db_operation_time("get_last_processed_height", start);
if let Some(row) = maybe_record {
Ok(row.last_processed_height)
@@ -157,6 +216,27 @@ impl StorageManager {
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
@@ -170,7 +250,8 @@ pub(crate) async fn insert_validator<'a, E>(
where
E: Executor<'a, Database = Sqlite>,
{
trace!("insert validator");
trace!("insert_validator");
let start = Instant::now();
sqlx::query!(
r#"
@@ -183,6 +264,7 @@ where
)
.execute(executor)
.await?;
log_db_operation_time("insert_validator", start);
Ok(())
}
@@ -200,7 +282,8 @@ pub(crate) async fn insert_block<'a, E>(
where
E: Executor<'a, Database = Sqlite>,
{
trace!("insert block");
trace!("insert_block");
let start = Instant::now();
sqlx::query!(
r#"
@@ -217,6 +300,7 @@ where
)
.execute(executor)
.await?;
log_db_operation_time("insert_block", start);
Ok(())
}
@@ -233,7 +317,8 @@ pub(crate) async fn insert_precommit<'a, E>(
where
E: Executor<'a, Database = Sqlite>,
{
trace!("insert precommit");
trace!("insert_precommit");
let start = Instant::now();
sqlx::query!(
r#"
@@ -249,6 +334,7 @@ where
)
.execute(executor)
.await?;
log_db_operation_time("insert_precommit", start);
Ok(())
}
@@ -270,7 +356,8 @@ pub(crate) async fn insert_transaction<'a, E>(
where
E: Executor<'a, Database = Sqlite>,
{
trace!("insert transaction");
trace!("insert_transaction");
let start = Instant::now();
sqlx::query!(
r#"
@@ -298,6 +385,7 @@ where
)
.execute(executor)
.await?;
log_db_operation_time("insert_transaction", start);
Ok(())
}
@@ -313,7 +401,8 @@ pub(crate) async fn insert_message<'a, E>(
where
E: Executor<'a, Database = Sqlite>,
{
trace!("insert message");
trace!("insert_message");
let start = Instant::now();
sqlx::query!(
r#"
@@ -330,6 +419,7 @@ where
)
.execute(executor)
.await?;
log_db_operation_time("insert_message", start);
Ok(())
}
@@ -343,10 +433,100 @@ where
E: Executor<'a, Database = Sqlite>,
{
trace!("update_last_processed");
let start = Instant::now();
sqlx::query!("UPDATE metadata SET last_processed_height = ?", height)
.execute(executor)
.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(())
}
+50 -1
View File
@@ -5,7 +5,8 @@ use crate::block_processor::types::{FullBlockInformation, ParsedTransactionRespo
use crate::error::ScraperError;
use crate::storage::manager::{
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 sqlx::types::time::OffsetDateTime;
@@ -15,6 +16,7 @@ use std::path::Path;
use tendermint::block::{Commit, CommitSig};
use tendermint::Block;
use tendermint_rpc::endpoint::validators;
use tokio::time::Instant;
use tracing::{debug, error, info, instrument, trace, warn};
mod helpers;
@@ -28,6 +30,19 @@ pub struct ScraperStorage {
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 {
#[instrument]
pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> {
@@ -65,6 +80,32 @@ impl ScraperStorage {
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)]
pub async fn begin_processing_tx(&self) -> Result<StorageTransaction, ScraperError> {
debug!("starting storage tx");
@@ -75,6 +116,10 @@ impl ScraperStorage {
.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(
&self,
time: OffsetDateTime,
@@ -155,6 +200,10 @@ impl ScraperStorage {
pub async fn get_last_processed_height(&self) -> Result<i64, ScraperError> {
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(
+4 -6
View File
@@ -316,12 +316,10 @@ mod tests {
&pub_attrs,
)
.unwrap();
let sig = blind_sig
.unblind(
keypair.verification_key(),
&sig_req.pedersen_commitments_openings,
)
.unwrap();
let sig = blind_sig.unblind(
keypair.verification_key(),
&sig_req.pedersen_commitments_openings,
);
let issued = issuance.into_issued_credential(sig, 42);
let spending = issued
+1
View File
@@ -49,6 +49,7 @@ pub fn override_network_requester_config(
let Some(opts) = opts else { return cfg };
// in the old code we had calls to `assert` thus panicking
#[allow(clippy::expect_used)]
cfg.base
.try_apply_traffic_modes(
cfg.network_requester.disable_poisson_rate,
+12 -5
View File
@@ -5,7 +5,7 @@ use crate::config::Config;
use crate::error::GatewayError;
use crate::helpers::load_public_key;
use ipnetwork::IpNetwork;
use log::{debug, warn};
use log::{debug, error, warn};
use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{encryption, identity};
use nym_network_requester::RequestFilter;
@@ -295,12 +295,19 @@ impl<'a> HttpApiBuilder<'a> {
.ok()
});
let bind_address = self.gateway_config.http.bind_address;
let router = nym_node_http_api::NymNodeRouter::new(config, None, wg_state);
let server = router
.build_server(&self.gateway_config.http.bind_address)?
.with_task_client(task_client);
tokio::spawn(async move { server.run().await });
tokio::spawn(async move {
let server = match router.build_server(&bind_address).await {
Ok(server) => server.with_task_client(task_client),
Err(err) => {
error!("failed to create http server: {err}");
return;
}
};
server.run().await
});
Ok(())
}
}
+12 -6
View File
@@ -4,7 +4,7 @@
use crate::config::Config;
use crate::error::MixnodeError;
use crate::node::node_description::NodeDescription;
use log::info;
use log::{error, info};
use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{encryption, identity};
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());
let router = nym_node_http_api::NymNodeRouter::new(config, None, None);
let server = router
// .with_merged(legacy::routes(self.legacy_mixnode, self.legacy_descriptor))
.build_server(&bind_address)?
.with_task_client(task_client);
tokio::spawn(async move { server.run().await });
tokio::spawn(async move {
let server = match router.build_server(&bind_address).await {
Ok(server) => server.with_task_client(task_client),
Err(err) => {
error!("failed to create http server: {err}");
return;
}
};
server.run().await
});
Ok(())
}
}
+4 -6
View File
@@ -1752,12 +1752,10 @@ mod credential_tests {
&pub_attrs,
)
.unwrap();
let sig = blind_sig
.unblind(
key_pair.verification_key(),
&sig_req.pedersen_commitments_openings,
)
.unwrap();
let sig = blind_sig.unblind(
key_pair.verification_key(),
&sig_req.pedersen_commitments_openings,
);
let issued = issuance.into_issued_credential(sig, epoch);
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
[dependencies]
axum = { workspace = true, features = ["headers"] }
# \/ will be needed once we update axum to 0.7
#axum-extra = { version = "0.9.3", features = ["typed-header"] }
#headers = "0.4"
axum.workspace = true
axum-extra = { axum.workspace = true, features = ["typed-header"] }
headers.workspace = true
# useful for `#[axum_macros::debug_handler]`
#axum-macros = "0.3.8"
hyper.workspace = true
thiserror.workspace = true
time = { workspace = true, features = ["serde"] }
tokio = { workspace = true, features = ["macros"] }
tower-http = { version = "0.4.4", features = ["fs"] }
tower-http = { version = "0.5.2", features = ["fs"] }
tracing.workspace = true
utoipa = { workspace = true, features = ["axum_extras", "time"] }
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"] }
[dev-dependencies]
hyper.workspace = true
dashmap.workspace = true
serde_json.workspace = true
+2 -1
View File
@@ -1,6 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::io;
use std::net::SocketAddr;
use thiserror::Error;
@@ -9,7 +10,7 @@ pub enum NymNodeHttpError {
#[error("failed to bind the HTTP API to {bind_address}: {source}")]
HttpBindFailure {
bind_address: SocketAddr,
source: hyper::Error,
source: io::Error,
},
#[error("failed to use nym-node requests: {source}")]
+12 -11
View File
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: GPL-3.0-only
use axum::extract::connect_info::IntoMakeServiceWithConnectInfo;
use axum::extract::ConnectInfo;
use axum::middleware::AddExtension;
use axum::serve::Serve;
use axum::Router;
use hyper::server::conn::AddrIncoming;
use hyper::Server;
use nym_task::TaskClient;
use std::net::SocketAddr;
use tracing::{debug, error, info};
use tracing::{debug, error};
pub mod error;
pub mod middleware;
@@ -17,15 +18,18 @@ pub mod state;
pub use error::NymNodeHttpError;
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 {
task_client: Option<TaskClient>,
inner: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>,
inner: ServeService,
}
impl NymNodeHTTPServer {
pub(crate) fn new(
inner: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>,
) -> Self {
pub(crate) fn new(inner: ServeService) -> Self {
NymNodeHTTPServer {
task_client: None,
inner,
@@ -38,9 +42,7 @@ impl NymNodeHTTPServer {
self
}
async fn run_server_forever(
server: Server<AddrIncoming, IntoMakeServiceWithConnectInfo<Router, SocketAddr>>,
) {
async fn run_server_forever(server: ServeService) {
if let Err(err) = server.await {
error!("the HTTP server has terminated with the error: {err}");
} else {
@@ -49,7 +51,6 @@ impl NymNodeHTTPServer {
}
pub async fn run(self) {
info!("Started NymNodeHTTPServer on {}", self.inner.local_addr());
if let Some(mut task_client) = self.task_client {
tokio::select! {
_ = 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
use axum::{
extract::ConnectInfo,
http::{HeaderValue, Request},
extract::{ConnectInfo, Request},
http::{
header::{HOST, USER_AGENT},
HeaderValue,
},
middleware::Next,
response::IntoResponse,
};
use colored::*;
use hyper::header::{HOST, USER_AGENT};
use std::net::SocketAddr;
use tracing::info;
/// Simple logger for requests
pub async fn logger<B>(
pub async fn logger(
ConnectInfo(addr): ConnectInfo<SocketAddr>,
req: Request<B>,
next: Next<B>,
req: Request,
next: Next,
) -> impl IntoResponse {
let method = req.method().to_string().green();
let uri = req.uri().to_string().blue();
@@ -104,6 +104,7 @@ mod test {
use crate::api::v1::gateway::client_interfaces::wireguard::{
routes, WireguardAppState, WireguardAppStateInner,
};
use axum::body::to_bytes;
use axum::body::Body;
use axum::http::Request;
use axum::http::StatusCode;
@@ -203,7 +204,7 @@ mod test {
nonce,
gateway_data,
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()
else {
panic!("invalid response")
@@ -257,7 +258,7 @@ mod test {
assert_eq!(response.status(), StatusCode::OK);
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();
assert!(!clients.is_empty());
@@ -3,10 +3,10 @@
use crate::state::metrics::MetricsAppState;
use axum::extract::State;
use axum::headers::authorization::Bearer;
use axum::headers::Authorization;
use axum::http::StatusCode;
use axum::TypedHeader;
use axum_extra::TypedHeader;
use headers::authorization::Bearer;
use headers::Authorization;
use nym_metrics::metrics;
/// Returns `prometheus` compatible metrics
+10 -7
View File
@@ -204,19 +204,22 @@ impl NymNodeRouter {
self
}
pub fn build_server(
pub async fn build_server(
self,
bind_address: &SocketAddr,
) -> 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 {
bind_address: *bind_address,
source,
})?
.serve(
self.inner
.into_make_service_with_connect_info::<SocketAddr>(),
);
})?;
let axum_server = axum::serve(
listener,
self.inner
.into_make_service_with_connect_info::<SocketAddr>(),
);
Ok(NymNodeHTTPServer::new(axum_server))
}
+12 -4
View File
@@ -455,7 +455,7 @@ impl NymNode {
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(
&self.config,
self.x25519_sphinx_keys.public_key(),
@@ -559,15 +559,23 @@ impl NymNode {
.with_metrics_key(self.config.http.access_token.clone());
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> {
let mut task_manager = TaskManager::default().named("NymNode");
let http_server = self
.build_http_server()?
.build_http_server()
.await?
.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 {
NodeMode::Mixnode => {
+3 -3
View File
@@ -31,7 +31,7 @@ humantime = "2.1.0"
humantime-serde.workspace = true
# 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-coconut = { path = "../common/nymcoconut" }
nym-crypto = { path = "../common/crypto", features = ["asymmetric"] }
@@ -39,8 +39,8 @@ nym-credentials = { path = "../common/credentials" }
nym-network-defaults = { path = "../common/network-defaults" }
nym-task = { path = "../common/task" }
nym-validator-client = { path = "../common/client-libs/validator-client" }
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-dkg-common = { path = "../common/cosmwasm-smart-contracts/coconut-dkg" }
nym-coconut-bandwidth-contract-common = { path = "../common/cosmwasm-smart-contracts/coconut-bandwidth-contract" }
nyxd-scraper = { path = "../common/nyxd-scraper" }
[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);
config.ensure_is_valid()?;
config.validate()?;
config
.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) {
cfg.ensure_is_valid()?;
cfg.validate()?;
return Ok(cfg);
}
@@ -122,7 +122,7 @@ fn try_load_current_config(custom_path: &Option<PathBuf>) -> Result<Config, NymR
);
err
})?;
config.ensure_is_valid()?;
config.validate()?;
Ok(config)
}
+49 -5
View File
@@ -10,6 +10,7 @@ use nym_config::{
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use nym_validator_client::nyxd::{AccountId, Coin};
use nyxd_scraper::PruningOptions;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
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_SAMPLING_RATE: f64 = 0.10;
// 'worst' case scenario
pub const TYPICAL_BLOCK_TIME: f32 = 5.;
/// Get default path to rewarder's config directory.
/// It should get resolved to `$HOME/.nym/validators-rewarder/config`
pub fn default_config_directory() -> PathBuf {
@@ -100,7 +104,10 @@ impl Config {
rewarding: Rewarding::default(),
block_signing: Default::default(),
issuance_monitor: IssuanceMonitor::default(),
nyxd_scraper: NyxdScraper { websocket_url },
nyxd_scraper: NyxdScraper {
websocket_url,
pruning: Default::default(),
},
base: Base {
upstream_nyxd: nyxd_url,
mnemonic,
@@ -114,11 +121,13 @@ impl Config {
websocket_url: self.nyxd_scraper.websocket_url.clone(),
rpc_url: self.base.upstream_nyxd.clone(),
database_path: self.storage_paths.nyxd_scraper.clone(),
pruning_options: self.nyxd_scraper.pruning,
}
}
pub fn ensure_is_valid(&self) -> Result<(), NymRewarderError> {
self.rewarding.ratios.ensure_is_valid()?;
pub fn validate(&self) -> Result<(), NymRewarderError> {
self.rewarding.ratios.validate()?;
self.nyxd_scraper.validate(self.rewarding.epoch_duration)?;
Ok(())
}
@@ -140,7 +149,7 @@ impl Config {
source,
}
})?;
loaded.ensure_is_valid()?;
loaded.validate()?;
loaded.save_path = Some(path.to_path_buf());
debug!("loaded config file from {}", path.display());
Ok(loaded)
@@ -223,7 +232,7 @@ impl Default for 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 {
return Err(NymRewarderError::InvalidRewardingRatios { ratios: *self });
}
@@ -235,9 +244,44 @@ impl RewardingRatios {
pub struct NyxdScraper {
/// Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket`
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
}
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)]
pub struct BlockSigning {
/// Specifies whether rewards for block signing is enabled.
@@ -74,4 +74,14 @@ whitelist = [
[nyxd_scraper]
# Url to the websocket endpoint of a validator, for example `wss://rpc.nymtech.net/websocket`
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")]
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)]
+1 -1
View File
@@ -20,7 +20,7 @@ mod rewarder;
async fn main() -> anyhow::Result<()> {
// std::env::set_var(
// "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();
@@ -11,7 +11,7 @@ use nyxd_scraper::NyxdScraper;
use std::cmp::min;
use std::collections::HashMap;
use std::ops::Range;
use tracing::{debug, info, trace, warn};
use tracing::{debug, error, info, trace, warn};
pub(crate) mod types;
@@ -28,7 +28,7 @@ impl EpochSigning {
height_range: Range<i64>,
) -> Result<Option<i64>, NymRewarderError> {
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
.nyxd_scraper
.storage
@@ -121,7 +121,7 @@ impl EpochSigning {
.get_voting_power(&validator.consensus_address, vp_range.clone())
.await?
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;
};
+173 -20
View File
@@ -220,7 +220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7"
dependencies = [
"flate2",
"http",
"http 0.2.9",
"log",
"native-tls",
"serde",
@@ -279,6 +279,12 @@ version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.6.0"
@@ -2178,7 +2184,7 @@ dependencies = [
"futures-core",
"futures-sink",
"futures-util",
"http",
"http 0.2.9",
"indexmap 1.9.3",
"slab",
"tokio",
@@ -2311,6 +2317,17 @@ dependencies = [
"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]]
name = "http-body"
version = "0.4.5"
@@ -2318,7 +2335,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [
"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",
]
@@ -2376,8 +2416,8 @@ dependencies = [
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"http 0.2.9",
"http-body 0.4.5",
"httparse",
"httpdate",
"itoa 1.0.9",
@@ -2389,6 +2429,25 @@ dependencies = [
"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]]
name = "hyper-rustls"
version = "0.24.2"
@@ -2396,8 +2455,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [
"futures-util",
"http",
"hyper",
"http 0.2.9",
"hyper 0.14.27",
"rustls",
"tokio",
"tokio-rustls",
@@ -2410,12 +2469,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"hyper 0.14.27",
"native-tls",
"tokio",
"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]]
name = "ico"
version = "0.2.0"
@@ -3174,7 +3253,7 @@ name = "nym-http-api-client"
version = "0.1.0"
dependencies = [
"async-trait",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"thiserror",
@@ -3321,7 +3400,7 @@ dependencies = [
"nym-mixnet-contract-common",
"nym-validator-client",
"nym-vesting-contract-common",
"reqwest",
"reqwest 0.12.4",
"schemars",
"serde",
"serde_json",
@@ -3370,7 +3449,7 @@ dependencies = [
"nym-service-provider-directory-common",
"nym-vesting-contract-common",
"prost",
"reqwest",
"reqwest 0.12.4",
"serde",
"serde_json",
"sha2 0.9.9",
@@ -3472,7 +3551,7 @@ dependencies = [
"once_cell",
"pretty_env_logger",
"rand_chacha 0.2.2",
"reqwest",
"reqwest 0.11.22",
"serde",
"serde_json",
"serde_repr",
@@ -4320,9 +4399,9 @@ dependencies = [
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"http 0.2.9",
"http-body 0.4.5",
"hyper 0.14.27",
"hyper-rustls",
"hyper-tls",
"ipnet",
@@ -4348,7 +4427,42 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"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]]
@@ -5116,6 +5230,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
@@ -5251,7 +5371,7 @@ dependencies = [
"glob",
"gtk",
"heck 0.4.1",
"http",
"http 0.2.9",
"ignore",
"minisign-verify",
"objc",
@@ -5348,7 +5468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c507d954d08ac8705d235bc70ec6975b9054fb95ff7823af72dbb04186596f3b"
dependencies = [
"gtk",
"http",
"http 0.2.9",
"http-range",
"rand 0.8.5",
"raw-window-handle",
@@ -5498,7 +5618,7 @@ dependencies = [
"getrandom 0.2.10",
"peg",
"pin-project",
"reqwest",
"reqwest 0.11.22",
"semver 1.0.22",
"serde",
"serde_bytes",
@@ -5726,6 +5846,28 @@ dependencies = [
"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]]
name = "tower-service"
version = "0.3.2"
@@ -5739,6 +5881,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -6475,6 +6618,16 @@ dependencies = [
"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]]
name = "winres"
version = "0.1.12"
@@ -6501,7 +6654,7 @@ dependencies = [
"glib",
"gtk",
"html5ever",
"http",
"http 0.2.9",
"kuchiki",
"libc",
"log",