Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 291544c311 | |||
| b4f51baf94 | |||
| a3f3d83c1b | |||
| 84d7004cb2 | |||
| be063a36eb | |||
| 0a712b9fce | |||
| 88d6fb4e22 | |||
| 04c2045d94 |
@@ -1 +0,0 @@
|
||||
nym-validator-rewarder/.sqlx/** diff=nodiff
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ arc-ubuntu-20.04, custom-runner-mac-m1 ]
|
||||
os: [ arc-ubuntu-20.04, custom-windows-11, custom-runner-mac-m1 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
+3
-1
@@ -51,4 +51,6 @@ ppa-private-key.b64
|
||||
ppa-private-key.asc
|
||||
nym-network-monitor/topology.json
|
||||
nym-network-monitor/__pycache__
|
||||
nym-network-monitor/*.key
|
||||
nym-network-monitor/*.key
|
||||
nym-network-monitor/.envrc
|
||||
nym-network-monitor/.envrc
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.
|
||||
# See https://redocly.com/docs/cli/ for more information.
|
||||
formatted-openapi.json:
|
||||
path-parameters-defined:
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/0/name
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/1/name
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/2/name
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/3/name
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/4/name
|
||||
# - >-
|
||||
# #/paths/~1v1~1status~1mixnode~1{mix_id}~1compute-reward-estimation/post/parameters/5/name
|
||||
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/0/name'
|
||||
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/1/name'
|
||||
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/2/name'
|
||||
# - '#/paths/~1v1~1unstable~1nym-nodes~1skimmed~1active/get/parameters/3/name'
|
||||
operation-operationId-unique:
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnodes~1active~1detailed/get/get_active_set_detailed
|
||||
- '#/paths/~1v1~1status~1mixnodes~1detailed/get/get_mixnodes_detailed'
|
||||
- >-
|
||||
#/paths/~1v1~1status~1mixnodes~1rewarded~1detailed/get/get_rewarded_set_detailed
|
||||
no-unused-components:
|
||||
- '#/components/schemas/AxumErrorResponse'
|
||||
- '#/components/schemas/DateQuery'
|
||||
- '#/components/schemas/EcashTicketVerificationRejection'
|
||||
- '#/components/schemas/ExpirationDatePathParam'
|
||||
- '#/components/schemas/FullFatNode'
|
||||
- '#/components/schemas/HistoricalPerformanceResponse'
|
||||
- '#/components/schemas/HistoricalUptimeResponse'
|
||||
- '#/components/schemas/MasterVerificationKeyResponse'
|
||||
- '#/components/schemas/MixnodeStatusReport'
|
||||
- '#/components/schemas/NodeId'
|
||||
- '#/components/schemas/NodeRoleQueryParam'
|
||||
- '#/components/schemas/NoiseDetails'
|
||||
- '#/components/schemas/NymNodeDescription'
|
||||
- '#/components/schemas/NymNodeDetails'
|
||||
- '#/components/schemas/PaginationRequest'
|
||||
- '#/components/schemas/PartialCoinIndicesSignatureResponse'
|
||||
- '#/components/schemas/SpentCredentialsResponse'
|
||||
- '#/components/schemas/UptimeHistoryResponse'
|
||||
- '#/components/schemas/VerifyEcashCredentialBody'
|
||||
- '#/components/responses/AxumErrorResponse'
|
||||
- '#/components/responses/CirculatingSupplyResponse'
|
||||
- '#/components/responses/RequestError'
|
||||
@@ -1,83 +0,0 @@
|
||||
extends:
|
||||
- minimal
|
||||
apis:
|
||||
nym-api:
|
||||
root: ./formatted-openapi.json
|
||||
rules:
|
||||
# https://redocly.com/docs/cli/rules/oas/operation-summary
|
||||
operation-summary: off
|
||||
# https://redocly.com/docs/cli/rules/oas/security-defined
|
||||
security-defined: off
|
||||
struct: off
|
||||
# https://redocly.com/docs/cli/rules/oas/operation-2xx-response
|
||||
operation-2xx-response: off
|
||||
# rules:
|
||||
# skip-warnings: true
|
||||
# ignore:
|
||||
# - path: /v1/gateways
|
||||
# method: get
|
||||
# - path: /v1/gateways/blacklisted
|
||||
# method: get
|
||||
# - path: /v1/mixnodes
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/active
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/active/detailed
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/blacklisted
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/detailed
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/rewarded
|
||||
# method: get
|
||||
# - path: /v1/mixnodes/rewarded/detailed
|
||||
# method: get
|
||||
# - path: /v1/gateways/described
|
||||
# method: get
|
||||
# # network-monitor-status (deprecated)
|
||||
# - path: /v1/status/gateway/{identity}/avg_uptime
|
||||
# method: GET
|
||||
# - path: /v1/status/gateway/{identity}/core-status-count
|
||||
# method: GET
|
||||
# - path: /v1/status/gateway/{identity}/history
|
||||
# method: GET
|
||||
# - path: /v1/status/gateway/{identity}/report
|
||||
# method: GET
|
||||
# - path: /v1/status/gateways/detailed
|
||||
# method: GET
|
||||
# - path: /v1/status/gateways/detailed-unfiltered
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/avg_uptime
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/compute-reward-estimation
|
||||
# method: POST
|
||||
# - path: /v1/status/mixnode/{mix_id}/core-status-count
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/history
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/report
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/reward-estimation
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnodes/detailed-unfiltered
|
||||
# method: GET
|
||||
# # status
|
||||
# - path: /v1/status/mixnode/{mix_id}/inclusion-probability
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/stake-saturation
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnode/{mix_id}/status
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnodes/active/detailed
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnodes/detailed
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnodes/inclusion-probability
|
||||
# method: GET
|
||||
# - path: /v1/status/mixnodes/rewarded/detailed
|
||||
# method: GET
|
||||
# # unstable nym nodes
|
||||
# - path: /v1/unstable/nym-nodes/gateways/skimmed
|
||||
# method: get
|
||||
# - path: /v1/unstable/nym-nodes/mixnodes/skimmed
|
||||
# method: get
|
||||
Generated
+176
-49
@@ -2475,6 +2475,12 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fancy_constructor"
|
||||
version = "1.2.2"
|
||||
@@ -3830,12 +3836,6 @@ dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lockfree-object-pool"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
@@ -4355,6 +4355,27 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
@@ -4951,7 +4972,6 @@ dependencies = [
|
||||
"sha2 0.9.9",
|
||||
"subtle 2.5.0",
|
||||
"thiserror",
|
||||
"utoipa",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -4980,7 +5000,6 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"utoipa",
|
||||
"vergen",
|
||||
]
|
||||
|
||||
@@ -5172,7 +5191,6 @@ dependencies = [
|
||||
"strum 0.26.3",
|
||||
"thiserror",
|
||||
"time",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5770,6 +5788,7 @@ dependencies = [
|
||||
"nym-bin-common",
|
||||
"nym-client-core",
|
||||
"nym-crypto",
|
||||
"nym-gateway-requests",
|
||||
"nym-network-defaults",
|
||||
"nym-sdk",
|
||||
"nym-sphinx",
|
||||
@@ -5783,6 +5802,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-postgres",
|
||||
"tokio-util",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
@@ -6532,7 +6552,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
"time",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6599,7 +6618,6 @@ dependencies = [
|
||||
"thiserror",
|
||||
"ts-rs",
|
||||
"url",
|
||||
"utoipa",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
@@ -7240,6 +7258,24 @@ dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||
dependencies = [
|
||||
"siphasher 0.3.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.6"
|
||||
@@ -7378,6 +7414,35 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "postgres-protocol"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"hmac",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"rand",
|
||||
"sha2 0.10.8",
|
||||
"stringprep",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postgres-types"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"postgres-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
@@ -7410,6 +7475,39 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
|
||||
dependencies = [
|
||||
"toml_edit 0.21.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
@@ -7841,6 +7939,7 @@ checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
@@ -8766,12 +8865,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
@@ -9684,6 +9777,32 @@ dependencies = [
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-postgres"
|
||||
version = "0.7.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"fallible-iterator",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"phf",
|
||||
"pin-project-lite",
|
||||
"postgres-protocol",
|
||||
"postgres-types",
|
||||
"rand",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
@@ -9803,7 +9922,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
"toml_edit 0.22.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9815,6 +9934,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"toml_datetime",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.14"
|
||||
@@ -9825,7 +9955,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
"winnow 0.6.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10472,9 +10602,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "5.2.0"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514a48569e4e21c86d0b84b5612b5e73c0b2cf09db63260134ba426d4e8ea714"
|
||||
checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
@@ -10484,10 +10614,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "5.2.0"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5629efe65599d0ccd5d493688cbf6e03aa7c1da07fe59ff97cf5977ed0637f66"
|
||||
checksum = "7bf0e16c02bc4bf5322ab65f10ab1149bdbcaa782cba66dc7057370a3f8190be"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
@@ -10497,13 +10628,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "8.0.3"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5c80b4dd79ea382e8374d67dcce22b5c6663fa13a82ad3886441d1bbede5e35"
|
||||
checksum = "943e0ff606c6d57d410fd5663a4d7c074ab2c5f14ab903b9514565e59fa1189e"
|
||||
dependencies = [
|
||||
"axum 0.7.7",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"reqwest 0.12.4",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -10514,18 +10646,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto"
|
||||
version = "0.2.0"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cba36db2c397c614110554a60fbb4bb97d5f8c6823775c766e6f455e37377047"
|
||||
checksum = "608b8f2279483be386261655b562e40877ea434eb92093c894a644fda2021860"
|
||||
dependencies = [
|
||||
"utoipauto-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-core"
|
||||
version = "0.2.0"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "268d76aaebb80eba79240b805972e52d7d410d4bcc52321b951318b0f440cd60"
|
||||
checksum = "17e82ab96c5a55263b5bed151b8426410d93aa909a453acdbd4b6792b5af7d64"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10534,9 +10666,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "utoipauto-macro"
|
||||
version = "0.2.0"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "382673bda1d05c85b4550d32fd4192ccd4cffe9a908543a0795d1e7682b36246"
|
||||
checksum = "86b8338dc3c9526011ffaa2aa6bd60ddfda9d49d2123108690755c6e34844212"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -10861,6 +10993,7 @@ checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
|
||||
dependencies = [
|
||||
"redox_syscall 0.5.1",
|
||||
"wasite",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11127,6 +11260,15 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.13"
|
||||
@@ -11239,9 +11381,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.1.6"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e"
|
||||
checksum = "9cc23c04387f4da0374be4533ad1208cbb091d5c11d070dfef13676ad6497164"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
@@ -11249,9 +11391,8 @@ dependencies = [
|
||||
"displaydoc",
|
||||
"flate2",
|
||||
"indexmap 2.2.6",
|
||||
"memchr",
|
||||
"num_enum",
|
||||
"thiserror",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11281,17 +11422,3 @@ dependencies = [
|
||||
"wasmtimer",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zopfli"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"lockfree-object-pool",
|
||||
"log",
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
+3
-3
@@ -345,9 +345,9 @@ tracing-log = "0.2"
|
||||
ts-rs = "10.0.0"
|
||||
tungstenite = { version = "0.20.1", default-features = false }
|
||||
url = "2.5"
|
||||
utoipa = "5.2"
|
||||
utoipa-swagger-ui = "8.0"
|
||||
utoipauto = "0.2"
|
||||
utoipa = "4.2"
|
||||
utoipa-swagger-ui = "7.1"
|
||||
utoipauto = "0.1"
|
||||
uuid = "*"
|
||||
vergen = { version = "=8.3.1", default-features = false }
|
||||
walkdir = "2"
|
||||
|
||||
@@ -8,7 +8,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use log::{debug, error};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -30,6 +33,9 @@ impl StorageManager {
|
||||
}
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -110,7 +116,7 @@ impl StorageManager {
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
|
||||
INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type)
|
||||
VALUES (?, ?, ?)
|
||||
"#,
|
||||
registered_gateway.gateway_id_bs58,
|
||||
@@ -224,7 +230,7 @@ impl StorageManager {
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
|
||||
INSERT INTO custom_gateway_details(gateway_id_bs58, data)
|
||||
VALUES (?, ?)
|
||||
"#,
|
||||
custom.gateway_id_bs58,
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::init::{
|
||||
setup_gateway,
|
||||
types::{GatewaySetup, InitialisationResult},
|
||||
};
|
||||
use crate::{config, spawn_future};
|
||||
use crate::{config, spawn_future, ForgetMe};
|
||||
use futures::channel::mpsc;
|
||||
use log::*;
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
@@ -188,6 +188,11 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
|
||||
user_agent: Option<UserAgent>,
|
||||
|
||||
setup_method: GatewaySetup,
|
||||
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
|
||||
forget_me: ForgetMe,
|
||||
}
|
||||
|
||||
impl<'a, C, S> BaseClientBuilder<'a, C, S>
|
||||
@@ -210,9 +215,18 @@ where
|
||||
shutdown: None,
|
||||
user_agent: None,
|
||||
setup_method: GatewaySetup::MustLoad { gateway_id: None },
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
forget_me: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
|
||||
self.forget_me = forget_me.clone();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_gateway_setup(mut self, setup: GatewaySetup) -> Self {
|
||||
self.setup_method = setup;
|
||||
@@ -261,6 +275,15 @@ where
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn with_connection_fd_callback(
|
||||
mut self,
|
||||
callback: Arc<dyn Fn(RawFd) + Send + Sync>,
|
||||
) -> Self {
|
||||
self.connection_fd_callback = Some(callback);
|
||||
self
|
||||
}
|
||||
|
||||
// note: do **NOT** make this method public as its only valid usage is from within `start_base`
|
||||
// because it relies on the crypto keys being already loaded
|
||||
fn mix_address(details: &InitialisationResult) -> Recipient {
|
||||
@@ -352,6 +375,7 @@ where
|
||||
controller.start_with_shutdown(shutdown)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn start_gateway_client(
|
||||
config: &Config,
|
||||
initialisation_result: InitialisationResult,
|
||||
@@ -359,6 +383,7 @@ where
|
||||
details_store: &S::GatewaysDetailsStore,
|
||||
packet_router: PacketRouter,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
shutdown: TaskClient,
|
||||
) -> Result<GatewayClient<C, S::CredentialStore>, ClientCoreError>
|
||||
where
|
||||
@@ -401,6 +426,8 @@ where
|
||||
packet_router,
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
shutdown,
|
||||
)
|
||||
};
|
||||
@@ -462,6 +489,7 @@ where
|
||||
details_store: &S::GatewaysDetailsStore,
|
||||
packet_router: PacketRouter,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
mut shutdown: TaskClient,
|
||||
) -> Result<Box<dyn GatewayTransceiver + Send>, ClientCoreError>
|
||||
where
|
||||
@@ -493,6 +521,8 @@ where
|
||||
details_store,
|
||||
packet_router,
|
||||
stats_reporter,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
shutdown,
|
||||
)
|
||||
.await?;
|
||||
@@ -615,9 +645,11 @@ where
|
||||
fn start_mix_traffic_controller(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
shutdown: TaskClient,
|
||||
forget_me: ForgetMe,
|
||||
) -> BatchMixMessageSender {
|
||||
info!("Starting mix traffic controller...");
|
||||
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_transceiver);
|
||||
let (mix_traffic_controller, mix_tx) =
|
||||
MixTrafficController::new(gateway_transceiver, forget_me);
|
||||
mix_traffic_controller.start_with_shutdown(shutdown);
|
||||
mix_tx
|
||||
}
|
||||
@@ -772,6 +804,8 @@ where
|
||||
&details_store,
|
||||
gateway_packet_router,
|
||||
stats_reporter.clone(),
|
||||
#[cfg(unix)]
|
||||
self.connection_fd_callback,
|
||||
shutdown.fork("gateway_transceiver"),
|
||||
)
|
||||
.await?;
|
||||
@@ -797,9 +831,11 @@ where
|
||||
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
|
||||
let message_sender = Self::start_mix_traffic_controller(
|
||||
gateway_transceiver,
|
||||
shutdown.fork("mix_traffic_controller"),
|
||||
self.forget_me,
|
||||
);
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::mix_traffic::transceiver::GatewayTransceiver;
|
||||
use crate::spawn_future;
|
||||
use crate::{spawn_future, ForgetMe};
|
||||
use log::*;
|
||||
use nym_gateway_requests::ClientRequest;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
|
||||
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
|
||||
@@ -26,10 +27,14 @@ pub struct MixTrafficController {
|
||||
// TODO: this is temporary work-around.
|
||||
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
|
||||
consecutive_gateway_failure_count: usize,
|
||||
forget_me: ForgetMe,
|
||||
}
|
||||
|
||||
impl MixTrafficController {
|
||||
pub fn new<T>(gateway_transceiver: T) -> (MixTrafficController, BatchMixMessageSender)
|
||||
pub fn new<T>(
|
||||
gateway_transceiver: T,
|
||||
forget_me: ForgetMe,
|
||||
) -> (MixTrafficController, BatchMixMessageSender)
|
||||
where
|
||||
T: GatewayTransceiver + Send + 'static,
|
||||
{
|
||||
@@ -40,6 +45,7 @@ impl MixTrafficController {
|
||||
gateway_transceiver: Box::new(gateway_transceiver),
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
forget_me,
|
||||
},
|
||||
message_sender,
|
||||
)
|
||||
@@ -47,6 +53,7 @@ impl MixTrafficController {
|
||||
|
||||
pub fn new_dynamic(
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
|
||||
forget_me: ForgetMe,
|
||||
) -> (MixTrafficController, BatchMixMessageSender) {
|
||||
let (message_sender, message_receiver) =
|
||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||
@@ -55,6 +62,7 @@ impl MixTrafficController {
|
||||
gateway_transceiver,
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
forget_me,
|
||||
},
|
||||
message_sender,
|
||||
)
|
||||
@@ -111,7 +119,27 @@ impl MixTrafficController {
|
||||
}
|
||||
}
|
||||
shutdown.recv_timeout().await;
|
||||
|
||||
if self.forget_me.any() {
|
||||
log::info!("Sending forget me request to the gateway");
|
||||
match self
|
||||
.gateway_transceiver
|
||||
.send_client_request(ClientRequest::ForgetMe {
|
||||
client: self.forget_me.client(),
|
||||
stats: self.forget_me.stats(),
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
log::info!("Successfully sent forget me request to the gateway");
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("Failed to send forget me request to the gateway: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!("MixTrafficController: Exiting");
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ use async_trait::async_trait;
|
||||
use log::{debug, error};
|
||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::error::GatewayClientError;
|
||||
use nym_gateway_client::GatewayClient;
|
||||
pub use nym_gateway_client::{GatewayPacketRouter, PacketRouter};
|
||||
use nym_gateway_requests::ClientRequest;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use std::fmt::Debug;
|
||||
@@ -26,9 +28,14 @@ fn erase_err<E: std::error::Error + Send + Sync + 'static>(err: E) -> ErasedGate
|
||||
}
|
||||
|
||||
/// This combines combines the functionalities of being able to send and receive mix packets.
|
||||
#[async_trait]
|
||||
pub trait GatewayTransceiver: GatewaySender + GatewayReceiver {
|
||||
fn gateway_identity(&self) -> identity::PublicKey;
|
||||
fn ws_fd(&self) -> Option<RawFd>;
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError>;
|
||||
}
|
||||
|
||||
/// This trait defines the functionality of sending `MixPacket` into the mixnet,
|
||||
@@ -65,6 +72,7 @@ pub trait GatewayReceiver {
|
||||
}
|
||||
|
||||
// to allow for dynamic dispatch
|
||||
#[async_trait]
|
||||
impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
|
||||
#[inline]
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
@@ -73,6 +81,13 @@ impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
(**self).ws_fd()
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
(**self).send_client_request(message).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -91,7 +106,6 @@ impl<G: GatewaySender + ?Sized + Send> GatewaySender for Box<G> {
|
||||
(**self).batch_send_mix_packets(packets).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: GatewayReceiver + ?Sized> GatewayReceiver for Box<G> {
|
||||
#[inline]
|
||||
fn set_packet_router(&mut self, packet_router: PacketRouter) -> Result<(), ErasedGatewayError> {
|
||||
@@ -111,6 +125,7 @@ impl<C, St> RemoteGateway<C, St> {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<C, St> GatewayTransceiver for RemoteGateway<C, St>
|
||||
where
|
||||
C: DkgQueryClient + Send + Sync,
|
||||
@@ -123,6 +138,20 @@ where
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
self.gateway_client.ws_fd()
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
if let Some(shared_key) = self.gateway_client.shared_key() {
|
||||
self.gateway_client
|
||||
.send_websocket_message(message.encrypt(&*shared_key)?)
|
||||
.await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(GatewayClientError::ConnectionInInvalidState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
@@ -195,6 +224,7 @@ impl LocalGateway {
|
||||
mod nonwasm_sealed {
|
||||
use super::*;
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for LocalGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
self.local_identity
|
||||
@@ -202,6 +232,13 @@ mod nonwasm_sealed {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
_message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -269,6 +306,7 @@ impl GatewaySender for MockGateway {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl GatewayTransceiver for MockGateway {
|
||||
fn gateway_identity(&self) -> identity::PublicKey {
|
||||
self.dummy_identity
|
||||
@@ -276,4 +314,11 @@ impl GatewayTransceiver for MockGateway {
|
||||
fn ws_fd(&self) -> Option<RawFd> {
|
||||
None
|
||||
}
|
||||
|
||||
async fn send_client_request(
|
||||
&mut self,
|
||||
_message: ClientRequest,
|
||||
) -> Result<(), GatewayClientError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,3 +34,48 @@ where
|
||||
{
|
||||
tokio::spawn(future);
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct ForgetMe {
|
||||
client: bool,
|
||||
stats: bool,
|
||||
}
|
||||
|
||||
impl ForgetMe {
|
||||
pub fn new_all() -> Self {
|
||||
Self {
|
||||
client: true,
|
||||
stats: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_client() -> Self {
|
||||
Self {
|
||||
client: true,
|
||||
stats: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_stats() -> Self {
|
||||
Self {
|
||||
client: false,
|
||||
stats: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(client: bool, stats: bool) -> Self {
|
||||
Self { client, stats }
|
||||
}
|
||||
|
||||
pub fn any(&self) -> bool {
|
||||
self.client || self.stats
|
||||
}
|
||||
|
||||
pub fn client(&self) -> bool {
|
||||
self.client
|
||||
}
|
||||
|
||||
pub fn stats(&self) -> bool {
|
||||
self.stats
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use crate::backend::fs_backend::{
|
||||
},
|
||||
};
|
||||
use log::{error, info};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -31,6 +34,9 @@ impl StorageManager {
|
||||
}
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(fresh)
|
||||
.disable_statement_logging();
|
||||
|
||||
@@ -101,6 +101,10 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
|
||||
// currently unused (but populated)
|
||||
negotiated_protocol: Option<u8>,
|
||||
|
||||
// Callback on the fd as soon as the connection has been established
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
|
||||
/// Listen to shutdown messages and send notifications back to the task manager
|
||||
task_client: TaskClient,
|
||||
}
|
||||
@@ -116,6 +120,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
packet_router: PacketRouter,
|
||||
bandwidth_controller: Option<BandwidthController<C, St>>,
|
||||
stats_reporter: ClientStatsSender,
|
||||
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
|
||||
task_client: TaskClient,
|
||||
) -> Self {
|
||||
GatewayClient {
|
||||
@@ -131,6 +136,8 @@ impl<C, St> GatewayClient<C, St> {
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
negotiated_protocol: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
@@ -205,6 +212,12 @@ impl<C, St> GatewayClient<C, St> {
|
||||
};
|
||||
|
||||
self.connection = SocketState::Available(Box::new(ws_stream));
|
||||
|
||||
#[cfg(unix)]
|
||||
if let (Some(callback), Some(fd)) = (self.connection_fd_callback.as_ref(), self.ws_fd()) {
|
||||
callback.as_ref()(fd);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -311,7 +324,7 @@ impl<C, St> GatewayClient<C, St> {
|
||||
|
||||
// If we want to send a message (with response), we need to have a full control over the socket,
|
||||
// as we need to be able to write the request and read the subsequent response
|
||||
async fn send_websocket_message(
|
||||
pub async fn send_websocket_message(
|
||||
&mut self,
|
||||
msg: impl Into<Message>,
|
||||
) -> Result<ServerResponse, GatewayClientError> {
|
||||
@@ -1034,6 +1047,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
bandwidth_controller: None,
|
||||
stats_reporter: ClientStatsSender::new(None),
|
||||
negotiated_protocol: None,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: None,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
@@ -1064,6 +1079,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
|
||||
bandwidth_controller,
|
||||
stats_reporter,
|
||||
negotiated_protocol: self.negotiated_protocol,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: self.connection_fd_callback,
|
||||
task_client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ cosmwasm-std = { workspace = true }
|
||||
cosmwasm-schema = { workspace = true }
|
||||
cw-storage-plus = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
utoipa = { workspace = true, optional = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -24,5 +23,4 @@ serde_json = { workspace = true }
|
||||
vergen = { workspace = true, features = ["build", "git", "gitcl", "rustc", "cargo"] }
|
||||
|
||||
[features]
|
||||
naive_float = []
|
||||
utoipa = ["dep:utoipa"]
|
||||
naive_float = []
|
||||
@@ -221,7 +221,6 @@ fn default_unknown() -> String {
|
||||
// TODO: there's no reason this couldn't be used for proper binaries, but in that case
|
||||
// perhaps the struct should get renamed and moved to a "more" common crate
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct ContractBuildInformation {
|
||||
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
|
||||
#[serde(default = "default_unknown")]
|
||||
|
||||
@@ -42,11 +42,9 @@ pub struct Gateway {
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct GatewayBond {
|
||||
/// Original amount pledged by the operator of this node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub pledge_amount: Coin,
|
||||
|
||||
/// Address of the owner of this gateway.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Block height at which this gateway has been bonded.
|
||||
@@ -57,7 +55,6 @@ pub struct GatewayBond {
|
||||
|
||||
/// Entity who bonded this gateway on behalf of the owner.
|
||||
/// If exists, it's most likely the address of the vesting contract.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub proxy: Option<Addr>,
|
||||
}
|
||||
|
||||
|
||||
@@ -81,25 +81,20 @@ impl MixNodeDetails {
|
||||
|
||||
// currently this struct is shared between mixnodes and nymnodes
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NodeRewarding {
|
||||
/// Information provided by the operator that influence the cost function.
|
||||
pub cost_params: NodeCostParams,
|
||||
|
||||
/// Total pledge and compounded reward earned by the node operator.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operator: Decimal,
|
||||
|
||||
/// Total delegation and compounded reward earned by all node delegators.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub delegates: Decimal,
|
||||
|
||||
/// Cumulative reward earned by the "unit delegation" since the block 0.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub total_unit_reward: Decimal,
|
||||
|
||||
/// Value of the theoretical "unit delegation" that has delegated to this node at block 0.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub unit_delegation: Decimal,
|
||||
|
||||
/// Marks the epoch when this node was last rewarded so that we wouldn't accidentally attempt
|
||||
@@ -496,17 +491,14 @@ impl NodeRewarding {
|
||||
::cosmwasm_schema::schemars::JsonSchema,
|
||||
)]
|
||||
#[schemars(crate = "::cosmwasm_schema::schemars")]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct MixNodeBond {
|
||||
/// Unique id assigned to the bonded mixnode.
|
||||
pub mix_id: NodeId,
|
||||
|
||||
/// Address of the owner of this mixnode.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Original amount pledged by the operator of this node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub original_pledge: Coin,
|
||||
|
||||
// REMOVED (but might be needed due to legacy things, idk yet)
|
||||
@@ -517,7 +509,6 @@ pub struct MixNodeBond {
|
||||
|
||||
/// Entity who bonded this mixnode on behalf of the owner.
|
||||
/// If exists, it's most likely the address of the vesting contract.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
|
||||
pub proxy: Option<Addr>,
|
||||
|
||||
/// Block height at which this mixnode has been bonded.
|
||||
@@ -553,7 +544,6 @@ impl MixNodeBond {
|
||||
feature = "generate-ts",
|
||||
ts(export, export_to = "ts-packages/types/src/types/rust/Mixnode.ts")
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct MixNode {
|
||||
/// Network address of this mixnode, for example 1.1.1.1 or foo.mixnode.com
|
||||
pub host: String,
|
||||
@@ -580,14 +570,11 @@ pub struct MixNode {
|
||||
/// The cost parameters, or the cost function, defined for the particular mixnode that influences
|
||||
/// how the rewards should be split between the node operator and its delegators.
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NodeCostParams {
|
||||
/// The profit margin of the associated node, i.e. the desired percent of the reward to be distributed to the operator.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub profit_margin_percent: Percent,
|
||||
|
||||
/// Operating cost of the associated node per the entire interval.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub interval_operating_cost: Coin,
|
||||
}
|
||||
|
||||
@@ -682,9 +669,7 @@ pub struct PendingMixNodeChanges {
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct LegacyPendingMixNodeChanges {
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub pledge_change: Option<EpochEventId>,
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,6 @@ pub struct RoleMetadata {
|
||||
|
||||
/// Full details associated with given node.
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNodeDetails {
|
||||
/// Basic bond information of this node, such as owner address, original pledge, etc.
|
||||
pub bond_information: NymNodeBond,
|
||||
@@ -289,19 +288,14 @@ impl NymNodeDetails {
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNodeBond {
|
||||
/// Unique id assigned to the bonded node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = u32))]
|
||||
pub node_id: NodeId,
|
||||
|
||||
/// Address of the owner of this nym-node.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub owner: Addr,
|
||||
|
||||
/// Original amount pledged by the operator of this node.
|
||||
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = crate::CoinSchema))]
|
||||
pub original_pledge: Coin,
|
||||
|
||||
/// Block height at which this nym-node has been bonded.
|
||||
@@ -354,7 +348,6 @@ impl NymNodeBond {
|
||||
feature = "generate-ts",
|
||||
ts(export, export_to = "ts-packages/types/src/types/rust/NymNode.ts")
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct NymNode {
|
||||
/// Network address of this nym-node, for example 1.1.1.1 or foo.mixnode.com
|
||||
/// that is used to discover other capabilities of this node.
|
||||
@@ -365,7 +358,6 @@ pub struct NymNode {
|
||||
pub custom_http_port: Option<u16>,
|
||||
|
||||
/// Base58-encoded ed25519 EdDSA public key.
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub identity_key: IdentityKey,
|
||||
// TODO: I don't think we want to include sphinx keys here,
|
||||
// given we want to rotate them and keeping that in sync with contract will be a PITA
|
||||
@@ -443,11 +435,8 @@ pub struct NodeConfigUpdate {
|
||||
export_to = "ts-packages/types/src/types/rust/PendingNodeChanges.ts"
|
||||
)
|
||||
)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct PendingNodeChanges {
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub pledge_change: Option<EpochEventId>,
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = Option<u32>))]
|
||||
pub cost_params_change: Option<IntervalEventId>,
|
||||
}
|
||||
|
||||
|
||||
@@ -21,37 +21,31 @@ pub type WorkFactor = Decimal;
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct IntervalRewardParams {
|
||||
/// Current value of the rewarding pool.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub reward_pool: Decimal,
|
||||
|
||||
/// Current value of the staking supply.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub staking_supply: Decimal,
|
||||
|
||||
/// Defines the percentage of stake needed to reach saturation for all of the nodes in the rewarded set.
|
||||
/// Also known as `beta`.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub staking_supply_scale_factor: Percent,
|
||||
|
||||
// computed values
|
||||
/// Current value of the computed reward budget per epoch, per node.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub epoch_reward_budget: Decimal,
|
||||
|
||||
/// Current value of the stake saturation point.
|
||||
/// It is expected to be constant throughout the interval.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub stake_saturation_point: Decimal,
|
||||
|
||||
// constants(-ish)
|
||||
@@ -60,7 +54,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub sybil_resistance: Percent,
|
||||
|
||||
// default: 10
|
||||
@@ -68,7 +61,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub active_set_work_factor: Decimal,
|
||||
|
||||
// default: 2%
|
||||
@@ -78,7 +70,6 @@ pub struct IntervalRewardParams {
|
||||
/// It is not really expected to be changing very often.
|
||||
/// As a matter of fact, unless there's a very specific reason, it should remain constant.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub interval_pool_emission: Percent,
|
||||
}
|
||||
|
||||
@@ -99,7 +90,6 @@ impl IntervalRewardParams {
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardingParams {
|
||||
/// Parameters that should remain unchanged throughout an interval.
|
||||
pub interval: IntervalRewardParams,
|
||||
@@ -264,7 +254,6 @@ impl RewardingParams {
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardedSetParams {
|
||||
/// The expected number of nodes assigned entry gateway role (i.e. [`Role::EntryGateway`])
|
||||
pub entry_gateways: u32,
|
||||
|
||||
@@ -17,12 +17,10 @@ pub mod simulator;
|
||||
)]
|
||||
#[cw_serde]
|
||||
#[derive(Copy, Default)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub struct RewardEstimate {
|
||||
/// The amount of **decimal** coins that are going to get distributed to the node,
|
||||
/// i.e. the operator and all its delegators.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub total_node_reward: Decimal,
|
||||
|
||||
// note that operator reward includes the operating_cost,
|
||||
@@ -30,17 +28,14 @@ pub struct RewardEstimate {
|
||||
// in that case the operator reward would still be `1nym` as opposed to 0
|
||||
/// The share of the reward that is going to get distributed to the node operator.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operator: Decimal,
|
||||
|
||||
/// The share of the reward that is going to get distributed among the node delegators.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub delegates: Decimal,
|
||||
|
||||
/// The operating cost of this node. Note: it's already included in the operator reward.
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
#[cfg_attr(feature = "utoipa", schema(value_type = String))]
|
||||
pub operating_cost: Decimal,
|
||||
}
|
||||
|
||||
|
||||
@@ -134,14 +134,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "utoipa")]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
#[cfg_attr(feature = "utoipa", schema(title = "Coin"))]
|
||||
pub struct CoinSchema {
|
||||
pub denom: String,
|
||||
pub amount: String,
|
||||
}
|
||||
|
||||
/// The current state of the mixnet contract.
|
||||
#[cw_serde]
|
||||
pub struct ContractState {
|
||||
|
||||
@@ -33,7 +33,10 @@ use nym_credentials::{
|
||||
IssuanceTicketBook, IssuedTicketBook,
|
||||
};
|
||||
use nym_ecash_time::{ecash_today, Date, EcashTime};
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
@@ -56,6 +59,9 @@ impl PersistentStorage {
|
||||
);
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
|
||||
@@ -16,7 +16,6 @@ serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true, features = ["serde"] }
|
||||
utoipa = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
|
||||
nym-compact-ecash = { path = "../nym_offline_compact_ecash" }
|
||||
|
||||
@@ -86,6 +86,7 @@ impl Display for AddressPolicyAction {
|
||||
/// ```
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
#[cfg_attr(feature = "openapi", aliases(ExitPolicy))]
|
||||
pub struct AddressPolicy {
|
||||
/// A list of rules to apply to find out whether an address is
|
||||
/// contained by this policy.
|
||||
@@ -726,10 +727,10 @@ mod test {
|
||||
let policy = AddressPolicy::parse_from_torrc(
|
||||
r#"
|
||||
ExitPolicy reject 1.2.3.4/32:*
|
||||
ExitPolicy reject 1.2.3.5:*
|
||||
ExitPolicy reject 1.2.3.5:*
|
||||
ExitPolicy reject 1.2.3.6/16:*
|
||||
ExitPolicy reject 1.2.3.6/16:123-456
|
||||
ExitPolicy accept *:53
|
||||
ExitPolicy reject 1.2.3.6/16:123-456
|
||||
ExitPolicy accept *:53
|
||||
ExitPolicy accept6 *6:119
|
||||
ExitPolicy accept *4:120
|
||||
ExitPolicy reject6 [FC00::]/7:*
|
||||
|
||||
@@ -20,6 +20,10 @@ pub enum ClientRequest {
|
||||
hkdf_salt: Vec<u8>,
|
||||
derived_key_digest: Vec<u8>,
|
||||
},
|
||||
ForgetMe {
|
||||
client: bool,
|
||||
stats: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl ClientRequest {
|
||||
|
||||
@@ -11,6 +11,7 @@ use tungstenite::Message;
|
||||
#[non_exhaustive]
|
||||
pub enum SensitiveServerResponse {
|
||||
KeyUpgradeAck {},
|
||||
ForgetMeAck {},
|
||||
}
|
||||
|
||||
impl SensitiveServerResponse {
|
||||
|
||||
@@ -6,7 +6,10 @@ use models::StoredFinishedSession;
|
||||
use nym_node_metrics::entry::{ActiveSession, FinishedSession, SessionType};
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use sessions::SessionManager;
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use time::Date;
|
||||
use tracing::{debug, error};
|
||||
@@ -36,6 +39,9 @@ impl PersistentStatsStorage {
|
||||
// TODO: we can inject here more stuff based on our gateway global config
|
||||
// struct. Maybe different pool size or timeout intervals?
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -116,6 +122,16 @@ impl PersistentStatsStorage {
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn delete_unique_user(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), StatsStorageError> {
|
||||
Ok(self
|
||||
.session_manager
|
||||
.delete_unique_user(client_address.as_base58_string())
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn insert_active_session(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
|
||||
@@ -71,6 +71,16 @@ impl SessionManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_unique_user(&self, client_address_b58: String) -> Result<()> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM sessions_unique_users WHERE client_address = ?",
|
||||
client_address_b58
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_unique_users(&self, date: Date) -> Result<Vec<String>> {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT client_address as count FROM sessions_unique_users WHERE day = ?",
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM message_store WHERE client_address_bs58 = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3ea5542b21a41b14276a8fd6b870c61aa0ddd30fee2565803b88c6086bd2a734"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM available_bandwidth WHERE client_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a3cc707995b8215fa77738cd1a55f9e8d251a3e764104d2a54153895dee1a118"
|
||||
}
|
||||
@@ -49,6 +49,16 @@ impl BandwidthManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_client(&self, client_id: i64) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM available_bandwidth WHERE client_id = ?",
|
||||
client_id
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the expiration date of the particular client to the provided date.
|
||||
pub(crate) async fn set_expiration(
|
||||
&self,
|
||||
|
||||
@@ -133,4 +133,17 @@ impl InboxManager {
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_messages_for_client(
|
||||
&self,
|
||||
client_address_bs58: &str,
|
||||
) -> Result<(), sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"DELETE FROM message_store WHERE client_address_bs58 = ?",
|
||||
client_address_bs58
|
||||
)
|
||||
.execute(&self.connection_pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,10 @@ use nym_credentials_interface::ClientTicket;
|
||||
use nym_gateway_requests::shared_key::SharedGatewayKey;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use shared_keys::SharedKeysManager;
|
||||
use sqlx::ConnectOptions;
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
ConnectOptions,
|
||||
};
|
||||
use std::path::Path;
|
||||
use tickets::TicketStorageManager;
|
||||
use time::OffsetDateTime;
|
||||
@@ -41,6 +44,33 @@ pub struct GatewayStorage {
|
||||
}
|
||||
|
||||
impl GatewayStorage {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn client_manager(&self) -> &ClientManager {
|
||||
&self.client_manager
|
||||
}
|
||||
|
||||
pub(crate) fn shared_key_manager(&self) -> &SharedKeysManager {
|
||||
&self.shared_key_manager
|
||||
}
|
||||
|
||||
pub(crate) fn inbox_manager(&self) -> &InboxManager {
|
||||
&self.inbox_manager
|
||||
}
|
||||
|
||||
pub(crate) fn bandwidth_manager(&self) -> &BandwidthManager {
|
||||
&self.bandwidth_manager
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn ticket_manager(&self) -> &TicketStorageManager {
|
||||
&self.ticket_manager
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn wireguard_peer_manager(&self) -> &wireguard_peers::WgPeerManager {
|
||||
&self.wireguard_peer_manager
|
||||
}
|
||||
|
||||
/// Initialises `PersistentStorage` using the provided path.
|
||||
///
|
||||
/// # Arguments
|
||||
@@ -59,6 +89,9 @@ impl GatewayStorage {
|
||||
// TODO: we can inject here more stuff based on our gateway global config
|
||||
// struct. Maybe different pool size or timeout intervals?
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
@@ -101,6 +134,21 @@ impl GatewayStorage {
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn handle_forget_me(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
) -> Result<(), GatewayStorageError> {
|
||||
let client_id = self.get_mixnet_client_id(client_address).await?;
|
||||
self.inbox_manager()
|
||||
.remove_messages_for_client(&client_address.as_base58_string())
|
||||
.await?;
|
||||
self.bandwidth_manager().remove_client(client_id).await?;
|
||||
self.shared_key_manager()
|
||||
.remove_shared_keys(&client_address.as_base58_string())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_shared_keys(
|
||||
&self,
|
||||
client_address: DestinationAddressBytes,
|
||||
|
||||
@@ -324,6 +324,56 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_patch_request<B, K, V>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> RequestBuilder
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
self.reqwest_client.patch(url).json(json_body)
|
||||
}
|
||||
|
||||
pub async fn send_patch_request<B, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<Response, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display,
|
||||
{
|
||||
let url = sanitize_url(&self.base_url, path, params);
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
Ok(wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client.patch(url).json(json_body).send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
Ok(self
|
||||
.reqwest_client
|
||||
.patch(url)
|
||||
.json(json_body)
|
||||
.send()
|
||||
.await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_json<T, K, V, E>(
|
||||
&self,
|
||||
@@ -372,6 +422,23 @@ impl Client {
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn patch_json<B, T, K, V, E>(
|
||||
&self,
|
||||
path: PathSegments<'_>,
|
||||
params: Params<'_, K, V>,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
K: AsRef<str>,
|
||||
V: AsRef<str>,
|
||||
E: Display + DeserializeOwned,
|
||||
{
|
||||
let res = self.send_patch_request(path, params, json_body).await?;
|
||||
parse_response(res, true).await
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_json_endpoint<T, S, E>(&self, endpoint: S) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
@@ -466,6 +533,42 @@ impl Client {
|
||||
|
||||
parse_response(res, false).await
|
||||
}
|
||||
|
||||
pub async fn patch_json_endpoint<B, T, S, E>(
|
||||
&self,
|
||||
endpoint: S,
|
||||
json_body: &B,
|
||||
) -> Result<T, HttpClientError<E>>
|
||||
where
|
||||
B: Serialize + ?Sized,
|
||||
for<'a> T: Deserialize<'a>,
|
||||
E: Display + DeserializeOwned,
|
||||
S: AsRef<str>,
|
||||
{
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let res = {
|
||||
wasmtimer::tokio::timeout(
|
||||
self.request_timeout,
|
||||
self.reqwest_client
|
||||
.patch(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_timeout| HttpClientError::RequestTimeout)??
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let res = {
|
||||
self.reqwest_client
|
||||
.patch(self.base_url.join(endpoint.as_ref())?)
|
||||
.json(json_body)
|
||||
.send()
|
||||
.await?
|
||||
};
|
||||
|
||||
parse_response(res, true).await
|
||||
}
|
||||
}
|
||||
|
||||
// define those methods on the trait for nicer extensions (and not having to type the thing twice)
|
||||
|
||||
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub mod middleware;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
|
||||
pub enum FormattedResponse<T> {
|
||||
Json(Json<T>),
|
||||
Yaml(Yaml<T>),
|
||||
|
||||
@@ -20,7 +20,6 @@ rand = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
sha2 = "0.9"
|
||||
bs58 = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
rayon = { workspace = true, optional = true }
|
||||
zeroize = { workspace = true, features = ["zeroize_derive"] }
|
||||
@@ -64,4 +63,4 @@ par_signing = ["rayon"]
|
||||
# but given it's not done very frequently, it shouldn't be too much of a problem
|
||||
# furthermore, we can't and shouldn't dedicate the entire nym-api CPU just for verification,
|
||||
# but this feature might potentially be desirable for clients.
|
||||
par_verify = ["rayon"]
|
||||
par_verify = ["rayon"]
|
||||
@@ -4,10 +4,10 @@
|
||||
use crate::ecash_group_parameters;
|
||||
use crate::error::Result;
|
||||
use crate::helpers::{g1_tuple_to_bytes, recover_g1_tuple};
|
||||
use bls12_381::{G1Projective, Scalar};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use subtle::Choice;
|
||||
|
||||
pub use bls12_381::{G1Projective, G2Projective, Scalar};
|
||||
pub type SignerIndex = u64;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -36,7 +36,7 @@ pub mod common_types;
|
||||
pub mod constants;
|
||||
pub mod error;
|
||||
mod helpers;
|
||||
pub mod proofs;
|
||||
mod proofs;
|
||||
pub mod scheme;
|
||||
pub mod tests;
|
||||
mod traits;
|
||||
|
||||
@@ -16,7 +16,6 @@ use group::{Curve, Group};
|
||||
use itertools::Itertools;
|
||||
use std::borrow::Borrow;
|
||||
use std::ops::Neg;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub struct Polynomial {
|
||||
coefficients: Vec<Scalar>,
|
||||
@@ -52,17 +51,6 @@ impl Polynomial {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
#[schema(title = "G2Projective")]
|
||||
pub struct G2ProjectiveSchema {
|
||||
#[schema(content_encoding = "base16")]
|
||||
pub x: [u64; 6],
|
||||
#[schema(content_encoding = "base16")]
|
||||
pub y: [u64; 6],
|
||||
#[schema(content_encoding = "base16")]
|
||||
pub z: [u64; 6],
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generate_lagrangian_coefficients_at_origin(points: &[u64]) -> Vec<Scalar> {
|
||||
let x = Scalar::zero();
|
||||
|
||||
@@ -13,7 +13,11 @@ use crate::{
|
||||
models::{CommitSignature, Validator},
|
||||
},
|
||||
};
|
||||
use sqlx::{types::time::OffsetDateTime, ConnectOptions, Sqlite, Transaction};
|
||||
use sqlx::{
|
||||
sqlite::{SqliteAutoVacuum, SqliteSynchronous},
|
||||
types::time::OffsetDateTime,
|
||||
ConnectOptions, Sqlite, Transaction,
|
||||
};
|
||||
use std::{fmt::Debug, path::Path};
|
||||
use tendermint::{
|
||||
block::{Commit, CommitSig},
|
||||
@@ -51,6 +55,9 @@ impl ScraperStorage {
|
||||
#[instrument]
|
||||
pub async fn init<P: AsRef<Path> + Debug>(database_path: P) -> Result<Self, ScraperError> {
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.disable_statement_logging();
|
||||
|
||||
@@ -58,6 +58,10 @@ pub enum GatewaySessionEvent {
|
||||
/// Address of the remote client opening the connection
|
||||
client: DestinationAddressBytes,
|
||||
},
|
||||
SessionDelete {
|
||||
/// Address of the remote client opening the connection
|
||||
client: DestinationAddressBytes,
|
||||
},
|
||||
}
|
||||
|
||||
impl GatewaySessionEvent {
|
||||
@@ -87,4 +91,8 @@ impl GatewaySessionEvent {
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_session_delete(client: DestinationAddressBytes) -> GatewaySessionEvent {
|
||||
GatewaySessionEvent::SessionDelete { client }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ readme.workspace = true
|
||||
sha2 = { workspace = true }
|
||||
rs_merkle = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
time = { workspace = true }
|
||||
|
||||
@@ -24,4 +23,4 @@ nym-serde-helpers = { path = "../serde-helpers", features = ["date", "base64", "
|
||||
[dev-dependencies]
|
||||
rand_chacha = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
@@ -14,18 +14,15 @@ use serde::{Deserialize, Serialize};
|
||||
use sha2::Digest;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use time::Date;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
// no point in importing the entire contract commons just for this one type
|
||||
pub type DepositId = u32;
|
||||
pub type DKGEpochId = u64;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbook {
|
||||
#[schema(value_type = u32)]
|
||||
pub deposit_id: DepositId,
|
||||
#[schema(value_type = u32)]
|
||||
pub epoch_id: DKGEpochId,
|
||||
|
||||
// 96 bytes serialised 'BlindedSignature'
|
||||
@@ -40,11 +37,9 @@ pub struct IssuedTicketbook {
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::date")]
|
||||
#[schema(value_type = String)]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
@@ -85,7 +80,7 @@ pub struct InsertedMerkleLeaf {
|
||||
pub leaf: MerkleLeaf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialOrd, PartialEq, Eq, ToSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialOrd, PartialEq, Eq)]
|
||||
pub struct MerkleLeaf {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::hex")]
|
||||
@@ -167,14 +162,16 @@ impl IssuedTicketbooksMerkleTree {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct IssuedTicketbooksFullMerkleProof {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "inner_proof_base64_serde")]
|
||||
#[schema(value_type = String)]
|
||||
inner_proof: MerkleProof<Sha256>,
|
||||
|
||||
included_leaves: Vec<MerkleLeaf>,
|
||||
|
||||
total_leaves: usize,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "nym_serde_helpers::hex")]
|
||||
root: Vec<u8>,
|
||||
|
||||
@@ -22,7 +22,6 @@ strum = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
ts-rs = { workspace = true }
|
||||
url = { workspace = true }
|
||||
utoipa = { workspace = true }
|
||||
x25519-dalek = { workspace = true, features = ["static_secrets"] }
|
||||
|
||||
cosmwasm-std = { workspace = true }
|
||||
|
||||
@@ -3,7 +3,6 @@ use nym_mixnet_contract_common::NodeId;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, sync::LazyLock, time::SystemTime};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
|
||||
let mut nm = HashSet::new();
|
||||
@@ -11,9 +10,8 @@ static NETWORK_MONITORS: LazyLock<HashSet<String>> = LazyLock::new(|| {
|
||||
nm
|
||||
});
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, ToSchema)]
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone)]
|
||||
pub struct NodeResult {
|
||||
#[schema(value_type = u32)]
|
||||
pub node_id: NodeId,
|
||||
pub identity: String,
|
||||
pub reliability: u8,
|
||||
@@ -36,7 +34,7 @@ pub enum MonitorResults {
|
||||
Gateway(Vec<NodeResult>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||
pub struct MonitorMessage {
|
||||
results: Vec<NodeResult>,
|
||||
signature: String,
|
||||
|
||||
@@ -4,8 +4,6 @@ The information below is generated with [Redoc](https://redocly.com/docs/redoc)
|
||||
|
||||
There is also an overview of other Validator endpoints at [https://cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://api.nymtech.net/swagger/swagger.yaml"
|
||||
options={{
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://api.sandbox.nymtech.net/swagger/swagger.yaml](https://api.sandbox.nymtech.net/swagger/swagger.yaml).
|
||||
|
||||
<br /><br />
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at []() which is also used to generate the Swagger docs deployed at []().
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://api.sandbox.nymtech.net/swagger/swagger.yaml"
|
||||
specUrl=""
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
|
||||
@@ -3,8 +3,6 @@ import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://explorer.nymtech.net/api/v1/openapi.json](https://explorer.nymtech.net/api/v1/openapi.json) which is also used to generate the Swagger docs deployed at [https://explorer.nymtech.net/api/swagger/index.html](https://explorer.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-explorer.nymtech.net/api/v1/openapi.json"
|
||||
options={{
|
||||
|
||||
@@ -2,8 +2,6 @@ import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://sandbox-explorer.nymtech.net/api/v1/openapi.json](https://sandbox-explorer.nymtech.net/api/v1/openapi.json) which is also used to generate the Swagger docs deployed at [https://sandbox-explorer.nymtech.net/api/swagger/index.html](https://sandbox-explorer.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-explorer.nymtech.net/api/v1/openapi.json"
|
||||
options={{
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
description: Interactive APIs generated from the OpenAPI specs of various API endpoints offered by bits of Nym infrastructure run both by Nym and community operators for both Mainnet and the Sandbox testnet.
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
This site contains interactive APIs generated from the OpenAPI specs of various API endpoints offered by bits of Nym infrastructure run both by Nym and community operators for both Mainnet and the Sandbox testnet.
|
||||
|
||||
@@ -2,8 +2,6 @@ import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json](https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://mainnet-node-status-api.nymtech.cc/swagger/](https://mainnet-node-status-api.nymtech.cc/swagger/).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://mainnet-node-status-api.nymtech.cc/api-docs/openapi.json"
|
||||
options={{
|
||||
|
||||
@@ -2,8 +2,6 @@ import { RedocStandalone } from 'redoc';
|
||||
|
||||
The information below is generated with [Redoc](https://redocly.com/docs/redoc) consuming the OpenAPI spec found at [https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json](https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://sandbox-node-status-api.nymte.ch/swagger/](https://sandbox-node-status-api.nymte.ch/swagger/).
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="https://sandbox-node-status-api.nymte.ch/api-docs/openapi.json"
|
||||
options={{
|
||||
|
||||
@@ -1,27 +1,10 @@
|
||||
import APITable from 'components/api-table.tsx';
|
||||
import { RedocStandalone } from 'redoc';
|
||||
import { Callout } from 'nextra/components'
|
||||
|
||||
You can find the OpenAPI spec found at [https://validator.nymtech.net/api-docs/openapi.json](https://validator.nymtech.net/api-docs/openapi.json) which is also used to generate the Swagger docs deployed at [https://validator.nymtech.net/api/swagger/index.html](https://validator.nymtech.net/api/swagger/index.html).
|
||||
|
||||
<Callout type="info" emoji="ℹ️">
|
||||
You can find the Swagger endpoints of other NymAPI instances at the following endpoints:
|
||||
<APITable endpoint="https://api.nymtech.net/cosmwasm/wasm/v1/contract/n19604yflqggs9mk2z26mqygq43q2kr3n932egxx630svywd5mpxjsztfpvx/smart/eyJnZXRfY3VycmVudF9kZWFsZXJzIjogeyJsaW1pdCI6IDMwfX0=" />
|
||||
|
||||
There is also an overview of endpoints at [https://cosmos.directory/nyx](https://cosmos.directory/nyx).
|
||||
</Callout>
|
||||
|
||||
<br /><br />
|
||||
|
||||
<RedocStandalone
|
||||
specUrl="http://localhost:8000/api-docs/openapi.json"
|
||||
options={{
|
||||
nativeScrollbars: true,
|
||||
theme: {
|
||||
sidebar: {
|
||||
backgroundColor: '#273239',
|
||||
textColor: '#FCFDFE'
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
> Interactive Redoc component coming soon
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
description: Nym's developer documentation covering core concepts of integrating with the Mixnet, interacting with the Nyx blockchain, an overview of the avaliable tools, and our SDK docs.
|
||||
---
|
||||
|
||||
# Introduction
|
||||
Nym's developer documentation covering core concepts of integrating with the Mixnet, interacting with the Nyx blockchain, an overview of the avaliable tools, and our SDK docs.
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
description: Nym's network documentation covering network architecture, node types, tokenomics, and cryptography.
|
||||
---
|
||||
|
||||
# Introduction
|
||||
Nym's network documentation covering network architecture, node types, tokenomics, and crypto systems.
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
---
|
||||
description: Nym's Operators guide containing information and setup guides for the various components of Nym network and Nyx blockchain validators.
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
This is **Nym's Operators guide**, containing information and setup guides for the various components of Nym network and Nyx blockchain validators.
|
||||
|
||||
@@ -222,7 +222,7 @@ Good performance is much more essential than [total stake](../tokenomics.mdx#sta
|
||||
For a comparison we made an example with 5 nodes, where first number is node performance and second stake saturation (assuming all of them `config_score` = 1 for simplification):
|
||||
|
||||
<br />
|
||||
<AccordionTemplate name="✏️ Example: Performance ^ 20 \* total_stake calculation">
|
||||
<AccordionTemplate name="✏️ Example: Performance ^ 20 * total_stake calculation">
|
||||
> node_1 = 1.00 ^ 20 \* 1.0 = 1 <br />
|
||||
> node_2 = 1.00 ^ 20 \* 0.5 = 0.5 <br />
|
||||
> node_3 = 0.99 ^ 20 \* 1.0 = 0.818 <br />
|
||||
|
||||
@@ -11,10 +11,23 @@ const config: DocsThemeConfig = {
|
||||
const url = process.env.NEXT_PUBLIC_SITE_URL
|
||||
const image = url + '/nym_logo.jpg'
|
||||
|
||||
// Define descriptions for different "books"
|
||||
const bookDescriptions: Record<string, string> = {
|
||||
'/developers': "Nym's developer documentation covering core concepts of integrating with the Mixnet, interacting with the Nyx blockchain, an overview of the avaliable tools, and our SDK docs.",
|
||||
'/network': "Nym's network documentation covering network architecture, node types, tokenomics, and cryptography.",
|
||||
'/operators': "Nym's Operators guide containing information and setup guides for the various components of Nym network and Nyx blockchain validators.",
|
||||
'/apis': "Interactive APIs generated from the OpenAPI specs of various API endpoints offered by bits of Nym infrastructure run both by Nym and community operators for both Mainnet and the Sandbox testnet."
|
||||
}
|
||||
|
||||
const defaultDescription = 'Nym is a privacy platform. It provides strong network-level privacy against sophisticated end-to-end attackers, and anonymous access control using blinded, re-randomizable, decentralized credentials.'
|
||||
|
||||
const topLevel = '/' + route.split('/')[1]
|
||||
const description =
|
||||
config.frontMatter.description ||
|
||||
'Nym is a privacy platform. It provides strong network-level privacy against sophisticated end-to-end attackers, and anonymous access control using blinded, re-randomizable, decentralized credentials.'
|
||||
const title = config.title + (route === '/' ? '' : ' - Nym docs')
|
||||
bookDescriptions[topLevel] ||
|
||||
defaultDescription
|
||||
|
||||
const title = config.title + (route === '/' ? '' : ' - Nym docs')
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,3 +21,9 @@ pub(crate) struct CommonHandlerState {
|
||||
pub(crate) outbound_mix_sender: MixForwardingSender,
|
||||
pub(crate) active_clients_store: ActiveClientsStore,
|
||||
}
|
||||
|
||||
impl CommonHandlerState {
|
||||
pub(crate) fn storage(&self) -> &GatewayStorage {
|
||||
&self.storage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,10 @@ impl<R, S> Drop for AuthenticatedHandler<R, S> {
|
||||
}
|
||||
|
||||
impl<R, S> AuthenticatedHandler<R, S> {
|
||||
pub(crate) fn inner(&self) -> &FreshHandler<R, S> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Upgrades `FreshHandler` into the Authenticated variant implying the client is now authenticated
|
||||
/// and thus allowed to perform more actions with the gateway, such as redeeming bandwidth or
|
||||
/// sending sphinx packets.
|
||||
@@ -327,6 +331,24 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_forget_me(
|
||||
&mut self,
|
||||
client: bool,
|
||||
stats: bool,
|
||||
) -> Result<ServerResponse, RequestHandlingError> {
|
||||
if client {
|
||||
self.inner()
|
||||
.shared_state()
|
||||
.storage()
|
||||
.handle_forget_me(self.client.address)
|
||||
.await?;
|
||||
}
|
||||
if stats {
|
||||
self.send_metrics(GatewaySessionEvent::new_session_delete(self.client.address));
|
||||
}
|
||||
Ok(SensitiveServerResponse::ForgetMeAck {}.encrypt(&self.client.shared_keys)?)
|
||||
}
|
||||
|
||||
async fn handle_key_upgrade(
|
||||
&mut self,
|
||||
hkdf_salt: Vec<u8>,
|
||||
@@ -370,6 +392,7 @@ impl<R, S> AuthenticatedHandler<R, S> {
|
||||
hkdf_salt,
|
||||
derived_key_digest,
|
||||
} => self.handle_key_upgrade(hkdf_salt, derived_key_digest).await,
|
||||
ClientRequest::ForgetMe { client, stats } => self.handle_forget_me(client, stats).await,
|
||||
_ => Err(RequestHandlingError::UnknownEncryptedTextRequest),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,10 @@ pub(crate) struct FreshHandler<R, S> {
|
||||
}
|
||||
|
||||
impl<R, S> FreshHandler<R, S> {
|
||||
pub(crate) fn shared_state(&self) -> &CommonHandlerState {
|
||||
&self.shared_state
|
||||
}
|
||||
|
||||
// for time being we assume handle is always constructed from raw socket.
|
||||
// if we decide we want to change it, that's not too difficult
|
||||
// also at this point I'm not entirely sure how to deal with this warning without
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ nym-gateway-client = { path = "../common/client-libs/gateway-client" }
|
||||
nym-inclusion-probability = { path = "../common/inclusion-probability" }
|
||||
nym-mixnet-contract-common = { path = "../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] }
|
||||
nym-vesting-contract-common = { path = "../common/cosmwasm-smart-contracts/vesting-contract" }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float", "utoipa"] }
|
||||
nym-contracts-common = { path = "../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float"] }
|
||||
nym-multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" }
|
||||
nym-coconut = { path = "../common/nymcoconut", features = ["key-zeroize"] }
|
||||
nym-sphinx = { path = "../common/nymsphinx" }
|
||||
|
||||
@@ -31,7 +31,7 @@ nym-crypto = { path = "../../common/crypto", features = ["serde", "asymmetric"]
|
||||
nym-ecash-time = { path = "../../common/ecash-time" }
|
||||
nym-compact-ecash = { path = "../../common/nym_offline_compact_ecash" }
|
||||
nym-contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common", features = ["naive_float"] }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract", features = ["utoipa"] }
|
||||
nym-mixnet-contract-common = { path = "../../common/cosmwasm-smart-contracts/mixnet-contract" }
|
||||
nym-node-requests = { path = "../../nym-node/nym-node-requests", default-features = false, features = ["openapi"] }
|
||||
nym-network-defaults = { path = "../../common/network-defaults" }
|
||||
nym-ticketbooks-merkle = { path = "../../common/ticketbooks-merkle" }
|
||||
|
||||
@@ -27,12 +27,10 @@ use utoipa::ToSchema;
|
||||
pub struct VerifyEcashTicketBody {
|
||||
/// The cryptographic material required for spending the underlying credential.
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub credential: CredentialSpendingData,
|
||||
|
||||
/// Cosmos address of the sender of the credential
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
}
|
||||
|
||||
@@ -40,12 +38,10 @@ pub struct VerifyEcashTicketBody {
|
||||
pub struct VerifyEcashCredentialBody {
|
||||
/// The cryptographic material required for spending the underlying credential.
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::CredentialSpendingData)]
|
||||
pub credential: CredentialSpendingData,
|
||||
|
||||
/// Cosmos address of the sender of the credential
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
|
||||
/// Multisig proposal for releasing funds for the provided bandwidth credential
|
||||
@@ -66,16 +62,8 @@ impl VerifyEcashCredentialBody {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used exclusively as part of OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub enum EcashTicketVerificationResult {
|
||||
Ok(()),
|
||||
EcashTicketVerificationRejection,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct EcashTicketVerificationResponse {
|
||||
#[schema(value_type = EcashTicketVerificationResult)]
|
||||
pub verified: Result<(), EcashTicketVerificationRejection>,
|
||||
}
|
||||
|
||||
@@ -93,15 +81,12 @@ pub enum EcashTicketVerificationRejection {
|
||||
InvalidSpentDate {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
today: Date,
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
yesterday: Date,
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
received: Date,
|
||||
},
|
||||
|
||||
@@ -124,7 +109,6 @@ pub enum EcashTicketVerificationRejection {
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, JsonSchema, ToSchema)]
|
||||
pub struct BlindSignRequestBody {
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::WithdrawalRequest)]
|
||||
pub inner_sign_request: WithdrawalRequest,
|
||||
|
||||
/// the id of the associated deposit
|
||||
@@ -132,20 +116,16 @@ pub struct BlindSignRequestBody {
|
||||
|
||||
/// Signature on the inner sign request and the tx hash
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: identity::Signature,
|
||||
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::PublicKeyUser)]
|
||||
pub ecash_pubkey: PublicKeyUser,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ticketbook_type: TicketType,
|
||||
}
|
||||
|
||||
@@ -203,7 +183,6 @@ impl BlindSignRequestBody {
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct BlindedSignatureResponse {
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::BlindedSignature)]
|
||||
pub blinded_signature: BlindedSignature,
|
||||
}
|
||||
|
||||
@@ -235,7 +214,6 @@ impl BlindedSignatureResponse {
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct MasterVerificationKeyResponse {
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::VerificationKeyAuth)]
|
||||
pub key: VerificationKeyAuth,
|
||||
}
|
||||
|
||||
@@ -248,7 +226,6 @@ impl MasterVerificationKeyResponse {
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct VerificationKeyResponse {
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::VerificationKeyAuth)]
|
||||
pub key: VerificationKeyAuth,
|
||||
}
|
||||
|
||||
@@ -276,10 +253,9 @@ pub struct PartialExpirationDateSignatureResponse {
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
#[schema(value_type = String)]
|
||||
pub expiration_date: Date,
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::AnnotatedExpirationDateSignature)]
|
||||
pub signatures: Vec<AnnotatedExpirationDateSignature>,
|
||||
}
|
||||
|
||||
@@ -287,7 +263,6 @@ pub struct PartialExpirationDateSignatureResponse {
|
||||
pub struct PartialCoinIndicesSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::AnnotatedCoinIndexSignature)]
|
||||
pub signatures: Vec<AnnotatedCoinIndexSignature>,
|
||||
}
|
||||
|
||||
@@ -297,11 +272,9 @@ pub struct AggregatedExpirationDateSignatureResponse {
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = Vec<openapi_schema::AnnotatedExpirationDateSignature>)]
|
||||
pub signatures: Vec<AnnotatedExpirationDateSignature>,
|
||||
}
|
||||
|
||||
@@ -309,155 +282,9 @@ pub struct AggregatedExpirationDateSignatureResponse {
|
||||
pub struct AggregatedCoinIndicesSignatureResponse {
|
||||
pub epoch_id: u64,
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = openapi_schema::Signature)]
|
||||
pub signatures: Vec<AnnotatedCoinIndexSignature>,
|
||||
}
|
||||
|
||||
/// duplicate types from `nym-compact-ecash`, but these do derive `ToSchema```
|
||||
pub mod openapi_schema {
|
||||
#![allow(dead_code)]
|
||||
use nym_compact_ecash::common_types::{G2Projective, Scalar};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct AnnotatedExpirationDateSignature {
|
||||
pub signature: Signature,
|
||||
pub expiration_timestamp: u32,
|
||||
pub spending_timestamp: u32,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct AnnotatedCoinIndexSignature {
|
||||
pub signature: Signature,
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct Signature {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) h: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) s: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct PublicKeyUser {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) pk: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct BlindedSignature {
|
||||
#[schema(value_type = String)]
|
||||
pub h: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub c: G1Projective,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct VerificationKeyAuth {
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) alpha: G2Projective,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub(crate) beta_g1: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub(crate) beta_g2: Vec<G2Projective>,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct WithdrawalRequest {
|
||||
#[schema(value_type = String)]
|
||||
joined_commitment_hash: G1Projective,
|
||||
#[schema(value_type = String)]
|
||||
joined_commitment: G1Projective,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
private_attributes_commitments: Vec<G1Projective>,
|
||||
zk_proof: WithdrawalReqProof,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct WithdrawalReqProof {
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
challenge: Scalar,
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
response_opening: Scalar,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
response_openings: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
response_attributes: Vec<Scalar>,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct CredentialSpendingData {
|
||||
pub payment: Payment,
|
||||
|
||||
#[schema(value_type = [u8; 72], format = Binary)]
|
||||
pub pay_info: PayInfo,
|
||||
|
||||
pub spend_date: Date,
|
||||
|
||||
// pub value: u64,
|
||||
/// The (DKG) epoch id under which the credential has been issued so that the verifier could use correct verification key for validation.
|
||||
pub epoch_id: u64,
|
||||
}
|
||||
|
||||
#[derive(ToSchema)]
|
||||
pub struct Payment {
|
||||
#[schema(value_type = String)]
|
||||
pub kappa: G2Projective,
|
||||
#[schema(value_type = String)]
|
||||
pub kappa_e: G2Projective,
|
||||
pub sig: Signature,
|
||||
|
||||
pub sig_exp: Signature,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub kappa_k: Vec<G2Projective>,
|
||||
pub omega: Vec<Signature>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ss: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub tt: Vec<G1Projective>,
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub aa: Vec<G1Projective>,
|
||||
pub spend_value: u64,
|
||||
#[schema(value_type = String)]
|
||||
pub cc: G1Projective,
|
||||
pub t_type: u8,
|
||||
pub zk_proof: SpendProof,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, ToSchema)]
|
||||
pub struct PayInfo {
|
||||
#[schema(content_encoding = "base16")]
|
||||
pub pay_info_bytes: [u8; 72],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
|
||||
pub struct SpendProof {
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
challenge: Scalar,
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
response_r: Scalar,
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
response_r_e: Scalar,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_r_k: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_l: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_o_a: Vec<Scalar>,
|
||||
#[schema(value_type = [u64; 4], format = Binary)]
|
||||
response_o_c: Scalar,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_mu: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_o_mu: Vec<Scalar>,
|
||||
#[schema(value_type = Vec<[u64; 4]>, format = Binary)]
|
||||
responses_attributes: Vec<Scalar>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct Pagination<T> {
|
||||
/// last_key is the last value returned in the previous query.
|
||||
@@ -470,7 +297,7 @@ pub struct Pagination<T> {
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
|
||||
pub struct SerialNumberWrapper(
|
||||
#[serde(with = "nym_serde_helpers::bs58")]
|
||||
#[schemars(with = "String")]
|
||||
@@ -496,7 +323,7 @@ impl From<Vec<u8>> for SerialNumberWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, PartialEq)]
|
||||
pub struct BatchRedeemTicketsBody {
|
||||
#[serde(with = "nym_serde_helpers::bs58")]
|
||||
#[schemars(with = "String")]
|
||||
@@ -504,7 +331,6 @@ pub struct BatchRedeemTicketsBody {
|
||||
pub included_serial_numbers: Vec<SerialNumberWrapper>,
|
||||
pub proposal_id: u64,
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub gateway_cosmos_addr: AccountId,
|
||||
}
|
||||
|
||||
@@ -565,7 +391,6 @@ pub type DepositId = u32;
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CommitedDeposit {
|
||||
#[schema(value_type = u32)]
|
||||
pub deposit_id: DepositId,
|
||||
pub merkle_index: usize,
|
||||
}
|
||||
@@ -575,7 +400,6 @@ pub struct CommitedDeposit {
|
||||
pub struct IssuedTicketbooksForResponseBody {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
pub deposits: Vec<CommitedDeposit>,
|
||||
pub merkle_root: Option<[u8; 32]>,
|
||||
@@ -600,9 +424,8 @@ impl IssuedTicketbooksForResponseBody {
|
||||
pub struct IssuedTicketbooksForResponse {
|
||||
pub body: IssuedTicketbooksForResponseBody,
|
||||
|
||||
/// Signature on the body
|
||||
/// Signature on the body
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: identity::Signature,
|
||||
}
|
||||
|
||||
@@ -619,9 +442,7 @@ impl IssuedTicketbooksForResponse {
|
||||
pub struct IssuedTicketbooksChallengeRequest {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
#[schema(value_type = Vec<u32>)]
|
||||
pub deposits: Vec<DepositId>,
|
||||
}
|
||||
|
||||
@@ -630,10 +451,8 @@ pub struct IssuedTicketbooksChallengeRequest {
|
||||
pub struct IssuedTicketbooksChallengeResponseBody {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[schema(value_type = String, example = "1970-01-01")]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schema(value_type = BTreeMap<u32, IssuedTicketbook>)]
|
||||
pub partial_ticketbooks: BTreeMap<DepositId, IssuedTicketbook>,
|
||||
pub merkle_proof: IssuedTicketbooksFullMerkleProof,
|
||||
}
|
||||
@@ -667,13 +486,12 @@ impl IssuedTicketbooksChallengeResponseBody {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, JsonSchema, ToSchema, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuedTicketbooksChallengeResponse {
|
||||
pub body: IssuedTicketbooksChallengeResponseBody,
|
||||
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: identity::Signature,
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ impl From<LegacyMixNodeBondWithLayer> for MixNodeBond {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct LegacyMixNodeDetailsWithLayer {
|
||||
/// Basic bond information of this mixnode, such as owner address, original pledge, etc.
|
||||
pub bond_information: LegacyMixNodeBondWithLayer,
|
||||
|
||||
@@ -41,7 +41,7 @@ use thiserror::Error;
|
||||
use time::{Date, OffsetDateTime};
|
||||
use utoipa::{IntoParams, ToResponse, ToSchema};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, ToSchema, ToResponse)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
pub struct RequestError {
|
||||
message: String,
|
||||
}
|
||||
@@ -70,7 +70,7 @@ impl Display for RequestError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -143,7 +143,7 @@ pub struct NodePerformance {
|
||||
pub last_24h: Performance,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, JsonSchema, ToSchema)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
@@ -188,7 +188,7 @@ impl From<DisplayRole> for Role {
|
||||
// imo for now there's no point in exposing more than that,
|
||||
// nym-api shouldn't be calculating apy or stake saturation for you.
|
||||
// it should just return its own metrics (performance) and then you can do with it as you wish
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -200,14 +200,13 @@ impl From<DisplayRole> for Role {
|
||||
pub struct NodeAnnotation {
|
||||
#[cfg_attr(feature = "generate-ts", ts(type = "string"))]
|
||||
// legacy
|
||||
#[schema(value_type = String)]
|
||||
pub last_24h_performance: Performance,
|
||||
pub current_role: Option<DisplayRole>,
|
||||
|
||||
pub detailed_performance: DetailedNodePerformance,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -243,7 +242,7 @@ impl DetailedNodePerformance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -265,7 +264,7 @@ impl RoutingScore {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
@@ -396,15 +395,12 @@ pub struct MixNodeBondAnnotated {
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Performance,
|
||||
pub node_performance: NodePerformance,
|
||||
#[schema(value_type = String)]
|
||||
pub estimated_operator_apy: Decimal,
|
||||
#[schema(value_type = String)]
|
||||
pub estimated_delegators_apy: Decimal,
|
||||
pub blacklisted: bool,
|
||||
|
||||
// a rather temporary thing until we query self-described endpoints of mixnodes
|
||||
#[serde(default)]
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -473,13 +469,11 @@ pub struct GatewayBondAnnotated {
|
||||
pub self_described: Option<GatewayDescription>,
|
||||
|
||||
// NOTE: the performance field is deprecated in favour of node_performance
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Performance,
|
||||
pub node_performance: NodePerformance,
|
||||
pub blacklisted: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -530,24 +524,21 @@ impl GatewayBondAnnotated {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct GatewayDescription {
|
||||
// for now only expose what we need. this struct will evolve in the future (or be incorporated into nym-node properly)
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, ToSchema, IntoParams)]
|
||||
pub struct ComputeRewardEstParam {
|
||||
#[schema(value_type = Option<String>)]
|
||||
#[param(value_type = Option<String>)]
|
||||
#[schema(value_type = String)]
|
||||
pub performance: Option<Performance>,
|
||||
pub active_in_rewarded_set: Option<bool>,
|
||||
pub pledge_amount: Option<u64>,
|
||||
pub total_delegation: Option<u64>,
|
||||
#[schema(value_type = Option<CoinSchema>)]
|
||||
#[param(value_type = Option<CoinSchema>)]
|
||||
#[schema(value_type = CoinSchema)]
|
||||
pub interval_operating_cost: Option<Coin>,
|
||||
#[schema(value_type = Option<String>)]
|
||||
#[param(value_type = Option<String>)]
|
||||
#[schema(value_type = String)]
|
||||
pub profit_margin_percent: Option<Percent>,
|
||||
}
|
||||
|
||||
@@ -705,11 +696,8 @@ pub struct MixnodeStatusReportResponse {
|
||||
pub mix_id: NodeId,
|
||||
pub identity: IdentityKey,
|
||||
pub owner: String,
|
||||
#[schema(value_type = u8)]
|
||||
pub most_recent: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub last_hour: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub last_day: Uptime,
|
||||
}
|
||||
|
||||
@@ -835,7 +823,6 @@ pub struct CirculatingSupplyResponse {
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct HostInformation {
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_address: Vec<IpAddr>,
|
||||
pub hostname: Option<String>,
|
||||
pub keys: HostKeys,
|
||||
@@ -855,18 +842,15 @@ impl From<nym_node_requests::api::v1::node::models::HostInformation> for HostInf
|
||||
pub struct HostKeys {
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ed25519: ed25519::PublicKey,
|
||||
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519: x25519::PublicKey,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(with = "option_bs58_x25519_pubkey")]
|
||||
#[schemars(with = "Option<String>")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519_noise: Option<x25519::PublicKey>,
|
||||
}
|
||||
|
||||
@@ -910,7 +894,6 @@ pub struct OffsetDateTimeJsonSchemaWrapper(
|
||||
default = "unix_epoch",
|
||||
with = "crate::helpers::overengineered_offset_date_time_serde"
|
||||
)]
|
||||
#[schema(inline)]
|
||||
pub OffsetDateTime,
|
||||
);
|
||||
|
||||
@@ -1248,13 +1231,13 @@ pub struct SignerInformationResponse {
|
||||
pub verification_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, Default, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, Default)]
|
||||
pub struct TestNode {
|
||||
pub node_id: Option<u32>,
|
||||
pub identity_key: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct TestRoute {
|
||||
pub gateway: TestNode,
|
||||
pub layer1: TestNode,
|
||||
@@ -1289,12 +1272,10 @@ pub struct NetworkMonitorRunDetailsResponse {
|
||||
pub struct NoiseDetails {
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25119_pubkey: x25519::PublicKey,
|
||||
|
||||
pub mixnet_port: u16,
|
||||
|
||||
#[schema(value_type = Vec<String>)]
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
}
|
||||
|
||||
@@ -1302,14 +1283,12 @@ pub struct NoiseDetails {
|
||||
pub struct NodeRefreshBody {
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub node_identity: ed25519::PublicKey,
|
||||
|
||||
// a poor man's nonce
|
||||
pub request_timestamp: i64,
|
||||
|
||||
#[schemars(with = "PlaceholderJsonSchemaImpl")]
|
||||
#[schema(value_type = String)]
|
||||
pub signature: ed25519::Signature,
|
||||
}
|
||||
|
||||
|
||||
@@ -14,19 +14,19 @@ use std::net::IpAddr;
|
||||
use time::OffsetDateTime;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct CachedNodesResponse<T: ToSchema> {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
|
||||
pub struct CachedNodesResponse<T> {
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
pub nodes: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: ToSchema> From<Vec<T>> for CachedNodesResponse<T> {
|
||||
impl<T> From<Vec<T>> for CachedNodesResponse<T> {
|
||||
fn from(nodes: Vec<T>) -> Self {
|
||||
CachedNodesResponse::new(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToSchema> CachedNodesResponse<T> {
|
||||
impl<T> CachedNodesResponse<T> {
|
||||
pub fn new(nodes: Vec<T>) -> Self {
|
||||
CachedNodesResponse {
|
||||
refreshed_at: OffsetDateTime::now_utc().into(),
|
||||
@@ -129,7 +129,6 @@ pub struct SkimmedNode {
|
||||
|
||||
#[serde(with = "bs58_ed25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub ed25519_identity_pubkey: ed25519::PublicKey,
|
||||
|
||||
#[schema(value_type = Vec<String>)]
|
||||
@@ -140,7 +139,6 @@ pub struct SkimmedNode {
|
||||
|
||||
#[serde(with = "bs58_x25519_pubkey")]
|
||||
#[schemars(with = "String")]
|
||||
#[schema(value_type = String)]
|
||||
pub x25519_sphinx_pubkey: x25519::PublicKey,
|
||||
|
||||
#[serde(alias = "epoch_role")]
|
||||
|
||||
@@ -48,7 +48,7 @@ pub(crate) struct ExpirationDatePathParam {
|
||||
context_path = "/v1/ecash",
|
||||
responses(
|
||||
(status = 200, body = IssuedTicketbooksForResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_for(
|
||||
@@ -73,7 +73,7 @@ async fn issued_ticketbooks_for(
|
||||
context_path = "/v1/ecash",
|
||||
responses(
|
||||
(status = 200, body = IssuedTicketbooksChallengeResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn issued_ticketbooks_challenge(
|
||||
|
||||
@@ -42,7 +42,7 @@ pub(crate) fn partial_signing_routes() -> Router<AppState> {
|
||||
path = "/v1/ecash/blind-sign",
|
||||
responses(
|
||||
(status = 200, body = BlindedSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
|
||||
)
|
||||
)]
|
||||
@@ -118,7 +118,7 @@ struct ExpirationDateParam {
|
||||
path = "/v1/ecash/partial-expiration-date-signatures",
|
||||
responses(
|
||||
(status = 200, body = PartialExpirationDateSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn partial_expiration_date_signatures(
|
||||
@@ -156,7 +156,7 @@ async fn partial_expiration_date_signatures(
|
||||
path = "/v1/ecash/partial-coin-indices-signatures",
|
||||
responses(
|
||||
(status = 200, body = PartialExpirationDateSignatureResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn partial_coin_indices_signatures(
|
||||
|
||||
@@ -52,7 +52,7 @@ fn reject_ticket(
|
||||
path = "/v1/ecash/verify-ecash-ticket",
|
||||
responses(
|
||||
(status = 200, body = EcashTicketVerificationResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn verify_ticket(
|
||||
@@ -155,7 +155,7 @@ async fn verify_ticket(
|
||||
path = "/v1/ecash/batch-redeem-ecash-tickets",
|
||||
responses(
|
||||
(status = 200, body = EcashBatchTicketRedemptionResponse),
|
||||
(status = 400, body = String, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
(status = 400, body = ErrorResponse, description = "this nym-api is not an ecash signer in the current epoch"),
|
||||
)
|
||||
)]
|
||||
async fn batch_redeem_tickets(
|
||||
@@ -235,7 +235,7 @@ async fn batch_redeem_tickets(
|
||||
get,
|
||||
path = "/v1/ecash/double-spending-filter-v1",
|
||||
responses(
|
||||
(status = 500, body = String, description = "bloomfilters got disabled"),
|
||||
(status = 500, body = ErrorResponse, description = "bloomfilters got disabled"),
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -47,19 +47,12 @@ pub(crate) struct ContractVersionSchemaResponse {
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub struct ContractInformationContractVersion {
|
||||
pub(crate) address: Option<String>,
|
||||
pub(crate) details: Option<ContractVersionSchemaResponse>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "network",
|
||||
get,
|
||||
path = "/v1/network/nym-contracts",
|
||||
responses(
|
||||
(status = 200, body = HashMap<String, ContractInformationContractVersion>)
|
||||
(status = 200, body = HashMap<String, ContractInformation<ContractVersionSchemaResponse>>)
|
||||
)
|
||||
)]
|
||||
async fn nym_contracts(
|
||||
@@ -80,19 +73,12 @@ async fn nym_contracts(
|
||||
.into()
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
pub struct ContractInformationBuildInformation {
|
||||
pub(crate) address: Option<String>,
|
||||
pub(crate) details: Option<ContractBuildInformation>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "network",
|
||||
get,
|
||||
path = "/v1/network/nym-contracts-detailed",
|
||||
responses(
|
||||
(status = 200, body = HashMap<String, ContractInformationBuildInformation>)
|
||||
(status = 200, body = HashMap<String, ContractInformation<ContractBuildInformation>>)
|
||||
)
|
||||
)]
|
||||
async fn nym_contracts_detailed(
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
use nym_config::defaults::NymNetworkDetails;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
|
||||
pub struct NetworkDetails {
|
||||
pub(crate) connected_nyxd: String,
|
||||
pub(crate) network: NymNetworkDetails,
|
||||
@@ -21,7 +20,7 @@ impl NetworkDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, utoipa::ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct ContractInformation<T> {
|
||||
pub(crate) address: Option<String>,
|
||||
|
||||
@@ -183,6 +183,8 @@ impl PacketSender {
|
||||
gateway_packet_router,
|
||||
Some(fresh_gateway_client_data.bandwidth_controller.clone()),
|
||||
nym_statistics_common::clients::ClientStatsSender::new(None),
|
||||
#[cfg(unix)]
|
||||
None,
|
||||
task_client,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright 2021-2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// we want to mark the routes as deprecated in swagger, but still expose them
|
||||
#![allow(deprecated)]
|
||||
use crate::node_status_api::handlers::MixIdParam;
|
||||
use crate::node_status_api::helpers::{
|
||||
_get_active_set_legacy_mixnodes_detailed, _get_legacy_mixnodes_detailed,
|
||||
@@ -22,6 +20,8 @@ use nym_mixnet_contract_common::NodeId;
|
||||
use nym_types::monitoring::MonitorMessage;
|
||||
use tracing::error;
|
||||
|
||||
// we want to mark the routes as deprecated in swagger, but still expose them
|
||||
#[allow(deprecated)]
|
||||
pub(super) fn mandatory_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route(
|
||||
@@ -63,9 +63,9 @@ pub(super) fn mandatory_routes() -> Router<AppState> {
|
||||
path = "/v1/status/submit-gateway-monitoring-results",
|
||||
responses(
|
||||
(status = 200),
|
||||
(status = 400, body = String, description = "TBD"),
|
||||
(status = 403, body = String, description = "TBD"),
|
||||
(status = 500, body = String, description = "TBD"),
|
||||
(status = 400, body = ErrorResponse, description = "TBD"),
|
||||
(status = 403, body = ErrorResponse, description = "TBD"),
|
||||
(status = 500, body = ErrorResponse, description = "TBD"),
|
||||
),
|
||||
)]
|
||||
pub(crate) async fn submit_gateway_monitoring_results(
|
||||
@@ -107,9 +107,9 @@ pub(crate) async fn submit_gateway_monitoring_results(
|
||||
path = "/v1/status/submit-node-monitoring-results",
|
||||
responses(
|
||||
(status = 200),
|
||||
(status = 400, body = String, description = "TBD"),
|
||||
(status = 403, body = String, description = "TBD"),
|
||||
(status = 500, body = String, description = "TBD"),
|
||||
(status = 400, body = ErrorResponse, description = "TBD"),
|
||||
(status = 403, body = ErrorResponse, description = "TBD"),
|
||||
(status = 500, body = ErrorResponse, description = "TBD"),
|
||||
),
|
||||
)]
|
||||
pub(crate) async fn submit_node_monitoring_results(
|
||||
@@ -198,7 +198,7 @@ async fn get_mixnode_stake_saturation(
|
||||
),
|
||||
path = "/v1/status/mixnode/{mix_id}/inclusion-probability",
|
||||
responses(
|
||||
(status = 200, body = nym_api_requests::models::InclusionProbabilityResponse)
|
||||
(status = 200, body = InclusionProbabilityResponse)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
@@ -217,7 +217,7 @@ async fn get_mixnode_inclusion_probability(
|
||||
get,
|
||||
path = "/v1/status/mixnodes/inclusion-probability",
|
||||
responses(
|
||||
(status = 200, body = nym_api_requests::models::AllInclusionProbabilitiesResponse)
|
||||
(status = 200, body = AllInclusionProbabilitiesResponse)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -22,7 +22,6 @@ use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
use time::{Date, OffsetDateTime};
|
||||
use tracing::error;
|
||||
use utoipa::{ToResponse, ToSchema};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("Received uptime value was within 0-100 range (got {received})")]
|
||||
@@ -129,17 +128,14 @@ impl From<Uptime> for Performance {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema, ToSchema)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
|
||||
pub struct MixnodeStatusReport {
|
||||
#[schema(value_type = u32)]
|
||||
pub(crate) mix_id: NodeId,
|
||||
#[schema(value_type = String)]
|
||||
pub(crate) identity: IdentityKey,
|
||||
#[schema(value_type = u8)]
|
||||
|
||||
pub(crate) most_recent: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
|
||||
pub(crate) last_hour: Uptime,
|
||||
#[schema(value_type = u8)]
|
||||
pub(crate) last_day: Uptime,
|
||||
}
|
||||
|
||||
@@ -319,12 +315,8 @@ impl From<HistoricalUptime> for OldHistoricalUptimeResponse {
|
||||
|
||||
// TODO rocket remove smurf name after eliminating `rocket`
|
||||
pub(crate) type AxumResult<T> = Result<T, AxumErrorResponse>;
|
||||
|
||||
#[derive(ToSchema, ToResponse)]
|
||||
#[schema(title = "ErrorResponse")]
|
||||
pub(crate) struct AxumErrorResponse {
|
||||
message: RequestError,
|
||||
#[schema(value_type = u16)]
|
||||
status: StatusCode,
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ pub(crate) fn legacy_nym_node_routes() -> Router<AppState> {
|
||||
get,
|
||||
path = "/v1/gateways/described",
|
||||
responses(
|
||||
(status = 200, body = Vec<LegacyDescribedGateway>)
|
||||
(status = 200, body = Vec<DescribedGateway>)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
@@ -81,7 +81,7 @@ async fn get_gateways_described(
|
||||
get,
|
||||
path = "/v1/mixnodes/described",
|
||||
responses(
|
||||
(status = 200, body = Vec<LegacyDescribedMixNode>)
|
||||
(status = 200, body = Vec<DescribedMixNode>)
|
||||
)
|
||||
)]
|
||||
#[deprecated]
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_api_requests::nym_nodes::{CachedNodesResponse, FullFatNode};
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/full-fat",
|
||||
responses(
|
||||
// (status = 200, body = CachedNodesResponse<FullFatNode>)
|
||||
|
||||
@@ -88,7 +88,6 @@ struct NodesParamsWithRole {
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::IntoParams)]
|
||||
#[into_params(parameter_in = Query)]
|
||||
struct NodesParams {
|
||||
#[allow(dead_code)]
|
||||
semver_compatibility: Option<String>,
|
||||
|
||||
@@ -12,7 +12,7 @@ use nym_api_requests::nym_nodes::{CachedNodesResponse, SemiSkimmedNode};
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/semi-skimmed",
|
||||
responses(
|
||||
// (status = 200, body = CachedNodesResponse<SemiSkimmedNode>)
|
||||
|
||||
@@ -10,19 +10,15 @@ use crate::support::caching::Cache;
|
||||
use crate::support::http::state::AppState;
|
||||
use axum::extract::{Query, State};
|
||||
use axum::Json;
|
||||
use nym_api_requests::models::{
|
||||
NodeAnnotation, NymNodeDescription, OffsetDateTimeJsonSchemaWrapper,
|
||||
};
|
||||
use nym_api_requests::models::{NodeAnnotation, NymNodeDescription};
|
||||
use nym_api_requests::nym_nodes::{
|
||||
CachedNodesResponse, NodeRole, NodeRoleQueryParam, PaginatedCachedNodesResponse, SkimmedNode,
|
||||
};
|
||||
use nym_api_requests::pagination::PaginatedResponse;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use tokio::sync::RwLockReadGuard;
|
||||
use tracing::trace;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub type PaginatedSkimmedNodes = AxumResult<Json<PaginatedCachedNodesResponse<SkimmedNode>>>;
|
||||
|
||||
@@ -274,25 +270,16 @@ async fn nodes_basic(
|
||||
)))
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
#[derive(ToSchema)]
|
||||
#[schema(title = "PaginatedCachedNodesResponse")]
|
||||
pub struct PaginatedCachedNodesResponseSchema {
|
||||
pub refreshed_at: OffsetDateTimeJsonSchemaWrapper,
|
||||
#[schema(value_type = SkimmedNode)]
|
||||
pub nodes: PaginatedResponse<SkimmedNode>,
|
||||
}
|
||||
|
||||
/// Return all Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||
/// that are currently bonded.
|
||||
#[utoipa::path(
|
||||
tag = "Unstable Nym Nodes",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "",
|
||||
path = "/",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn nodes_basic_all(
|
||||
@@ -325,7 +312,7 @@ pub(super) async fn nodes_basic_all(
|
||||
path = "/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn nodes_basic_active(
|
||||
@@ -377,7 +364,7 @@ async fn mixnodes_basic(
|
||||
path = "/mixnodes/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn mixnodes_basic_all(
|
||||
@@ -396,7 +383,7 @@ pub(super) async fn mixnodes_basic_all(
|
||||
path = "/mixnodes/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn mixnodes_basic_active(
|
||||
@@ -434,7 +421,7 @@ async fn entry_gateways_basic(
|
||||
path = "/entry-gateways/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn entry_gateways_basic_active(
|
||||
@@ -453,7 +440,7 @@ pub(super) async fn entry_gateways_basic_active(
|
||||
path = "/entry-gateways/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn entry_gateways_basic_all(
|
||||
@@ -491,7 +478,7 @@ async fn exit_gateways_basic(
|
||||
path = "/exit-gateways/active",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn exit_gateways_basic_active(
|
||||
@@ -510,7 +497,7 @@ pub(super) async fn exit_gateways_basic_active(
|
||||
path = "/exit-gateways/all",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
(status = 200, body = PaginatedCachedNodesResponse<SkimmedNode>)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn exit_gateways_basic_all(
|
||||
|
||||
@@ -14,8 +14,6 @@ pub struct PaginationRequest {
|
||||
}
|
||||
|
||||
#[derive(Deserialize, IntoParams, ToSchema)]
|
||||
#[schema(title = "NodeId")]
|
||||
#[schema(as = NodeId)]
|
||||
#[into_params(parameter_in = Path)]
|
||||
pub(crate) struct NodeIdParam {
|
||||
#[schema(value_type = u32)]
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::network::handlers::ContractVersionSchemaResponse;
|
||||
use nym_api_requests::models;
|
||||
use utoipa::OpenApi;
|
||||
use utoipauto::utoipauto;
|
||||
|
||||
@@ -11,15 +13,7 @@ use utoipauto::utoipauto;
|
||||
// for automatic model discovery based on ToSchema / IntoParams implementation.
|
||||
// Then you can remove `components(schemas)` manual imports below
|
||||
|
||||
// dependencies which have derive(ToSchema) behind a feature flag with cfg_attr
|
||||
// cannot be autodiscovered because proc macros run before feature flags.
|
||||
// Tracking issue: https://github.com/ProbablyClem/utoipauto/issues/13
|
||||
|
||||
#[utoipauto(paths = "./nym-api/src,
|
||||
./nym-api/nym-api-requests/src from nym-api-requests,
|
||||
./common/config/src from nym-config,
|
||||
./common/ticketbooks-merkle/src from nym-ticketbooks-merkle,
|
||||
./common/nym_offline_compact_ecash/src from nym_compact_ecash")]
|
||||
#[utoipauto(paths = "./nym-api/src")]
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(title = "Nym API"),
|
||||
@@ -30,19 +24,79 @@ use utoipauto::utoipauto;
|
||||
),
|
||||
tags(),
|
||||
components(schemas(
|
||||
models::CirculatingSupplyResponse,
|
||||
models::CoinSchema,
|
||||
nym_mixnet_contract_common::Interval,
|
||||
nym_mixnet_contract_common::IntervalRewardParams,
|
||||
nym_mixnet_contract_common::RewardingParams,
|
||||
nym_mixnet_contract_common::reward_params::RewardedSetParams,
|
||||
nym_api_requests::models::NodeRefreshBody,
|
||||
nym_api_requests::models::GatewayStatusReportResponse,
|
||||
nym_api_requests::models::GatewayUptimeHistoryResponse,
|
||||
nym_api_requests::models::GatewayCoreStatusResponse,
|
||||
nym_api_requests::models::GatewayUptimeResponse,
|
||||
nym_api_requests::models::RewardEstimationResponse,
|
||||
nym_api_requests::models::UptimeResponse,
|
||||
nym_api_requests::models::ComputeRewardEstParam,
|
||||
nym_api_requests::models::MixNodeBondAnnotated,
|
||||
nym_api_requests::models::GatewayBondAnnotated,
|
||||
nym_api_requests::models::MixnodeTestResultResponse,
|
||||
nym_api_requests::models::StakeSaturationResponse,
|
||||
nym_api_requests::models::InclusionProbabilityResponse,
|
||||
nym_api_requests::models::AllInclusionProbabilitiesResponse,
|
||||
nym_api_requests::models::InclusionProbability,
|
||||
nym_api_requests::models::SelectionChance,
|
||||
crate::network::models::NetworkDetails,
|
||||
nym_config::defaults::NymNetworkDetails,
|
||||
nym_config::defaults::ChainDetails,
|
||||
nym_config::defaults::DenomDetailsOwned,
|
||||
nym_config::defaults::ValidatorDetails,
|
||||
nym_config::defaults::NymContracts,
|
||||
ContractVersionSchemaResponse,
|
||||
crate::network::models::ContractInformation<ContractVersionSchemaResponse>,
|
||||
nym_api_requests::models::ApiHealthResponse,
|
||||
nym_api_requests::models::ApiStatus,
|
||||
nym_bin_common::build_information::BinaryBuildInformationOwned,
|
||||
nym_api_requests::models::SignerInformationResponse,
|
||||
nym_api_requests::models::LegacyDescribedGateway,
|
||||
nym_mixnet_contract_common::Gateway,
|
||||
nym_mixnet_contract_common::GatewayBond,
|
||||
nym_api_requests::models::NymNodeDescription,
|
||||
nym_api_requests::models::HostInformation,
|
||||
nym_api_requests::models::HostKeys,
|
||||
nym_node_requests::api::v1::node::models::AuxiliaryDetails,
|
||||
nym_contracts_common::ContractBuildInformation
|
||||
nym_api_requests::models::NetworkRequesterDetails,
|
||||
nym_api_requests::models::IpPacketRouterDetails,
|
||||
nym_api_requests::models::AuthenticatorDetails,
|
||||
nym_api_requests::models::WebSockets,
|
||||
nym_api_requests::nym_nodes::NodeRole,
|
||||
nym_api_requests::models::LegacyDescribedMixNode,
|
||||
nym_api_requests::ecash::VerificationKeyResponse,
|
||||
nym_api_requests::ecash::models::AggregatedExpirationDateSignatureResponse,
|
||||
nym_api_requests::ecash::models::AggregatedCoinIndicesSignatureResponse,
|
||||
nym_api_requests::ecash::models::MasterVerificationKeyResponse,
|
||||
nym_api_requests::ecash::models::BlindedSignatureResponse,
|
||||
nym_api_requests::ecash::models::BlindSignRequestBody,
|
||||
nym_api_requests::ecash::models::PartialExpirationDateSignatureResponse,
|
||||
nym_api_requests::ecash::models::PartialCoinIndicesSignatureResponse,
|
||||
nym_api_requests::ecash::models::EcashTicketVerificationResponse,
|
||||
nym_api_requests::ecash::models::EcashTicketVerificationRejection,
|
||||
nym_api_requests::ecash::models::EcashBatchTicketRedemptionResponse,
|
||||
nym_api_requests::ecash::models::VerifyEcashTicketBody,
|
||||
nym_api_requests::ecash::models::VerifyEcashCredentialBody,
|
||||
nym_api_requests::ecash::models::CommitedDeposit,
|
||||
nym_api_requests::ecash::models::IssuedTicketbooksForResponseBody,
|
||||
nym_api_requests::ecash::models::IssuedTicketbooksForResponse,
|
||||
nym_api_requests::ecash::models::IssuedTicketbooksChallengeRequest,
|
||||
nym_api_requests::ecash::models::IssuedTicketbooksChallengeResponseBody,
|
||||
nym_api_requests::ecash::models::IssuedTicketbooksChallengeResponse,
|
||||
nym_api_requests::nym_nodes::SkimmedNode,
|
||||
nym_api_requests::nym_nodes::SemiSkimmedNode,
|
||||
nym_api_requests::nym_nodes::FullFatNode,
|
||||
nym_api_requests::nym_nodes::BasicEntryInformation,
|
||||
nym_api_requests::nym_nodes::NodeRoleQueryParam,
|
||||
nym_api_requests::models::AnnotationResponse,
|
||||
nym_api_requests::models::NodePerformanceResponse,
|
||||
nym_api_requests::models::NodeDatePerformanceResponse,
|
||||
nym_api_requests::models::PerformanceHistoryResponse,
|
||||
nym_api_requests::models::UptimeHistoryResponse,
|
||||
))
|
||||
)]
|
||||
pub(crate) struct ApiDoc;
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::support::storage::models::{
|
||||
use dashmap::DashMap;
|
||||
use nym_mixnet_contract_common::NodeId;
|
||||
use nym_types::monitoring::NodeResult;
|
||||
use sqlx::sqlite::{SqliteAutoVacuum, SqliteSynchronous};
|
||||
use sqlx::ConnectOptions;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
@@ -67,6 +68,9 @@ impl NymApiStorage {
|
||||
// TODO: we can inject here more stuff based on our nym-api global config
|
||||
// struct. Maybe different pool size or timeout intervals?
|
||||
let connect_opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.log_statements(LevelFilter::Trace)
|
||||
|
||||
@@ -10,7 +10,9 @@ use uuid::Uuid;
|
||||
pub mod ticketbook;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct ErrorResponse {
|
||||
#[cfg_attr(feature = "openapi",schema(value_type = Option<String>, example = "c48f9ce3-a1e9-4886-8000-13f290f34501"))]
|
||||
pub uuid: Option<Uuid>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ pub struct TicketbookRequest {
|
||||
// needs to be explicit in case user creates request at 23:59:59.999, but it reaches vpn-api at 00:00:00.001
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "crate::helpers::date_serde")]
|
||||
#[cfg_attr(feature = "openapi", schema(value_type = String))]
|
||||
pub expiration_date: Date,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
@@ -247,12 +246,10 @@ pub struct WebhookTicketbookWalletShares {
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
#[cfg_attr(feature = "openapi", schema(value_type = String))]
|
||||
pub created: OffsetDateTime,
|
||||
|
||||
#[schemars(with = "String")]
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
#[cfg_attr(feature = "openapi", schema(value_type = String))]
|
||||
pub updated: OffsetDateTime,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
// Copyright 2024 Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use nym_bin_common::bin_info;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::{debug, info, warn};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::{
|
||||
cli::Cli,
|
||||
deposit_maker::DepositMaker,
|
||||
error::VpnApiError,
|
||||
http::{
|
||||
state::{ApiState, ChainClient},
|
||||
HttpServer,
|
||||
},
|
||||
storage::VpnApiStorage,
|
||||
tasks::StoragePruner,
|
||||
};
|
||||
|
||||
pub struct LockTimer {
|
||||
created: OffsetDateTime,
|
||||
@@ -40,3 +54,88 @@ impl Default for LockTimer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wait_for_signal() {
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
|
||||
// if we fail to setup the signals, we should just blow up
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to setup SIGTERM channel");
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut sigquit = signal(SignalKind::quit()).expect("Failed to setup SIGQUIT channel");
|
||||
|
||||
tokio::select! {
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
info!("Received SIGINT");
|
||||
},
|
||||
_ = sigterm.recv() => {
|
||||
info!("Received SIGTERM");
|
||||
}
|
||||
_ = sigquit.recv() => {
|
||||
info!("Received SIGQUIT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_sha_short() -> &'static str {
|
||||
let bin_info = bin_info!();
|
||||
if bin_info.commit_sha.len() < 7 {
|
||||
panic!("unavailable build commit sha")
|
||||
}
|
||||
|
||||
if bin_info.commit_sha == "VERGEN_IDEMPOTENT_OUTPUT" {
|
||||
error!("the binary hasn't been built correctly. it doesn't have a commit sha information");
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
&bin_info.commit_sha[..7]
|
||||
}
|
||||
|
||||
pub(crate) async fn run_api(cli: Cli) -> Result<(), VpnApiError> {
|
||||
// create the tasks
|
||||
let bind_address = cli.bind_address();
|
||||
|
||||
let storage = VpnApiStorage::init(cli.persistent_storage_path()).await?;
|
||||
let mnemonic = cli.mnemonic;
|
||||
let auth_token = cli.http_auth_token;
|
||||
let webhook_cfg = cli.webhook;
|
||||
let chain_client = ChainClient::new(mnemonic)?;
|
||||
let cancellation_token = CancellationToken::new();
|
||||
|
||||
let deposit_maker = DepositMaker::new(
|
||||
build_sha_short(),
|
||||
chain_client.clone(),
|
||||
cli.max_concurrent_deposits,
|
||||
cancellation_token.clone(),
|
||||
);
|
||||
|
||||
let deposit_request_sender = deposit_maker.deposit_request_sender();
|
||||
let api_state = ApiState::new(
|
||||
storage.clone(),
|
||||
webhook_cfg,
|
||||
chain_client,
|
||||
deposit_request_sender,
|
||||
cancellation_token.clone(),
|
||||
)
|
||||
.await?;
|
||||
let http_server = HttpServer::new(
|
||||
bind_address,
|
||||
api_state.clone(),
|
||||
auth_token,
|
||||
cancellation_token.clone(),
|
||||
);
|
||||
let storage_pruner = StoragePruner::new(cancellation_token, storage);
|
||||
|
||||
// spawn all the tasks
|
||||
api_state.try_spawn(http_server.run_forever());
|
||||
api_state.try_spawn(storage_pruner.run_forever());
|
||||
api_state.try_spawn(deposit_maker.run_forever());
|
||||
|
||||
// wait for cancel signal (SIGINT, SIGTERM or SIGQUIT)
|
||||
wait_for_signal().await;
|
||||
|
||||
// cancel all the tasks and wait for all task to terminate
|
||||
api_state.cancel_and_wait().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::http::router::api;
|
||||
use crate::http::types::RequestError;
|
||||
use axum::Router;
|
||||
use nym_credential_proxy_requests::api as api_requests;
|
||||
use nym_credential_proxy_requests::routes::api::{v1, v1_absolute};
|
||||
@@ -68,6 +69,7 @@ pub(crate) struct ApiDoc;
|
||||
schemas(
|
||||
api::Output,
|
||||
api::OutputParams,
|
||||
api_requests::v1::ErrorResponse,
|
||||
api_requests::v1::ticketbook::models::DepositResponse,
|
||||
api_requests::v1::ticketbook::models::PartialVerificationKeysResponse,
|
||||
api_requests::v1::ticketbook::models::CurrentEpochResponse,
|
||||
@@ -88,6 +90,7 @@ pub(crate) struct ApiDoc;
|
||||
api_requests::v1::ticketbook::models::SharesQueryParams,
|
||||
api_requests::v1::ticketbook::models::PlaceholderJsonSchemaImpl,
|
||||
),
|
||||
responses(RequestError),
|
||||
),
|
||||
modifiers(&SecurityAddon),
|
||||
)]
|
||||
|
||||
+23
-23
@@ -48,14 +48,14 @@ pub type FormattedTicketbookWalletSharesAsyncResponse =
|
||||
),
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(TicketbookWalletSharesResponse = "application/json"),
|
||||
(TicketbookWalletSharesResponse = "application/yaml"),
|
||||
("application/json" = TicketbookWalletSharesResponse),
|
||||
("application/yaml" = TicketbookWalletSharesResponse),
|
||||
)),
|
||||
(status = 400, description = "the provided request hasn't been created against correct attributes"),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 422, description = "provided request was malformed"),
|
||||
(status = 500, body = String, description = "failed to obtain a ticketbook"),
|
||||
(status = 503, body = String, description = "ticketbooks can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain a ticketbook"),
|
||||
(status = 503, body = ErrorResponse, description = "ticketbooks can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
),
|
||||
params(TicketbookObtainQueryParams),
|
||||
security(
|
||||
@@ -138,15 +138,15 @@ pub(crate) async fn obtain_ticketbook_shares(
|
||||
),
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(TicketbookWalletSharesAsyncResponse = "application/json"),
|
||||
(TicketbookWalletSharesAsyncResponse = "application/yaml"),
|
||||
("application/json" = TicketbookWalletSharesAsyncResponse),
|
||||
("application/yaml" = TicketbookWalletSharesAsyncResponse),
|
||||
)),
|
||||
(status = 400, description = "the provided request hasn't been created against correct attributes"),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 409, description = "shares were already requested"),
|
||||
(status = 422, description = "provided request was malformed"),
|
||||
(status = 500, body = String, description = "failed to obtain a ticketbook"),
|
||||
(status = 503, body = String, description = "ticketbooks can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain a ticketbook"),
|
||||
(status = 503, body = ErrorResponse, description = "ticketbooks can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
),
|
||||
params(TicketbookObtainQueryParams),
|
||||
security(
|
||||
@@ -235,11 +235,11 @@ pub(crate) async fn obtain_ticketbook_shares_async(
|
||||
tag = "Ticketbook",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(DepositResponse = "application/json"),
|
||||
(DepositResponse = "application/yaml"),
|
||||
("application/json" = DepositResponse),
|
||||
("application/yaml" = DepositResponse),
|
||||
)),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to obtain current deposit information"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain current deposit information"),
|
||||
),
|
||||
params(OutputParams),
|
||||
security(
|
||||
@@ -270,12 +270,12 @@ pub(crate) async fn current_deposit(
|
||||
tag = "Ticketbook",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(PartialVerificationKeysResponse = "application/json"),
|
||||
(PartialVerificationKeysResponse = "application/yaml"),
|
||||
("application/json" = PartialVerificationKeysResponse),
|
||||
("application/yaml" = PartialVerificationKeysResponse),
|
||||
)),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = String, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = ErrorResponse, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
),
|
||||
params(OutputParams),
|
||||
security(
|
||||
@@ -320,12 +320,12 @@ pub(crate) async fn partial_verification_keys(
|
||||
tag = "Ticketbook",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(MasterVerificationKeyResponse = "application/json"),
|
||||
(MasterVerificationKeyResponse = "application/yaml"),
|
||||
("application/json" = MasterVerificationKeyResponse),
|
||||
("application/yaml" = MasterVerificationKeyResponse),
|
||||
)),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = String, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = ErrorResponse, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
),
|
||||
params(OutputParams),
|
||||
security(
|
||||
@@ -365,12 +365,12 @@ pub(crate) async fn master_verification_key(
|
||||
tag = "Ticketbook",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(CurrentEpochResponse = "application/json"),
|
||||
(CurrentEpochResponse = "application/yaml"),
|
||||
("application/json" = CurrentEpochResponse),
|
||||
("application/yaml" = CurrentEpochResponse),
|
||||
)),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = String, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to obtain current epoch information"),
|
||||
(status = 503, body = ErrorResponse, description = "credentials can't be issued at this moment: the epoch transition is probably taking place"),
|
||||
),
|
||||
params(OutputParams),
|
||||
security(
|
||||
|
||||
+6
-6
@@ -80,12 +80,12 @@ async fn shares_to_response(
|
||||
tag = "Ticketbook Wallet Shares",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(TicketbookWalletSharesResponse = "application/json"),
|
||||
(TicketbookWalletSharesResponse = "application/yaml"),
|
||||
("application/json" = TicketbookWalletSharesResponse),
|
||||
("application/yaml" = TicketbookWalletSharesResponse),
|
||||
)),
|
||||
(status = 404, description = "share_id not found"),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to query for bandwidth blinded shares"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to query for bandwidth blinded shares"),
|
||||
),
|
||||
params(OutputParams),
|
||||
security(
|
||||
@@ -155,12 +155,12 @@ pub(crate) async fn query_for_shares_by_id(
|
||||
tag = "Ticketbook Wallet Shares",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(TicketbookWalletSharesResponse = "application/json"),
|
||||
(TicketbookWalletSharesResponse = "application/yaml"),
|
||||
("application/json" = TicketbookWalletSharesResponse),
|
||||
("application/yaml" = TicketbookWalletSharesResponse),
|
||||
)),
|
||||
(status = 404, description = "share_id not found"),
|
||||
(status = 401, description = "authentication token is missing or is invalid"),
|
||||
(status = 500, body = String, description = "failed to query for bandwidth blinded shares"),
|
||||
(status = 500, body = ErrorResponse, description = "failed to query for bandwidth blinded shares"),
|
||||
),
|
||||
params(SharesQueryParams),
|
||||
security(
|
||||
|
||||
@@ -6,11 +6,14 @@ use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use nym_credential_proxy_requests::api::v1::ErrorResponse;
|
||||
use utoipa::ToResponse;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, ToResponse)]
|
||||
#[response(description = "Error response with additional message")]
|
||||
pub struct RequestError {
|
||||
pub inner: ErrorResponse,
|
||||
|
||||
pub status: StatusCode,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,117 +6,30 @@
|
||||
#![warn(clippy::todo)]
|
||||
#![warn(clippy::dbg_macro)]
|
||||
|
||||
use crate::cli::Cli;
|
||||
use crate::deposit_maker::DepositMaker;
|
||||
use crate::error::VpnApiError;
|
||||
use crate::http::state::{ApiState, ChainClient};
|
||||
use crate::http::HttpServer;
|
||||
use crate::storage::VpnApiStorage;
|
||||
use crate::tasks::StoragePruner;
|
||||
use clap::Parser;
|
||||
use nym_bin_common::logging::setup_tracing_logger;
|
||||
use nym_bin_common::{bin_info, bin_info_owned};
|
||||
use nym_network_defaults::setup_env;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::{error, info, trace};
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(unix)] {
|
||||
use crate::cli::Cli;
|
||||
use clap::Parser;
|
||||
use nym_bin_common::bin_info_owned;
|
||||
use nym_bin_common::logging::setup_tracing_logger;
|
||||
use nym_network_defaults::setup_env;
|
||||
use tracing::{info, trace};
|
||||
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod credentials;
|
||||
mod deposit_maker;
|
||||
pub mod error;
|
||||
pub mod helpers;
|
||||
pub mod http;
|
||||
pub mod nym_api_helpers;
|
||||
pub mod storage;
|
||||
pub mod tasks;
|
||||
mod webhook;
|
||||
|
||||
pub async fn wait_for_signal() {
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
|
||||
// if we fail to setup the signals, we should just blow up
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to setup SIGTERM channel");
|
||||
#[allow(clippy::expect_used)]
|
||||
let mut sigquit = signal(SignalKind::quit()).expect("Failed to setup SIGQUIT channel");
|
||||
|
||||
tokio::select! {
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
info!("Received SIGINT");
|
||||
},
|
||||
_ = sigterm.recv() => {
|
||||
info!("Received SIGTERM");
|
||||
}
|
||||
_ = sigquit.recv() => {
|
||||
info!("Received SIGQUIT");
|
||||
}
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod credentials;
|
||||
mod deposit_maker;
|
||||
pub mod error;
|
||||
pub mod helpers;
|
||||
pub mod http;
|
||||
pub mod nym_api_helpers;
|
||||
pub mod storage;
|
||||
pub mod tasks;
|
||||
mod webhook;
|
||||
}
|
||||
}
|
||||
|
||||
fn build_sha_short() -> &'static str {
|
||||
let bin_info = bin_info!();
|
||||
if bin_info.commit_sha.len() < 7 {
|
||||
panic!("unavailable build commit sha")
|
||||
}
|
||||
|
||||
if bin_info.commit_sha == "VERGEN_IDEMPOTENT_OUTPUT" {
|
||||
error!("the binary hasn't been built correctly. it doesn't have a commit sha information");
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
&bin_info.commit_sha[..7]
|
||||
}
|
||||
|
||||
async fn run_api(cli: Cli) -> Result<(), VpnApiError> {
|
||||
// create the tasks
|
||||
let bind_address = cli.bind_address();
|
||||
|
||||
let storage = VpnApiStorage::init(cli.persistent_storage_path()).await?;
|
||||
let mnemonic = cli.mnemonic;
|
||||
let auth_token = cli.http_auth_token;
|
||||
let webhook_cfg = cli.webhook;
|
||||
let chain_client = ChainClient::new(mnemonic)?;
|
||||
let cancellation_token = CancellationToken::new();
|
||||
|
||||
let deposit_maker = DepositMaker::new(
|
||||
build_sha_short(),
|
||||
chain_client.clone(),
|
||||
cli.max_concurrent_deposits,
|
||||
cancellation_token.clone(),
|
||||
);
|
||||
|
||||
let deposit_request_sender = deposit_maker.deposit_request_sender();
|
||||
let api_state = ApiState::new(
|
||||
storage.clone(),
|
||||
webhook_cfg,
|
||||
chain_client,
|
||||
deposit_request_sender,
|
||||
cancellation_token.clone(),
|
||||
)
|
||||
.await?;
|
||||
let http_server = HttpServer::new(
|
||||
bind_address,
|
||||
api_state.clone(),
|
||||
auth_token,
|
||||
cancellation_token.clone(),
|
||||
);
|
||||
let storage_pruner = StoragePruner::new(cancellation_token, storage);
|
||||
|
||||
// spawn all the tasks
|
||||
api_state.try_spawn(http_server.run_forever());
|
||||
api_state.try_spawn(storage_pruner.run_forever());
|
||||
api_state.try_spawn(deposit_maker.run_forever());
|
||||
|
||||
// wait for cancel signal (SIGINT, SIGTERM or SIGQUIT)
|
||||
wait_for_signal().await;
|
||||
|
||||
// cancel all the tasks and wait for all task to terminate
|
||||
api_state.cancel_and_wait().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// std::env::set_var(
|
||||
@@ -134,6 +47,13 @@ async fn main() -> anyhow::Result<()> {
|
||||
let bin_info = bin_info_owned!();
|
||||
info!("using the following version: {bin_info}");
|
||||
|
||||
run_api(cli).await?;
|
||||
helpers::run_api(cli).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
eprintln!("This tool is only supported on Unix systems");
|
||||
std::process::exit(1)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use nym_validator_client::ecash::BlindedSignatureResponse;
|
||||
use nym_validator_client::nym_api::EpochId;
|
||||
use nym_validator_client::nyxd::contract_traits::ecash_query_client::DepositId;
|
||||
use nym_validator_client::nyxd::Coin;
|
||||
use sqlx::sqlite::{SqliteAutoVacuum, SqliteSynchronous};
|
||||
use sqlx::ConnectOptions;
|
||||
use std::fmt::Debug;
|
||||
use std::path::Path;
|
||||
@@ -40,6 +41,9 @@ impl VpnApiStorage {
|
||||
debug!("Attempting to connect to database");
|
||||
|
||||
let opts = sqlx::sqlite::SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.synchronous(SqliteSynchronous::Normal)
|
||||
.auto_vacuum(SqliteAutoVacuum::Incremental)
|
||||
.filename(database_path)
|
||||
.create_if_missing(true)
|
||||
.log_statements(LevelFilter::Trace)
|
||||
|
||||
@@ -27,12 +27,14 @@ tokio = { workspace = true, features = ["macros", "time"] }
|
||||
tokio-util = { workspace = true }
|
||||
utoipa = { workspace = true, features = ["axum_extras"] }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
tokio-postgres = "0.7"
|
||||
|
||||
# internal
|
||||
nym-bin-common = { path = "../common/bin-common" }
|
||||
nym-client-core = { path = "../common/client-core" }
|
||||
nym-crypto = { path = "../common/crypto" }
|
||||
nym-network-defaults = { path = "../common/network-defaults" }
|
||||
nym-gateway-requests = { path = "../common/gateway-requests" }
|
||||
nym-sdk = { path = "../sdk/rust/nym-sdk" }
|
||||
nym-sphinx = { path = "../common/nymsphinx" }
|
||||
nym-topology = { path = "../common/topology" }
|
||||
|
||||
@@ -9,13 +9,14 @@ network=${NYM_NETWORK:-mainnet}
|
||||
timeout=${LOCUST_TIMEOUT:-600}
|
||||
users=${LOCUST_USERS:-10}
|
||||
processes=${LOCUST_PROCESSES:-4}
|
||||
_database_url=${DATABASE_URL}
|
||||
|
||||
RUST_LOG=info nym-network-monitor --env envs/"${network}".env --private-key "${_private_key}" &
|
||||
RUST_LOG=info nym-network-monitor --env envs/"${network}".env --private-key "${_private_key}" --database-url "${_database_url}" &
|
||||
nnm_pid=$!
|
||||
|
||||
sleep 10
|
||||
|
||||
python -m locust -H http://${NYM_NETWORK_MONITOR_HOST}:${NYM_NETWORK_MONITOR_PORT} --processes "${processes}" --autostart --autoquit 60 -u "${users}" -t "${timeout}"s &
|
||||
python -m locust -H http://"${NYM_NETWORK_MONITOR_HOST}":"${NYM_NETWORK_MONITOR_PORT}" --processes "${processes}" --autostart --autoquit 60 -u "${users}" -t "${timeout}"s &
|
||||
locust_pid=$!
|
||||
|
||||
wait $locust_pid
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use futures::{pin_mut, stream::FuturesUnordered, StreamExt};
|
||||
use log::{debug, info};
|
||||
use nym_sphinx::chunking::{monitoring, SentFragment};
|
||||
use nym_topology::{gateway, mix, NymTopology};
|
||||
@@ -10,6 +13,7 @@ use nym_validator_client::nym_api::routes::{API_VERSION, STATUS, SUBMIT_GATEWAY,
|
||||
use rand::SeedableRng;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio_postgres::{binary_copy::BinaryCopyInWriter, types::Type, Client};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::{NYM_API_URL, PRIVATE_KEY, TOPOLOGY};
|
||||
@@ -23,20 +27,20 @@ struct HydratedRoute {
|
||||
struct GatewayStats(u32, u32);
|
||||
|
||||
impl GatewayStats {
|
||||
fn new(sent: u32, recv: u32) -> Self {
|
||||
GatewayStats(sent, recv)
|
||||
fn new(success: u32, failure: u32) -> Self {
|
||||
GatewayStats(success, failure)
|
||||
}
|
||||
|
||||
fn success(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn failed(&self) -> u32 {
|
||||
fn failure(&self) -> u32 {
|
||||
self.1
|
||||
}
|
||||
|
||||
fn reliability(&self) -> f64 {
|
||||
self.success() as f64 / (self.success() + self.failed()) as f64
|
||||
self.success() as f64 / (self.success() + self.failure()) as f64
|
||||
}
|
||||
|
||||
fn incr_success(&mut self) {
|
||||
@@ -321,48 +325,125 @@ pub async fn monitor_mixnode_results() -> anyhow::Result<Vec<NodeResult>> {
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn submit_metrics() -> anyhow::Result<()> {
|
||||
let node_stats = monitor_mixnode_results().await?;
|
||||
let gateway_stats = monitor_gateway_results().await?;
|
||||
async fn submit_node_stats_to_db(client: Arc<Client>) -> anyhow::Result<()> {
|
||||
let client = Arc::clone(&client);
|
||||
let node_stats = all_node_stats().await?;
|
||||
|
||||
info!("Submitting metrics to {}", *NYM_API_URL);
|
||||
let client = reqwest::Client::new();
|
||||
let sink = client
|
||||
.copy_in("COPY node_stats (node_id, identity, reliability, complete_routes, incomplete_routes) FROM STDIN BINARY")
|
||||
.await?;
|
||||
|
||||
let node_submit_url = format!("{}/{API_VERSION}/{STATUS}/{SUBMIT_NODE}", &*NYM_API_URL);
|
||||
let gateway_submit_url = format!("{}/{API_VERSION}/{STATUS}/{SUBMIT_GATEWAY}", &*NYM_API_URL);
|
||||
let writer = BinaryCopyInWriter::new(
|
||||
sink,
|
||||
&[Type::INT4, Type::TEXT, Type::FLOAT8, Type::INT8, Type::INT8],
|
||||
);
|
||||
pin_mut!(writer);
|
||||
|
||||
info!("Submitting {} mixnode measurements", node_stats.len());
|
||||
for stat in node_stats {
|
||||
writer
|
||||
.as_mut()
|
||||
.write(&[
|
||||
&(stat.mix_id as i32),
|
||||
&stat.identity,
|
||||
&stat.reliability,
|
||||
&(stat.complete_routes as i64),
|
||||
&(stat.incomplete_routes as i64),
|
||||
])
|
||||
.await?;
|
||||
}
|
||||
|
||||
node_stats
|
||||
.chunks(10)
|
||||
.map(|chunk| {
|
||||
let monitor_message =
|
||||
MonitorMessage::new(chunk.to_vec(), PRIVATE_KEY.get().expect("We've set this!"));
|
||||
client.post(&node_submit_url).json(&monitor_message).send()
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.collect::<Vec<Result<_, _>>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
writer.finish().await?;
|
||||
|
||||
info!("Submitting {} gateway measurements", gateway_stats.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
gateway_stats
|
||||
.chunks(10)
|
||||
.map(|chunk| {
|
||||
let monitor_message =
|
||||
MonitorMessage::new(chunk.to_vec(), PRIVATE_KEY.get().expect("We've set this!"));
|
||||
client
|
||||
.post(&gateway_submit_url)
|
||||
.json(&monitor_message)
|
||||
.send()
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.collect::<Vec<Result<_, _>>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
async fn submit_gateway_stats_to_db(client: Arc<Client>) -> anyhow::Result<()> {
|
||||
let client = Arc::clone(&client);
|
||||
let network_account = NetworkAccount::finalize()?;
|
||||
let gateway_stats = network_account.gateway_stats;
|
||||
|
||||
let sink = client
|
||||
.copy_in("COPY gateway_stats (identity, reliability, success, failure) FROM STDIN BINARY")
|
||||
.await?;
|
||||
|
||||
let writer = BinaryCopyInWriter::new(sink, &[Type::TEXT, Type::FLOAT8, Type::INT8, Type::INT8]);
|
||||
pin_mut!(writer);
|
||||
|
||||
for (key, stats) in gateway_stats {
|
||||
writer
|
||||
.as_mut()
|
||||
.write(&[
|
||||
&key,
|
||||
&stats.reliability(),
|
||||
&(stats.success() as i64),
|
||||
&(stats.failure() as i64),
|
||||
])
|
||||
.await?;
|
||||
}
|
||||
|
||||
writer.finish().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn submit_metrics_to_db(client: Arc<Client>) -> anyhow::Result<()> {
|
||||
let client = Arc::clone(&client);
|
||||
let client2 = Arc::clone(&client);
|
||||
submit_node_stats_to_db(client).await?;
|
||||
submit_gateway_stats_to_db(client2).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn submit_metrics(client: Option<Arc<Client>>) -> anyhow::Result<()> {
|
||||
if let Some(client) = client {
|
||||
submit_metrics_to_db(client).await?;
|
||||
}
|
||||
|
||||
if let Some(private_key) = PRIVATE_KEY.get() {
|
||||
let node_stats = monitor_mixnode_results().await?;
|
||||
let gateway_stats = monitor_gateway_results().await?;
|
||||
|
||||
info!("Submitting metrics to {}", *NYM_API_URL);
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let node_submit_url = format!("{}/{API_VERSION}/{STATUS}/{SUBMIT_NODE}", &*NYM_API_URL);
|
||||
let gateway_submit_url =
|
||||
format!("{}/{API_VERSION}/{STATUS}/{SUBMIT_GATEWAY}", &*NYM_API_URL);
|
||||
|
||||
info!("Submitting {} mixnode measurements", node_stats.len());
|
||||
|
||||
node_stats
|
||||
.chunks(10)
|
||||
.map(|chunk| {
|
||||
let monitor_message = MonitorMessage::new(chunk.to_vec(), private_key);
|
||||
client.post(&node_submit_url).json(&monitor_message).send()
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.collect::<Vec<Result<_, _>>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
info!("Submitting {} gateway measurements", gateway_stats.len());
|
||||
|
||||
gateway_stats
|
||||
.chunks(10)
|
||||
.map(|chunk| {
|
||||
let monitor_message = MonitorMessage::new(
|
||||
chunk.to_vec(),
|
||||
PRIVATE_KEY.get().expect("We've set this!"),
|
||||
);
|
||||
client
|
||||
.post(&gateway_submit_url)
|
||||
.json(&monitor_message)
|
||||
.send()
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.collect::<Vec<Result<_, _>>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
}
|
||||
|
||||
NetworkAccount::empty_buffers();
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ use crate::http::HttpServer;
|
||||
use accounting::submit_metrics;
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use log::{info, warn};
|
||||
use log::{error, info, warn};
|
||||
use nym_client_core::ForgetMe;
|
||||
use nym_crypto::asymmetric::ed25519::PrivateKey;
|
||||
use nym_network_defaults::setup_env;
|
||||
use nym_network_defaults::var_names::NYM_API;
|
||||
@@ -21,6 +22,7 @@ use std::{
|
||||
};
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio::{signal::ctrl_c, sync::RwLock};
|
||||
use tokio_postgres::NoTls;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
static NYM_API_URL: LazyLock<String> = LazyLock::new(|| {
|
||||
@@ -56,7 +58,11 @@ async fn make_clients(
|
||||
loop {
|
||||
if Arc::strong_count(&dropped_client) == 1 {
|
||||
if let Some(client) = Arc::into_inner(dropped_client) {
|
||||
client.into_inner().disconnect().await;
|
||||
// let forget_me = ClientRequest::ForgetMe {
|
||||
// also_from_stats: true,
|
||||
// };
|
||||
let client_handle = client.into_inner();
|
||||
client_handle.disconnect().await;
|
||||
} else {
|
||||
warn!("Failed to drop client, client had more then one strong ref")
|
||||
}
|
||||
@@ -89,6 +95,7 @@ async fn make_client(topology: NymTopology) -> Result<MixnetClient> {
|
||||
.network_details(net)
|
||||
.custom_topology_provider(topology_provider)
|
||||
.debug_config(mixnet_debug_config(0))
|
||||
.with_forget_me(ForgetMe::new_all())
|
||||
// .enable_credentials_mode()
|
||||
.build()?;
|
||||
|
||||
@@ -130,7 +137,10 @@ struct Args {
|
||||
generate_key_pair: bool,
|
||||
|
||||
#[arg(long)]
|
||||
private_key: String,
|
||||
private_key: Option<String>,
|
||||
|
||||
#[arg(long, env = "DATABASE_URL")]
|
||||
database_url: Option<String>,
|
||||
}
|
||||
|
||||
fn generate_key_pair() -> Result<()> {
|
||||
@@ -168,8 +178,10 @@ async fn main() -> Result<()> {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let pk = PrivateKey::from_base58_string(&args.private_key)?;
|
||||
PRIVATE_KEY.set(pk).ok();
|
||||
if let Some(private_key) = args.private_key {
|
||||
let pk = PrivateKey::from_base58_string(&private_key)?;
|
||||
PRIVATE_KEY.set(pk).ok();
|
||||
}
|
||||
|
||||
TOPOLOGY
|
||||
.set(if let Some(topology_file) = args.topology {
|
||||
@@ -197,16 +209,31 @@ async fn main() -> Result<()> {
|
||||
|
||||
info!("Waiting for message (ctrl-c to exit)");
|
||||
|
||||
let client = if let Some(database_url) = args.database_url {
|
||||
let (client, connection) = tokio_postgres::connect(&database_url, NoTls).await?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = connection.await {
|
||||
error!("Postgres connection error: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
Some(Arc::new(client))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
loop {
|
||||
let client = client.as_ref().map(Arc::clone);
|
||||
match tokio::time::timeout(Duration::from_secs(600), ctrl_c()).await {
|
||||
Ok(_) => {
|
||||
info!("Received kill signal, shutting down, submitting final batch of metrics");
|
||||
submit_metrics().await?;
|
||||
submit_metrics(client).await?;
|
||||
break;
|
||||
}
|
||||
Err(_) => {
|
||||
info!("Submitting metrics, cleaning metric buffers");
|
||||
submit_metrics().await?;
|
||||
submit_metrics(client).await?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set -eu
|
||||
export ENVIRONMENT=${ENVIRONMENT:-"sandbox"}
|
||||
|
||||
probe_git_ref="nym-vpn-core-v1.1.0-beta.2"
|
||||
probe_git_ref="nym-vpn-core-v1.1.0"
|
||||
|
||||
crate_root=$(dirname $(realpath "$0"))
|
||||
monorepo_root=$(realpath "${crate_root}/../..")
|
||||
@@ -54,7 +54,7 @@ function swarm() {
|
||||
echo "All agents completed"
|
||||
}
|
||||
|
||||
copy_gw_probe
|
||||
# copy_gw_probe
|
||||
build_agent
|
||||
|
||||
swarm $workers
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use sqlx::{Connection, SqliteConnection};
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::fs::Permissions;
|
||||
#[cfg(target_family = "unix")]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
|
||||
@@ -39,7 +41,10 @@ async fn write_db_path_to_file(out_dir: &str, db_filename: &str) -> anyhow::Resu
|
||||
file.write_all(format!("sqlite3 {}/{}", out_dir, db_filename).as_bytes())
|
||||
.await?;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
file.set_permissions(Permissions::from_mode(0o755))
|
||||
.await
|
||||
.map_err(From::from)
|
||||
.map_err(anyhow::Error::from)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user