Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d9a6db6c2f | |||
| 277305e68d | |||
| e7d88c3c28 | |||
| 0c97b51a4c | |||
| b326993da6 | |||
| 12ed915069 | |||
| 65166bfd61 | |||
| 987e890e99 | |||
| 692cd32ac2 | |||
| 0e544da06f | |||
| 6ceb6c4ebe | |||
| 1fadf8c289 | |||
| 76195158e2 |
@@ -1,2 +1 @@
|
||||
nym-validator-rewarder/.sqlx/** diff=nodiff
|
||||
nym-node-status-api/nym-node-status-api/.sqlx/** diff=nodiff
|
||||
|
||||
@@ -100,6 +100,7 @@ jobs:
|
||||
cp target/release/nymvisor $OUTPUT_DIR
|
||||
cp target/release/nym-node $OUTPUT_DIR
|
||||
cp target/release/nym-cli $OUTPUT_DIR
|
||||
cp target/release/explorer-api $OUTPUT_DIR
|
||||
if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then
|
||||
cp target/debian/*.deb $OUTPUT_DIR
|
||||
fi
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
name: ci-check-ns-api-version
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "nym-node-status-api/**"
|
||||
|
||||
env:
|
||||
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-api"
|
||||
|
||||
jobs:
|
||||
check-if-tag-exists:
|
||||
runs-on: arc-ubuntu-22.04-dind
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get version from cargo.toml
|
||||
uses: mikefarah/yq@v4.45.1
|
||||
id: get_version
|
||||
with:
|
||||
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
|
||||
|
||||
- name: Check if git tag exists
|
||||
run: |
|
||||
TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
|
||||
if [[ -z "$TAG" ]]; then
|
||||
echo "Tag is empty"
|
||||
exit 1
|
||||
fi
|
||||
git ls-remote --tags origin | awk '{print $2}'
|
||||
if git ls-remote --tags origin | awk '{print $2}' | grep -q "refs/tags/$TAG$" ; then
|
||||
echo "Tag '$TAG' ALREADY EXISTS on the remote"
|
||||
exit 1
|
||||
else
|
||||
echo "Tag '$TAG' does not exist on the remote"
|
||||
fi
|
||||
- name: Check if harbor tag exists
|
||||
run: |
|
||||
TAG=${{ steps.get_version.outputs.result }}
|
||||
registry=https://harbor.nymte.ch
|
||||
repo_name=nym/node-status-api
|
||||
if [[ -z $TAG ]]; then
|
||||
echo "Tag is empty"
|
||||
exit 1
|
||||
fi
|
||||
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
|
||||
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq --arg tag $TAG '.tags | contains([$tag])' )
|
||||
if [[ $exists = "true" ]]; then
|
||||
echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo"
|
||||
exit 1
|
||||
elif [[ $exists = "false" ]]; then
|
||||
echo "Version '$TAG' doesn't exist on the remote"
|
||||
else
|
||||
echo "Unknown output '$exists'"
|
||||
exit 1
|
||||
fi
|
||||
+10
-108
@@ -4,104 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2025.5-chokito] (2025-03-18)
|
||||
|
||||
- build(deps): bump braces from 3.0.2 to 3.0.3 in /sdk/typescript/packages/nodejs-client ([#5611])
|
||||
- build(deps-dev): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/client/internal-dev ([#5610])
|
||||
- Export lane queue lengths in sdk ([#5609])
|
||||
- Chore/more payment watcher debug endpoints ([#5608])
|
||||
- build(deps): bump @babel/helpers from 7.24.4 to 7.26.10 ([#5606])
|
||||
- Chore/update bls12 381 fork ([#5605])
|
||||
- chore: change auth v2 timestamp skew and allow values from the future ([#5604])
|
||||
- Chore/payment watcher debug endpoints ([#5601])
|
||||
- Allow resetting all SURB sender tags ([#5600])
|
||||
- introduce internal tool for checking signer status ([#5598])
|
||||
- build(deps-dev): bump webpack from 5.77.0 to 5.98.0 in /wasm/mix-fetch/internal-dev ([#5597])
|
||||
- build(deps): bump body-parser and express in /wasm/mix-fetch/internal-dev ([#5596])
|
||||
- build(deps): bump serve-static and express in /wasm/mix-fetch/internal-dev ([#5594])
|
||||
- build(deps-dev): bump ws from 8.13.0 to 8.18.1 in /wasm/mix-fetch/internal-dev ([#5593])
|
||||
- build(deps): bump cookie and express in /wasm/client/internal-dev ([#5592])
|
||||
- build(deps): bump cookie and express in /wasm/mix-fetch/internal-dev ([#5591])
|
||||
- build(deps): bump braces from 3.0.2 to 3.0.3 in /wasm/zknym-lib/internal-dev ([#5590])
|
||||
- build(deps): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/zknym-lib/internal-dev ([#5589])
|
||||
- build(deps): bump tempfile from 3.17.1 to 3.18.0 ([#5588])
|
||||
- build(deps): bump tokio from 1.43.0 to 1.44.0 ([#5587])
|
||||
- build(deps): bump the patch-updates group with 8 updates ([#5585])
|
||||
- build(deps): bump ring from 0.17.9 to 0.17.13 ([#5583])
|
||||
- delete double memo field in send modal ([#5578])
|
||||
- Server Side internal DoT/DoH opt out ([#5577])
|
||||
- Rust SDK SURB example: change hardcoded file to tempdir ([#5576])
|
||||
- Add /v3/nym-nodes ([#5569])
|
||||
- chore: start sending v2 sphinx packets ([#5554])
|
||||
- build(deps): bump the patch-updates group across 1 directory with 14 updates ([#5549])
|
||||
- build(deps): bump uuid from 1.13.2 to 1.15.1 ([#5542])
|
||||
- build(deps): bump rs_merkle from 1.4.2 to 1.5.0 ([#5541])
|
||||
- feature: v2 authentication request ([#5537])
|
||||
- Set RUSTUP_PERMIT_COPY_RENAME ([#5533])
|
||||
- feature: disallow routing mix packets to nodes not present in the topology ([#5526])
|
||||
- Make "Memo" visible per default on send NYM ([#5524])
|
||||
- feat: make sure any terminated task kills the watcher and write run info to db ([#5517])
|
||||
- Another total_stake SQL fix ([#5516])
|
||||
- Fix total_stake on SQL update ([#5514])
|
||||
- build(deps): bump flate2 from 1.0.35 to 1.1.0 ([#5510])
|
||||
- build(deps): bump itertools from 0.13.0 to 0.14.0 ([#5509])
|
||||
- build(deps): bump the patch-updates group with 2 updates ([#5505])
|
||||
- Treat gateways as Nym Nodes ([#5504])
|
||||
- Update version in Cargo.toml ([#5503])
|
||||
- feat: use ct_eq for checking bearer token ([#5501])
|
||||
- Add extra args for the probe ([#5499])
|
||||
- Fix stats bug & remove HM caching ([#5495])
|
||||
- fix: Cargo.lock for contracts ([#5489])
|
||||
- Display error messages if IPv4 or IPv6 address not found on nymtun0 ([#5465])
|
||||
|
||||
[#5611]: https://github.com/nymtech/nym/pull/5611
|
||||
[#5610]: https://github.com/nymtech/nym/pull/5610
|
||||
[#5609]: https://github.com/nymtech/nym/pull/5609
|
||||
[#5608]: https://github.com/nymtech/nym/pull/5608
|
||||
[#5606]: https://github.com/nymtech/nym/pull/5606
|
||||
[#5605]: https://github.com/nymtech/nym/pull/5605
|
||||
[#5604]: https://github.com/nymtech/nym/pull/5604
|
||||
[#5601]: https://github.com/nymtech/nym/pull/5601
|
||||
[#5600]: https://github.com/nymtech/nym/pull/5600
|
||||
[#5598]: https://github.com/nymtech/nym/pull/5598
|
||||
[#5597]: https://github.com/nymtech/nym/pull/5597
|
||||
[#5596]: https://github.com/nymtech/nym/pull/5596
|
||||
[#5594]: https://github.com/nymtech/nym/pull/5594
|
||||
[#5593]: https://github.com/nymtech/nym/pull/5593
|
||||
[#5592]: https://github.com/nymtech/nym/pull/5592
|
||||
[#5591]: https://github.com/nymtech/nym/pull/5591
|
||||
[#5590]: https://github.com/nymtech/nym/pull/5590
|
||||
[#5589]: https://github.com/nymtech/nym/pull/5589
|
||||
[#5588]: https://github.com/nymtech/nym/pull/5588
|
||||
[#5587]: https://github.com/nymtech/nym/pull/5587
|
||||
[#5585]: https://github.com/nymtech/nym/pull/5585
|
||||
[#5583]: https://github.com/nymtech/nym/pull/5583
|
||||
[#5578]: https://github.com/nymtech/nym/pull/5578
|
||||
[#5577]: https://github.com/nymtech/nym/pull/5577
|
||||
[#5576]: https://github.com/nymtech/nym/pull/5576
|
||||
[#5569]: https://github.com/nymtech/nym/pull/5569
|
||||
[#5554]: https://github.com/nymtech/nym/pull/5554
|
||||
[#5549]: https://github.com/nymtech/nym/pull/5549
|
||||
[#5542]: https://github.com/nymtech/nym/pull/5542
|
||||
[#5541]: https://github.com/nymtech/nym/pull/5541
|
||||
[#5537]: https://github.com/nymtech/nym/pull/5537
|
||||
[#5533]: https://github.com/nymtech/nym/pull/5533
|
||||
[#5526]: https://github.com/nymtech/nym/pull/5526
|
||||
[#5524]: https://github.com/nymtech/nym/pull/5524
|
||||
[#5517]: https://github.com/nymtech/nym/pull/5517
|
||||
[#5516]: https://github.com/nymtech/nym/pull/5516
|
||||
[#5514]: https://github.com/nymtech/nym/pull/5514
|
||||
[#5510]: https://github.com/nymtech/nym/pull/5510
|
||||
[#5509]: https://github.com/nymtech/nym/pull/5509
|
||||
[#5505]: https://github.com/nymtech/nym/pull/5505
|
||||
[#5504]: https://github.com/nymtech/nym/pull/5504
|
||||
[#5503]: https://github.com/nymtech/nym/pull/5503
|
||||
[#5501]: https://github.com/nymtech/nym/pull/5501
|
||||
[#5499]: https://github.com/nymtech/nym/pull/5499
|
||||
[#5495]: https://github.com/nymtech/nym/pull/5495
|
||||
[#5489]: https://github.com/nymtech/nym/pull/5489
|
||||
[#5465]: https://github.com/nymtech/nym/pull/5465
|
||||
|
||||
## [2025.4-dorina-patched] (2025-03-06)
|
||||
|
||||
- use legacy crypto for constructing SURB headers ([#5579])
|
||||
@@ -258,7 +160,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- Downgrade harmless log message from info to debug ([#5403])
|
||||
- Redirect from mixnode page to nodes page ([#5397])
|
||||
- chore :update version of chain watcher and validator rewarder ([#5394])
|
||||
- bugfix: correctly handle ignore epoch roles flag ([#5390])
|
||||
- bugfix: correctly handle ingore epoch roles flag ([#5390])
|
||||
- bugfix: terminate mixnet socket listener on shutdown ([#5389])
|
||||
- feat: make client ignore dual mode nodes by default ([#5388])
|
||||
- Handle ecash network errors differently ([#5378])
|
||||
@@ -279,7 +181,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- Use expect in geodata test to give error message on failure ([#5314])
|
||||
- feature: periodically remove stale gateway messages ([#5312])
|
||||
- build(deps): bump the patch-updates group across 1 directory with 35 updates ([#5310])
|
||||
- Add dependabot assigns for the root cargo ecosystem ([#5297])
|
||||
- Add dependabot assignes for the root cargo ecosystem ([#5297])
|
||||
- Move tun constants to network defaults ([#5286])
|
||||
- Include IPINFO_API_TOKEN in nightly CI ([#5285])
|
||||
- Nyx Chain Watcher ([#5274])
|
||||
@@ -332,7 +234,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [2025.1-reeses] (2025-01-15)
|
||||
|
||||
- Feature, Future/legacy alert ([#5346])
|
||||
- Feture/legacy alert ([#5346])
|
||||
- chore: readjusted --mode behaviour to fix the regression ([#5331])
|
||||
- chore: apply 1.84 linter suggestions ([#5330])
|
||||
- bugfix: make sure refresh data key matches bond info ([#5329])
|
||||
@@ -412,7 +314,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [2024.14-crunch-patched] (2024-12-17)
|
||||
|
||||
- Fixes an issue to allow previously registered clients to connect to latest nym-nodes
|
||||
- Fixes an issue to allow previously registred clients to connect to latest nym-nodes
|
||||
- Fixes compatibility issues between nym-nodes and older clients
|
||||
|
||||
## [2024.14-crunch] (2024-12-11)
|
||||
@@ -420,7 +322,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- Merge/release/2024.14-crunch ([#5242])
|
||||
- bugfix: added explicit openapi servers to account for route prefixes ([#5237])
|
||||
- Further config score adjustments ([#5225])
|
||||
- feature: remove any filtering on node semver ([#5224])
|
||||
- feature: remve any filtering on node semver ([#5224])
|
||||
- Backport #5218 ([#5220])
|
||||
- Derive serialize for UserAgent (#5210) ([#5217])
|
||||
- dont consider legacy nodes for rewarded set selection ([#5215])
|
||||
@@ -599,7 +501,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- bugfix/feature: added NymApiClient method to get all skimmed nodes ([#5062])
|
||||
- Merge1/release/2024.13 magura ([#5061])
|
||||
- added hacky routes to return nymnodes alongside legacy nodes ([#5051])
|
||||
- bugfix: mark migrated gateways as rewarded in the previous epoch in case they're, their, there in the rewarded set ([#5049])
|
||||
- bugfix: mark migrated gateways as rewarded in the previous epoch in case theyre in the rewarded set ([#5049])
|
||||
- bugfix: adjust runtime storage migration ([#5047])
|
||||
- bugfix: supersede 'cb13be27f8f61d9ae74d924e85d2e6787895eb14' by using… ([#5046])
|
||||
- bugfix: restore default http port for nym-api ([#5045])
|
||||
@@ -660,7 +562,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- Fix broken build after merge ([#4937])
|
||||
- bugfix: correctly paginate through 'search_tx' endpoint ([#4936])
|
||||
- Add more conversions for responses of authenticator messages ([#4929])
|
||||
- Directory Services, Devices v2.1 ([#4903])
|
||||
- Directory Sevices v2.1 ([#4903])
|
||||
- Migrate Legacy Node (Frontend) ([#4826])
|
||||
- Fix critical issues SI84 and SI85 from Cure53 ([#4758])
|
||||
|
||||
@@ -1044,7 +946,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- Remove stale peers ([#4640])
|
||||
- Add generic wg private network routing ([#4636])
|
||||
- Feature/new node endpoints ([#4635])
|
||||
- standardised ContractBuildInformation and added it to all contracts ([#4631])
|
||||
- standarised ContractBuildInformation and added it to all contracts ([#4631])
|
||||
- validate nym-node public ips on startup ([#4630])
|
||||
- Bump defguard wg ([#4625])
|
||||
- Fix cargo warnings ([#4624])
|
||||
@@ -1665,7 +1567,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- clean-up nym-api startup arguments/flags to use clap 3 and its macro-derived arguments ([#2772])
|
||||
- renamed all references to validator_api to nym_api
|
||||
- renamed all references to nymd to nyxd ([#2696])
|
||||
- all-binaries: standardised argument names (note: old names should still be accepted) ([#2762]
|
||||
- all-binaries: standarised argument names (note: old names should still be accepted) ([#2762]
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -2170,7 +2072,7 @@ The release also include some additional work for distributed key generation in
|
||||
- Explorer UI tests missing data-testid [\#903](https://github.com/nymtech/nym/pull/903) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Fix up Nym-Wallet README.md [\#899](https://github.com/nymtech/nym/pull/899) ([tommyv1987](https://github.com/tommyv1987))
|
||||
- Feature/batch delegator rewarding [\#898](https://github.com/nymtech/nym/pull/898) ([jstuczyn](https://github.com/jstuczyn))
|
||||
- Bug map nodemap [\#897](https://github.com/nymtech/nym/pull/897) ([Aid19801](https://github.com/Aid19801))
|
||||
- Bug mapp nodemap [\#897](https://github.com/nymtech/nym/pull/897) ([Aid19801](https://github.com/Aid19801))
|
||||
- Bug fix/macos keyboard shortcuts [\#896](https://github.com/nymtech/nym/pull/896) ([fmtabbara](https://github.com/fmtabbara))
|
||||
- Add a Mobile Nav to the Network Explorer [\#895](https://github.com/nymtech/nym/pull/895) ([Aid19801](https://github.com/Aid19801))
|
||||
- Only use ts-rs in tests [\#894](https://github.com/nymtech/nym/pull/894) ([durch](https://github.com/durch))
|
||||
|
||||
Generated
+682
-214
File diff suppressed because it is too large
Load Diff
+15
-14
@@ -98,9 +98,9 @@ members = [
|
||||
"common/wireguard",
|
||||
"common/wireguard-types",
|
||||
"documentation/autodoc",
|
||||
# "explorer-api",
|
||||
# "explorer-api/explorer-api-requests",
|
||||
# "explorer-api/explorer-client",
|
||||
"explorer-api",
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"integrations/bity",
|
||||
"nym-api",
|
||||
@@ -153,6 +153,7 @@ members = [
|
||||
default-members = [
|
||||
"clients/native",
|
||||
"clients/socks5",
|
||||
"explorer-api",
|
||||
"nym-api",
|
||||
"nym-credential-proxy/nym-credential-proxy",
|
||||
"nym-node",
|
||||
@@ -193,7 +194,7 @@ ammonia = "4"
|
||||
anyhow = "1.0.97"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = "0.5.0"
|
||||
async-trait = "0.1.88"
|
||||
async-trait = "0.1.87"
|
||||
axum = "0.7.5"
|
||||
axum-client-ip = "0.6.1"
|
||||
axum-extra = "0.9.4"
|
||||
@@ -210,13 +211,13 @@ bs58 = "0.5.1"
|
||||
bytecodec = "0.4.15"
|
||||
bytes = "1.10.1"
|
||||
cargo_metadata = "0.18.1"
|
||||
celes = "2.6.0"
|
||||
celes = "2.5.0"
|
||||
cfg-if = "1.0.0"
|
||||
chacha20 = "0.9.0"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
chrono = "0.4.40"
|
||||
cipher = "0.4.3"
|
||||
clap = "4.5.32"
|
||||
clap = "4.5.31"
|
||||
clap_complete = "4.5"
|
||||
clap_complete_fig = "4.5"
|
||||
colored = "2.2"
|
||||
@@ -241,7 +242,7 @@ dotenvy = "0.15.6"
|
||||
ecdsa = "0.16"
|
||||
ed25519-dalek = "2.1"
|
||||
encoding_rs = "0.8.35"
|
||||
env_logger = "0.11.7"
|
||||
env_logger = "0.11.6"
|
||||
envy = "0.4"
|
||||
etherparse = "0.13.0"
|
||||
eyre = "0.6.9"
|
||||
@@ -263,7 +264,7 @@ http = "1"
|
||||
http-body-util = "0.1"
|
||||
httpcodec = "0.2.3"
|
||||
human-repr = "1.1.0"
|
||||
humantime = "2.2.0"
|
||||
humantime = "2.1.0"
|
||||
humantime-serde = "1.1.1"
|
||||
hyper = "1.6.0"
|
||||
hyper-util = "0.1"
|
||||
@@ -284,7 +285,7 @@ moka = { version = "0.12", features = ["future"] }
|
||||
nix = "0.27.1"
|
||||
notify = "5.1.0"
|
||||
okapi = "0.7.0"
|
||||
once_cell = "1.21.1"
|
||||
once_cell = "1.20.3"
|
||||
opentelemetry = "0.19.0"
|
||||
opentelemetry-jaeger = "0.18.0"
|
||||
parking_lot = "0.12.3"
|
||||
@@ -322,7 +323,7 @@ serde_yaml = "0.9.25"
|
||||
sha2 = "0.10.8"
|
||||
si-scale = "0.2.3"
|
||||
sphinx-packet = "=0.3.2"
|
||||
sqlx = "0.8.3"
|
||||
sqlx = "0.7.4"
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
subtle-encoding = "0.5"
|
||||
@@ -330,7 +331,7 @@ syn = "1"
|
||||
sysinfo = "0.33.0"
|
||||
tap = "1.0.1"
|
||||
tar = "0.4.44"
|
||||
tempfile = "3.19"
|
||||
tempfile = "3.18"
|
||||
thiserror = "2.0"
|
||||
time = "0.3.39"
|
||||
tokio = "1.44"
|
||||
@@ -339,7 +340,7 @@ tokio-stream = "0.1.17"
|
||||
tokio-test = "0.4.4"
|
||||
tokio-tun = "0.11.5"
|
||||
tokio-tungstenite = { version = "0.20.1" }
|
||||
tokio-util = "0.7.14"
|
||||
tokio-util = "0.7.13"
|
||||
toml = "0.8.20"
|
||||
tower = "0.5.2"
|
||||
tower-http = "0.5.2"
|
||||
@@ -361,7 +362,7 @@ vergen = { version = "=8.3.1", default-features = false }
|
||||
walkdir = "2"
|
||||
wasm-bindgen-test = "0.3.49"
|
||||
x25519-dalek = "2.0.0"
|
||||
zeroize = "1.8.1"
|
||||
zeroize = "1.6.0"
|
||||
|
||||
prometheus = { version = "0.13.0" }
|
||||
|
||||
@@ -402,7 +403,7 @@ prost = { version = "0.13", default-features = false }
|
||||
gloo-utils = "0.2.0"
|
||||
gloo-net = "0.6.0"
|
||||
|
||||
indexed_db_futures = "0.6.1"
|
||||
indexed_db_futures = "0.6.0"
|
||||
js-sys = "0.3.76"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
tsify = "0.4.5"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.51"
|
||||
version = "1.1.50"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.51"
|
||||
version = "1.1.50"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
@@ -87,7 +87,7 @@ impl StorageManager {
|
||||
sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|result| result.exists == 1)
|
||||
.map(|result| result.exists == Some(1))
|
||||
}
|
||||
|
||||
pub(crate) async fn maybe_get_registered_gateway(
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::client::replies::reply_controller::{ReplyControllerReceiver, ReplyCon
|
||||
use crate::client::replies::reply_storage::{
|
||||
CombinedReplyStorage, PersistentReplyStorage, ReplyStorageBackend, SentReplyKeys,
|
||||
};
|
||||
use crate::client::topology_control::nym_api_provider::NymApiTopologyProvider;
|
||||
use crate::client::topology_control::smart_api_provider::NymApiTopologyProvider;
|
||||
use crate::client::topology_control::{
|
||||
TopologyAccessor, TopologyRefresher, TopologyRefresherConfig,
|
||||
};
|
||||
@@ -54,8 +54,7 @@ use nym_statistics_common::clients::ClientStatsSender;
|
||||
use nym_statistics_common::generate_client_stats_id;
|
||||
use nym_task::connections::{ConnectionCommandReceiver, ConnectionCommandSender, LaneQueueLengths};
|
||||
use nym_task::{TaskClient, TaskHandle};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::HardcodedTopologyProvider;
|
||||
use nym_topology::providers::{HardcodedTopologyProvider, TopologyProvider};
|
||||
use nym_validator_client::{nyxd::contract_traits::DkgQueryClient, UserAgent};
|
||||
use rand::rngs::OsRng;
|
||||
use std::fmt::Debug;
|
||||
@@ -557,6 +556,7 @@ where
|
||||
config_topology,
|
||||
nym_api_urls,
|
||||
user_agent,
|
||||
None,
|
||||
)),
|
||||
config::TopologyStructure::GeoAware(group_by) => {
|
||||
warn!("using deprecated 'GeoAware' topology provider - this option will be removed very soon");
|
||||
|
||||
@@ -3,7 +3,7 @@ use log::{debug, error};
|
||||
use nym_explorer_client::{ExplorerClient, PrettyDetailedMixNodeBond};
|
||||
use nym_network_defaults::var_names::EXPLORER_API;
|
||||
use nym_topology::{
|
||||
provider_trait::{async_trait, TopologyProvider},
|
||||
providers::{async_trait, TopologyProvider},
|
||||
NymTopology,
|
||||
};
|
||||
use nym_validator_client::client::NodeId;
|
||||
|
||||
@@ -19,11 +19,12 @@ use wasmtimer::tokio::sleep;
|
||||
mod accessor;
|
||||
pub mod geo_aware_provider;
|
||||
pub mod nym_api_provider;
|
||||
pub mod smart_api_provider;
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use geo_aware_provider::GeoAwareTopologyProvider;
|
||||
pub use nym_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
|
||||
pub use nym_topology::provider_trait::TopologyProvider;
|
||||
pub use nym_topology::providers::TopologyProvider;
|
||||
pub use smart_api_provider::{Config as NymApiTopologyProviderConfig, NymApiTopologyProvider};
|
||||
|
||||
// TODO: move it to config later
|
||||
const MAX_FAILURE_COUNT: usize = 10;
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error, warn};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::NymTopology;
|
||||
use nym_topology::{NymTopology, TopologyProvider};
|
||||
use nym_validator_client::UserAgent;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
//! Caching, piecewise API Topology Provider
|
||||
//!
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::{debug, error, warn};
|
||||
pub use nym_topology::providers::piecewise::Config;
|
||||
use nym_topology::{
|
||||
providers::piecewise::{NymTopologyProvider, PiecewiseTopologyProvider},
|
||||
EpochRewardedSet, NymTopology, RoutingNode, TopologyProvider,
|
||||
};
|
||||
use nym_validator_client::UserAgent;
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use url::Url;
|
||||
|
||||
/// Topology Provider build around a cached piecewise provider that uses the Nym API to
|
||||
/// fetch changes and node details.
|
||||
#[derive(Clone)]
|
||||
pub struct NymApiTopologyProvider {
|
||||
inner: NymTopologyProvider<NymApiPiecewiseProvider>,
|
||||
}
|
||||
|
||||
impl NymApiTopologyProvider {
|
||||
/// Construct a new thread safe Cached topology provider using the Nym API
|
||||
pub fn new(
|
||||
config: impl Into<Config>,
|
||||
nym_api_urls: Vec<Url>,
|
||||
user_agent: Option<UserAgent>,
|
||||
initial_topology: Option<NymTopology>,
|
||||
) -> Self {
|
||||
let manager = NymApiPiecewiseProvider::new(nym_api_urls, user_agent);
|
||||
let inner = NymTopologyProvider::new(manager, config.into(), initial_topology);
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<NymTopologyProvider<NymApiPiecewiseProvider>> for NymApiTopologyProvider {
|
||||
fn as_ref(&self) -> &NymTopologyProvider<NymApiPiecewiseProvider> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<NymTopologyProvider<NymApiPiecewiseProvider>> for NymApiTopologyProvider {
|
||||
fn as_mut(&mut self) -> &mut NymTopologyProvider<NymApiPiecewiseProvider> {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.as_mut().get_new_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl TopologyProvider for NymApiTopologyProvider {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.as_mut().get_new_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct NymApiPiecewiseProvider {
|
||||
validator_client: nym_validator_client::client::NymApiClient,
|
||||
nym_api_urls: Vec<Url>,
|
||||
currently_used_api: usize,
|
||||
}
|
||||
|
||||
impl NymApiPiecewiseProvider {
|
||||
fn new(mut nym_api_urls: Vec<Url>, user_agent: Option<UserAgent>) -> Self {
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
|
||||
let validator_client = if let Some(user_agent) = user_agent {
|
||||
nym_validator_client::client::NymApiClient::new_with_user_agent(
|
||||
nym_api_urls[0].clone(),
|
||||
user_agent,
|
||||
)
|
||||
} else {
|
||||
nym_validator_client::client::NymApiClient::new(nym_api_urls[0].clone())
|
||||
};
|
||||
|
||||
Self {
|
||||
validator_client,
|
||||
nym_api_urls,
|
||||
currently_used_api: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn use_next_nym_api(&mut self) {
|
||||
if self.nym_api_urls.len() == 1 {
|
||||
warn!("There's only a single nym API available - it won't be possible to use a different one");
|
||||
return;
|
||||
}
|
||||
|
||||
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
|
||||
self.validator_client
|
||||
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
|
||||
}
|
||||
|
||||
async fn get_full_topology_inner(&mut self) -> Option<NymTopology> {
|
||||
let layer_assignments = self.get_layer_assignments().await?;
|
||||
|
||||
let mut topology = NymTopology::new_empty(layer_assignments);
|
||||
|
||||
let all_nodes = self
|
||||
.validator_client
|
||||
.get_all_basic_nodes()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
self.use_next_nym_api();
|
||||
error!("failed to get network nodes: {err}");
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
debug!("there are {} nodes on the network", all_nodes.len());
|
||||
topology.add_additional_nodes(all_nodes.iter());
|
||||
|
||||
if !topology.is_minimally_routable() {
|
||||
error!("the current filtered active topology can't be used to construct any packets");
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(topology)
|
||||
}
|
||||
|
||||
async fn get_descriptor_batch_inner(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>> {
|
||||
// Does this need to return a hashmap of RoutingNodes? that is moderately inconvenient
|
||||
// especially when the nodes themselves contain their node_id unless we expect to directly
|
||||
// use the result of this fn for lookups where we would otherwise for example, have to
|
||||
// iterate over a whole vec to find a specific node_id.
|
||||
let descriptor_vec = self
|
||||
.validator_client
|
||||
.retrieve_basic_nodes_batch(ids)
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
self.use_next_nym_api();
|
||||
error!("failed to get current rewarded set: {err}");
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
let mut out = Vec::new();
|
||||
for node in descriptor_vec {
|
||||
if let Ok(routing_node) = RoutingNode::try_from(&node) {
|
||||
out.push(routing_node);
|
||||
}
|
||||
}
|
||||
Some(out)
|
||||
}
|
||||
|
||||
async fn get_layer_assignments_inner(&mut self) -> Option<EpochRewardedSet> {
|
||||
self.validator_client
|
||||
.get_current_rewarded_set()
|
||||
.await
|
||||
.inspect_err(|err| {
|
||||
self.use_next_nym_api();
|
||||
error!("failed to get current rewarded set: {err}");
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl PiecewiseTopologyProvider for NymApiPiecewiseProvider {
|
||||
async fn get_full_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_full_topology_inner().await
|
||||
}
|
||||
|
||||
async fn get_descriptor_batch(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>> {
|
||||
self.get_descriptor_batch_inner(ids).await
|
||||
}
|
||||
|
||||
async fn get_layer_assignments(&mut self) -> Option<EpochRewardedSet> {
|
||||
self.get_layer_assignments_inner().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl PiecewiseTopologyProvider for NymApiPiecewiseProvider {
|
||||
async fn get_full_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_full_topology_inner().await
|
||||
}
|
||||
|
||||
async fn get_descriptor_batch(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>> {
|
||||
self.get_descriptor_batch_inner(ids).await
|
||||
}
|
||||
|
||||
async fn get_layer_assignments(&mut self) -> Option<EpochRewardedSet> {
|
||||
self.get_layer_assignments_inner().await
|
||||
}
|
||||
}
|
||||
|
||||
// // Test requires running a local instance of the nym-api binary, for example using:
|
||||
// // `RUST_LOG="info" ./target/debug/nym-api run --nyxd-validator "https://rpc.nymtech.net"`
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod test {
|
||||
// use std::time::Duration;
|
||||
|
||||
// use super::*;
|
||||
// use nym_bin_common::logging::setup_tracing_logger;
|
||||
|
||||
// #[tokio::test]
|
||||
// async fn local_api_provider_test() {
|
||||
// setup_tracing_logger();
|
||||
// let mut provider = NymApiTopologyProvider::new(
|
||||
// Config::default(),
|
||||
// vec!["http://localhost:8000"
|
||||
// .parse()
|
||||
// .expect("failed to parse api url")],
|
||||
// None,
|
||||
// None,
|
||||
// );
|
||||
|
||||
// for _ in 0..180 {
|
||||
// let topo = provider.get_new_topology().await;
|
||||
// assert!(topo.is_some());
|
||||
// tokio::time::sleep(Duration::from_secs(30)).await;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -14,7 +14,8 @@ pub mod error;
|
||||
pub mod init;
|
||||
|
||||
pub use nym_topology::{
|
||||
HardcodedTopologyProvider, NymRouteProvider, NymTopology, NymTopologyError, TopologyProvider,
|
||||
providers::HardcodedTopologyProvider, NymRouteProvider, NymTopology, NymTopologyError,
|
||||
TopologyProvider,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
||||
@@ -498,6 +498,21 @@ impl NymApiClient {
|
||||
Ok(nodes)
|
||||
}
|
||||
|
||||
/// Batch request for node descriptors in the current topology.
|
||||
///
|
||||
/// Given the set of node IDs included in the request body, provide the descriptor for each
|
||||
/// associated node in if it is available in the current topology.
|
||||
pub async fn retrieve_basic_nodes_batch(
|
||||
&self,
|
||||
node_ids: &[u32],
|
||||
) -> Result<Vec<SkimmedNode>, ValidatorClientError> {
|
||||
Ok(self
|
||||
.nym_api
|
||||
.retrieve_basic_nodes_batch(node_ids)
|
||||
.await?
|
||||
.nodes)
|
||||
}
|
||||
|
||||
pub async fn health(&self) -> Result<ApiHealthResponse, ValidatorClientError> {
|
||||
Ok(self.nym_api.health().await?)
|
||||
}
|
||||
|
||||
@@ -270,10 +270,10 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"mixnodes",
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
@@ -286,10 +286,10 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"gateways",
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
@@ -335,9 +335,9 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
"entry-gateways",
|
||||
"all",
|
||||
],
|
||||
@@ -372,9 +372,9 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
"mixnodes",
|
||||
"active",
|
||||
],
|
||||
@@ -409,9 +409,9 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
"mixnodes",
|
||||
"all",
|
||||
],
|
||||
@@ -420,6 +420,31 @@ pub trait NymApiClientExt: ApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Send a Post request with a set of node ids. A successful response will contain descriptors
|
||||
/// for all nodes associated with those node IDs available in the current full topology.
|
||||
///
|
||||
/// If a provided node ID is not present there will be no descriptor for that node in the response.
|
||||
///
|
||||
/// If no node IDs are provided the response will contain no descriptors.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn retrieve_basic_nodes_batch(
|
||||
&self,
|
||||
node_ids: &[NodeId],
|
||||
) -> Result<CachedNodesResponse<SkimmedNode>, NymAPIError> {
|
||||
self.post_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
routes::SKIMMED,
|
||||
routes::BATCH,
|
||||
],
|
||||
NO_PARAMS,
|
||||
node_ids,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
async fn get_basic_nodes(
|
||||
&self,
|
||||
@@ -444,9 +469,9 @@ pub trait NymApiClientExt: ApiClient {
|
||||
self.get_json(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
"unstable",
|
||||
routes::UNSTABLE,
|
||||
routes::NYM_NODES_ROUTES,
|
||||
"skimmed",
|
||||
routes::SKIMMED,
|
||||
],
|
||||
¶ms,
|
||||
)
|
||||
|
||||
@@ -74,3 +74,7 @@ pub const SERVICE_PROVIDERS: &str = "services";
|
||||
pub const DETAILS: &str = "details";
|
||||
pub const CHAIN_STATUS: &str = "chain-status";
|
||||
pub const NETWORK: &str = "network";
|
||||
|
||||
pub const UNSTABLE: &str = "unstable";
|
||||
pub const SKIMMED: &str = "skimmed";
|
||||
pub const BATCH: &str = "batch";
|
||||
|
||||
@@ -182,7 +182,7 @@ impl PersistentStatsStorage {
|
||||
pub async fn get_started_sessions_count(
|
||||
&self,
|
||||
start_date: Date,
|
||||
) -> Result<i64, StatsStorageError> {
|
||||
) -> Result<i32, StatsStorageError> {
|
||||
Ok(self
|
||||
.session_manager
|
||||
.get_started_sessions_count(start_date)
|
||||
|
||||
@@ -148,7 +148,7 @@ impl SessionManager {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(crate) async fn get_started_sessions_count(&self, start_date: Date) -> Result<i64> {
|
||||
pub(crate) async fn get_started_sessions_count(&self, start_date: Date) -> Result<i32> {
|
||||
Ok(sqlx::query!(
|
||||
"SELECT COUNT(*) as count FROM sessions_active WHERE date(start_time) = ?",
|
||||
start_date
|
||||
|
||||
@@ -17,7 +17,7 @@ sqlx = { workspace = true, features = [
|
||||
"macros",
|
||||
"migrate",
|
||||
"time",
|
||||
# "chrono"
|
||||
"chrono"
|
||||
] }
|
||||
time = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -92,7 +92,7 @@ impl TicketStorageManager {
|
||||
)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|result| result.exists == 1)
|
||||
.map(|result| result.exists == Some(1))
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_binary_ticket_data(
|
||||
|
||||
@@ -111,7 +111,7 @@ impl StorageManager {
|
||||
consensus_address: &str,
|
||||
start_height: i64,
|
||||
end_height: i64,
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
trace!("get_signed_between");
|
||||
let start = Instant::now();
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ impl ScraperStorage {
|
||||
consensus_address: &str,
|
||||
start_height: i64,
|
||||
end_height: i64,
|
||||
) -> Result<i64, ScraperError> {
|
||||
) -> Result<i32, ScraperError> {
|
||||
Ok(self
|
||||
.manager
|
||||
.get_signed_between(consensus_address, start_height, end_height)
|
||||
@@ -182,7 +182,7 @@ impl ScraperStorage {
|
||||
consensus_address: &str,
|
||||
start_time: OffsetDateTime,
|
||||
end_time: OffsetDateTime,
|
||||
) -> Result<i64, ScraperError> {
|
||||
) -> Result<i32, ScraperError> {
|
||||
let Some(block_start) = self.get_first_block_height_after(start_time).await? else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
@@ -17,6 +17,9 @@ rand = { workspace = true }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
thiserror = { workspace = true }
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "sync"] }
|
||||
|
||||
|
||||
# 'serde' feature
|
||||
serde_json = { workspace = true, optional = true }
|
||||
@@ -35,7 +38,9 @@ nym-sphinx-types = { path = "../nymsphinx/types", features = [
|
||||
"outfox",
|
||||
] }
|
||||
nym-sphinx-routing = { path = "../nymsphinx/routing" }
|
||||
|
||||
nym-client-core-config-types = { path = "../client-core/config-types", features = [
|
||||
"disk-persistence",
|
||||
] }
|
||||
|
||||
# I'm not sure how to feel about pulling in this dependency here...
|
||||
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
@@ -45,8 +50,8 @@ nym-api-requests = { path = "../../nym-api/nym-api-requests" }
|
||||
wasm-utils = { path = "../wasm/utils", default-features = false, optional = true }
|
||||
|
||||
[features]
|
||||
default = ["provider-trait"]
|
||||
provider-trait = ["async-trait"]
|
||||
default = ["providers"]
|
||||
providers = ["async-trait"]
|
||||
wasm-serde-types = ["tsify", "wasm-bindgen", "wasm-utils"]
|
||||
persistence = ["serde_json"]
|
||||
outfox = []
|
||||
|
||||
+31
-16
@@ -23,13 +23,13 @@ pub mod error;
|
||||
pub mod node;
|
||||
pub mod rewarded_set;
|
||||
|
||||
#[cfg(feature = "provider-trait")]
|
||||
pub mod provider_trait;
|
||||
#[cfg(feature = "wasm-serde-types")]
|
||||
pub mod wasm_helpers;
|
||||
|
||||
#[cfg(feature = "provider-trait")]
|
||||
pub use provider_trait::{HardcodedTopologyProvider, TopologyProvider};
|
||||
#[cfg(feature = "providers")]
|
||||
pub mod providers;
|
||||
#[cfg(feature = "providers")]
|
||||
pub use providers::TopologyProvider;
|
||||
|
||||
#[deprecated]
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -91,18 +91,6 @@ mod deprecated_network_address_impls {
|
||||
|
||||
pub type MixLayer = u8;
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct NymTopology {
|
||||
// for the purposes of future VRF, everyone will need the same view of the network, regardless of performance filtering
|
||||
// so we use the same 'master' rewarded set information for that
|
||||
//
|
||||
// how do we solve the problem of "we have to go through a node that we want to filter out?"
|
||||
// ¯\_(ツ)_/¯ that's a future problem
|
||||
rewarded_set: CachedEpochRewardedSet,
|
||||
|
||||
node_details: HashMap<NodeId, RoutingNode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct NymRouteProvider {
|
||||
pub topology: NymTopology,
|
||||
@@ -189,6 +177,18 @@ impl NymRouteProvider {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
pub struct NymTopology {
|
||||
// for the purposes of future VRF, everyone will need the same view of the network, regardless of performance filtering
|
||||
// so we use the same 'master' rewarded set information for that
|
||||
//
|
||||
// how do we solve the problem of "we have to go through a node that we want to filter out?"
|
||||
// ¯\_(ツ)_/¯ that's a future problem
|
||||
rewarded_set: CachedEpochRewardedSet,
|
||||
|
||||
node_details: HashMap<NodeId, RoutingNode>,
|
||||
}
|
||||
|
||||
impl NymTopology {
|
||||
pub fn new_empty(rewarded_set: impl Into<CachedEpochRewardedSet>) -> Self {
|
||||
NymTopology {
|
||||
@@ -546,4 +546,19 @@ impl NymTopology {
|
||||
.values()
|
||||
.filter(|n| self.rewarded_set.is_active_mixnode(&n.node_id))
|
||||
}
|
||||
|
||||
pub fn all_nodes(&self) -> impl Iterator<Item = &RoutingNode> {
|
||||
self.node_details.values()
|
||||
}
|
||||
|
||||
pub fn all_node_ids(&self) -> impl Iterator<Item = &NodeId> {
|
||||
self.node_details.keys()
|
||||
}
|
||||
|
||||
pub fn gateways(&self) -> impl Iterator<Item = &RoutingNode> {
|
||||
self.node_details.values().filter(|n| {
|
||||
self.rewarded_set.entry_gateways.contains(&n.node_id)
|
||||
|| self.rewarded_set.exit_gateways.contains(&n.node_id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use thiserror::Error;
|
||||
|
||||
pub use nym_mixnet_contract_common::reward_params::Performance;
|
||||
pub use nym_mixnet_contract_common::LegacyMixLayer;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -19,7 +20,7 @@ pub enum RoutingNodeError {
|
||||
NoIpAddressesProvided { node_id: NodeId, identity: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct EntryDetails {
|
||||
// to allow client to choose ipv6 preference, if available
|
||||
pub ip_addresses: Vec<IpAddr>,
|
||||
@@ -28,7 +29,7 @@ pub struct EntryDetails {
|
||||
pub clients_wss_port: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SupportedRoles {
|
||||
pub mixnode: bool,
|
||||
pub mixnet_entry: bool,
|
||||
@@ -45,7 +46,7 @@ impl From<DeclaredRoles> for SupportedRoles {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct RoutingNode {
|
||||
pub node_id: NodeId,
|
||||
|
||||
@@ -56,6 +57,7 @@ pub struct RoutingNode {
|
||||
pub sphinx_key: x25519::PublicKey,
|
||||
|
||||
pub supported_roles: SupportedRoles,
|
||||
pub performance: Performance,
|
||||
}
|
||||
|
||||
impl RoutingNode {
|
||||
@@ -109,6 +111,12 @@ impl<'a> From<&'a RoutingNode> for SphinxNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a RoutingNode> for RoutingNode {
|
||||
fn from(node: &'a RoutingNode) -> Self {
|
||||
node.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a SkimmedNode> for RoutingNode {
|
||||
type Error = RoutingNodeError;
|
||||
|
||||
@@ -138,6 +146,7 @@ impl<'a> TryFrom<&'a SkimmedNode> for RoutingNode {
|
||||
identity_key: value.ed25519_identity_pubkey,
|
||||
sphinx_key: value.x25519_sphinx_pubkey,
|
||||
supported_roles: value.supported_roles.into(),
|
||||
performance: value.performance,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
use crate::NymTopology;
|
||||
pub use async_trait::async_trait;
|
||||
|
||||
// hehe, wasm
|
||||
/// Cached Topology Provider built using efficient piecewise requests.
|
||||
pub mod piecewise;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
pub trait TopologyProvider: Send {
|
||||
@@ -0,0 +1,482 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
//!
|
||||
//!
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use crate::{EpochRewardedSet, NymTopology, RoutingNode, TopologyProvider};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use std::{cmp::min, collections::HashSet, sync::Arc, time::Duration};
|
||||
|
||||
/// Topology filtering and caching configuration
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
/// Specifies a minimum performance of a mixnode that is used on route construction.
|
||||
/// This setting is only applicable when `NymApi` topology is used.
|
||||
pub min_mixnode_performance: u8,
|
||||
|
||||
/// Specifies a minimum performance of a gateway that is used on route construction.
|
||||
/// This setting is only applicable when `NymApi` topology is used.
|
||||
pub min_gateway_performance: u8,
|
||||
|
||||
/// Specifies whether this client should attempt to retrieve all available network nodes
|
||||
/// as opposed to just active mixnodes/gateways.
|
||||
pub use_extended_topology: bool,
|
||||
|
||||
/// Specifies whether this client should ignore the current epoch role of the target egress node
|
||||
/// when constructing the final hop packets.
|
||||
pub ignore_egress_epoch_role: bool,
|
||||
|
||||
/// Minimum duration during which querying the topology will NOT attempt to re-fetch data, and
|
||||
/// will be served from cache.
|
||||
pub cache_ttl: Duration,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
min_mixnode_performance: 50,
|
||||
min_gateway_performance: 0,
|
||||
use_extended_topology: false,
|
||||
ignore_egress_epoch_role: true,
|
||||
cache_ttl: Self::DEFAULT_TOPOLOGY_CACHE_TTL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_client_core_config_types::Topology> for Config {
|
||||
fn from(value: nym_client_core_config_types::Topology) -> Self {
|
||||
Config {
|
||||
min_mixnode_performance: value.minimum_mixnode_performance,
|
||||
min_gateway_performance: value.minimum_gateway_performance,
|
||||
use_extended_topology: value.use_extended_topology,
|
||||
ignore_egress_epoch_role: value.ignore_egress_epoch_role,
|
||||
cache_ttl: value.topology_refresh_rate,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Default duration during which the topology will be reproduced from cache.
|
||||
pub const DEFAULT_TOPOLOGY_CACHE_TTL: Duration = Duration::from_secs(120);
|
||||
|
||||
// if we're using 'extended' topology, filter the nodes based on the lowest set performance
|
||||
fn min_node_performance(&self) -> u8 {
|
||||
min(self.min_mixnode_performance, self.min_gateway_performance)
|
||||
}
|
||||
}
|
||||
|
||||
/// Topology Provider build around a cached piecewise provider that uses the Nym API to
|
||||
/// fetch changes and node details.
|
||||
#[derive(Clone)]
|
||||
pub struct NymTopologyProvider<M: PiecewiseTopologyProvider> {
|
||||
inner: Arc<Mutex<NymTopologyProviderInner<M>>>,
|
||||
}
|
||||
|
||||
impl<M: PiecewiseTopologyProvider> NymTopologyProvider<M> {
|
||||
/// Construct a new thread safe Cached topology provider
|
||||
pub fn new(
|
||||
manager: M,
|
||||
config: Config,
|
||||
initial_topology: Option<NymTopology>,
|
||||
) -> NymTopologyProvider<M> {
|
||||
let inner = NymTopologyProviderInner::new(config, manager, initial_topology);
|
||||
|
||||
NymTopologyProvider {
|
||||
inner: Arc::new(Mutex::new(inner)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Bypass the caching for the topology and force a check for the latest updates next time the
|
||||
/// topology is requested. This fn requires async to get lock in case other threads have access
|
||||
/// to the cached topology state.
|
||||
pub async fn force_refresh(&self) {
|
||||
let mut guard = self.inner.lock().await;
|
||||
guard.cached_at = OffsetDateTime::UNIX_EPOCH;
|
||||
}
|
||||
|
||||
/// Remove all stored topology state. The next time the topology is requested this will force a
|
||||
/// pull of all topology information. This fn requires async to get lock in case other threads
|
||||
/// have access to the cached topology state.
|
||||
///
|
||||
/// WARNING: This may be slow / require non-trivial bandwidth.
|
||||
pub async fn force_clear(&self) {
|
||||
let mut guard = self.inner.lock().await;
|
||||
guard.cached = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl<M: PiecewiseTopologyProvider> TopologyProvider for NymTopologyProvider<M> {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
let mut guard = self.inner.lock().await;
|
||||
// check the cache
|
||||
if let Some(cached) = guard.get_current_compatible_topology().await {
|
||||
return Some(cached);
|
||||
}
|
||||
|
||||
// not cached, or cache expired. try update.
|
||||
guard.update_cache().await;
|
||||
guard.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl<M: PiecewiseTopologyProvider> TopologyProvider for NymTopologyProvider<M> {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
let mut guard = self.inner.lock().await;
|
||||
// check the cache
|
||||
if let Some(cached) = guard.get_current_compatible_topology().await {
|
||||
return Some(cached);
|
||||
}
|
||||
|
||||
// not cached, or cache expired. try update.
|
||||
guard.update_cache().await;
|
||||
guard.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
struct NymTopologyProviderInner<M: PiecewiseTopologyProvider> {
|
||||
config: Config,
|
||||
|
||||
cached: Option<NymTopology>,
|
||||
cached_at: OffsetDateTime,
|
||||
|
||||
topology_manager: M,
|
||||
}
|
||||
|
||||
impl<M: PiecewiseTopologyProvider> NymTopologyProviderInner<M> {
|
||||
pub fn new(
|
||||
config: impl Into<Config>,
|
||||
manager: M,
|
||||
initial_topology: Option<NymTopology>,
|
||||
) -> Self {
|
||||
Self {
|
||||
config: config.into(),
|
||||
cached_at: OffsetDateTime::UNIX_EPOCH,
|
||||
cached: initial_topology,
|
||||
topology_manager: manager,
|
||||
}
|
||||
}
|
||||
|
||||
fn cached_topology(&self) -> Option<NymTopology> {
|
||||
if let Some(cached_topology) = &self.cached {
|
||||
if self.cached_at + self.config.cache_ttl > OffsetDateTime::now_utc() {
|
||||
return Some(cached_topology.clone());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
async fn update_cache(&mut self) {
|
||||
if let Some(ref mut cached_topology) = self.cached {
|
||||
// get layer assignment map
|
||||
let response = self.topology_manager.get_layer_assignments().await;
|
||||
if response.is_none() {
|
||||
warn!("pulled layer assignments and got no response");
|
||||
self.cached_at = OffsetDateTime::now_utc();
|
||||
return;
|
||||
}
|
||||
|
||||
let layer_assignments = response.unwrap();
|
||||
// Check if we already know about the epoch
|
||||
if cached_topology.rewarded_set.epoch_id == layer_assignments.epoch_id {
|
||||
debug!("pulled layer assignments, epoch already known");
|
||||
self.cached_at = OffsetDateTime::now_utc();
|
||||
return;
|
||||
}
|
||||
|
||||
cached_topology.rewarded_set = layer_assignments.into();
|
||||
|
||||
// get the set of node IDs
|
||||
let new_id_set = cached_topology.rewarded_set.all_ids();
|
||||
let known_id_set = HashSet::<u32>::from_iter(cached_topology.all_node_ids().copied());
|
||||
let unknown_node_ids: Vec<_> = new_id_set.difference(&known_id_set).copied().collect();
|
||||
|
||||
// Pull node descriptors for unknown IDs
|
||||
let response = self
|
||||
.topology_manager
|
||||
.get_descriptor_batch(&unknown_node_ids[..])
|
||||
.await;
|
||||
|
||||
// Add the new nodes to our cached topology
|
||||
if let Some(new_descriptors) = response {
|
||||
cached_topology.add_routing_nodes(new_descriptors);
|
||||
}
|
||||
|
||||
// double check that we have the expected nodes
|
||||
let known_id_set = HashSet::<u32>::from_iter(cached_topology.all_node_ids().copied());
|
||||
let unknown_node_ids: Vec<_> = new_id_set.difference(&known_id_set).collect();
|
||||
if !unknown_node_ids.is_empty() {
|
||||
warn!(
|
||||
"still missing descriptors for nodes in the assigned set: {:?}",
|
||||
unknown_node_ids
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self.cached = self.topology_manager.get_full_topology().await;
|
||||
}
|
||||
|
||||
self.cached_at = OffsetDateTime::now_utc();
|
||||
}
|
||||
|
||||
/// Gets the current topology state using `Self::cached_topology` and then applies any filters
|
||||
/// defined in the provided Config.
|
||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
||||
let full_topology = self.cached_topology()?;
|
||||
|
||||
let mut topology = NymTopology::new_empty(full_topology.rewarded_set().clone());
|
||||
|
||||
if self.config.use_extended_topology {
|
||||
topology.add_additional_nodes(full_topology.all_nodes().filter(|n| {
|
||||
n.performance.round_to_integer() >= self.config.min_node_performance()
|
||||
}));
|
||||
|
||||
return Some(full_topology);
|
||||
}
|
||||
|
||||
topology.add_additional_nodes(
|
||||
full_topology.mixnodes().filter(|m| {
|
||||
m.performance.round_to_integer() >= self.config.min_mixnode_performance
|
||||
}),
|
||||
);
|
||||
topology.add_additional_nodes(
|
||||
full_topology.gateways().filter(|m| {
|
||||
m.performance.round_to_integer() >= self.config.min_gateway_performance
|
||||
}),
|
||||
);
|
||||
|
||||
Some(topology)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[async_trait]
|
||||
impl<P: PiecewiseTopologyProvider> TopologyProvider for NymTopologyProviderInner<P> {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[async_trait(?Send)]
|
||||
impl<P: PiecewiseTopologyProvider> TopologyProvider for NymTopologyProviderInner<P> {
|
||||
async fn get_new_topology(&mut self) -> Option<NymTopology> {
|
||||
self.get_current_compatible_topology().await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// Trait allowing construction and upkeep of a
|
||||
#[async_trait]
|
||||
pub trait PiecewiseTopologyProvider: Send {
|
||||
/// Pull a copy of the full topology.
|
||||
///
|
||||
/// This is intended to be used sparingly as repeated usage could result in fetching duplicate
|
||||
/// information more often than necessary.
|
||||
async fn get_full_topology(&mut self) -> Option<NymTopology>;
|
||||
|
||||
/// Fetch a node descriptors for the set of provided IDs if available.
|
||||
async fn get_descriptor_batch(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>>;
|
||||
|
||||
/// Fetch the latest mapping of node IDs to Nym Network layer.
|
||||
async fn get_layer_assignments(&mut self) -> Option<EpochRewardedSet>;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
/// Trait allowing construction and upkeep of a
|
||||
#[async_trait(?Send)]
|
||||
pub trait PiecewiseTopologyProvider: Send {
|
||||
/// Pull a copy of the full topology.
|
||||
///
|
||||
/// This is intended to be used sparingly as repeated usage could result in fetching duplicate
|
||||
/// information more often than necessary.
|
||||
async fn get_full_topology(&mut self) -> Option<NymTopology>;
|
||||
|
||||
/// Fetch a node descriptors for the set of provided IDs if available.
|
||||
async fn get_descriptor_batch(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>>;
|
||||
|
||||
/// Fetch the latest mapping of node IDs to Nym Network layer.
|
||||
async fn get_layer_assignments(&mut self) -> Option<EpochRewardedSet>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::SupportedRoles;
|
||||
use nym_crypto::asymmetric::encryption::PublicKey as SphinxPubkey;
|
||||
use nym_crypto::asymmetric::identity::PublicKey as IdentityPubkey;
|
||||
use nym_mixnet_contract_common::Percent;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PassthroughPiecewiseTopologyProvider {
|
||||
topo: NymTopology,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl PiecewiseTopologyProvider for PassthroughPiecewiseTopologyProvider {
|
||||
async fn get_full_topology(&mut self) -> Option<NymTopology> {
|
||||
Some(self.topo.clone())
|
||||
}
|
||||
|
||||
async fn get_descriptor_batch(&mut self, ids: &[u32]) -> Option<Vec<RoutingNode>> {
|
||||
let mut nodes = Vec::new();
|
||||
ids.iter().for_each(|id| {
|
||||
if let Some(node) = self.topo.node_details.get(id) {
|
||||
nodes.push(node.clone());
|
||||
}
|
||||
});
|
||||
|
||||
Some(nodes)
|
||||
}
|
||||
|
||||
async fn get_layer_assignments(&mut self) -> Option<EpochRewardedSet> {
|
||||
return Some(self.topo.rewarded_set.clone().into());
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_topology_provider() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut topo_mgr = PassthroughPiecewiseTopologyProvider {
|
||||
topo: NymTopology::default(),
|
||||
};
|
||||
|
||||
let mut topo_provider =
|
||||
NymTopologyProviderInner::new(Config::default(), topo_mgr.clone(), None);
|
||||
|
||||
// No initial topology was provided, No update has run yet, None should be returned
|
||||
assert_eq!(topo_provider.cached_topology(), None);
|
||||
|
||||
// force an update of the cached topology
|
||||
topo_provider.update_cache().await;
|
||||
|
||||
let topo = topo_provider.cached_topology();
|
||||
assert!(topo.is_some());
|
||||
let topo = topo.unwrap();
|
||||
assert!(topo.is_empty());
|
||||
|
||||
// create a change in the manager to make sure it is propogated to the provider cache on update
|
||||
topo_mgr.topo.rewarded_set.epoch_id += 1;
|
||||
topo_mgr.topo.rewarded_set.entry_gateways = HashSet::from([123]);
|
||||
assert_eq!(topo_mgr.topo.node_details.insert(123, fake_node(123)), None);
|
||||
topo_provider.topology_manager = topo_mgr.clone();
|
||||
|
||||
// force an update of the cached topology
|
||||
topo_provider.update_cache().await;
|
||||
|
||||
let topo = topo_provider.cached_topology();
|
||||
assert!(topo.is_some());
|
||||
let topo1 = topo.unwrap();
|
||||
assert!(!topo1.is_empty());
|
||||
assert!(topo1.node_details.contains_key(&123));
|
||||
|
||||
// try forcing an update even though the epoch has not changed. Should result in no change
|
||||
topo_provider.update_cache().await;
|
||||
let topo2 = topo_provider.cached_topology().unwrap();
|
||||
assert_eq!(topo1, topo2);
|
||||
|
||||
// Add a node without a descriptor to make sure warning is printed.
|
||||
topo_mgr.topo.rewarded_set.epoch_id += 1;
|
||||
topo_mgr.topo.rewarded_set.entry_gateways = HashSet::from([123, 456]);
|
||||
topo_provider.topology_manager = topo_mgr.clone();
|
||||
|
||||
// try forcing an update even though the epoch has not changed. Should result in no change
|
||||
topo_provider.update_cache().await;
|
||||
let _ = topo_provider.cached_topology().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_topology_provider_by_trait() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut topo_mgr = PassthroughPiecewiseTopologyProvider {
|
||||
topo: NymTopology::default(),
|
||||
};
|
||||
|
||||
let mut topo_provider = NymTopologyProvider::new(topo_mgr.clone(), Config::default(), None);
|
||||
|
||||
// No initial topology was provided, the NymTopologyProvider should do an update from the
|
||||
// manager to build its cache. This should be our empty topology initialized in the manage
|
||||
// above
|
||||
let maybe_topo = topo_provider.get_new_topology().await;
|
||||
assert!(maybe_topo.is_some());
|
||||
let topo1 = maybe_topo.unwrap();
|
||||
assert!(topo1.is_empty());
|
||||
|
||||
// Try pulling again, should give response from cache because we are under ttl
|
||||
let maybe_topo = topo_provider.get_new_topology().await;
|
||||
assert!(maybe_topo.is_some());
|
||||
let topo2 = maybe_topo.unwrap();
|
||||
assert_eq!(topo1, topo2);
|
||||
|
||||
// create a change in the manager
|
||||
topo_mgr.topo.rewarded_set.epoch_id += 1;
|
||||
topo_mgr.topo.rewarded_set.entry_gateways = HashSet::from([123]);
|
||||
assert_eq!(topo_mgr.topo.node_details.insert(123, fake_node(123)), None);
|
||||
{
|
||||
let mut guard = topo_provider.inner.lock().await;
|
||||
guard.topology_manager = topo_mgr.clone();
|
||||
drop(guard)
|
||||
}
|
||||
|
||||
// The NymTopologyProvider should still serve from cache because we haven't crossed ttl
|
||||
// despite updates being available in the manager
|
||||
let maybe_topo = topo_provider.get_new_topology().await;
|
||||
assert!(maybe_topo.is_some());
|
||||
let topo3 = maybe_topo.unwrap();
|
||||
assert_eq!(topo2, topo3);
|
||||
|
||||
// force ttl timeout should allow refresh that includes latest changes from manager
|
||||
topo_provider.force_refresh().await;
|
||||
let maybe_topo = topo_provider.get_new_topology().await;
|
||||
assert!(maybe_topo.is_some());
|
||||
let topo4 = maybe_topo.unwrap();
|
||||
assert_ne!(topo3, topo4);
|
||||
assert!(topo4.node_details.contains_key(&123));
|
||||
|
||||
// create another change in the manager
|
||||
topo_mgr.topo.rewarded_set.epoch_id += 1;
|
||||
topo_mgr.topo.rewarded_set.entry_gateways = HashSet::from([123, 456]);
|
||||
assert_eq!(topo_mgr.topo.node_details.insert(456, fake_node(456)), None);
|
||||
{
|
||||
let mut guard = topo_provider.inner.lock().await;
|
||||
guard.topology_manager = topo_mgr.clone();
|
||||
drop(guard)
|
||||
}
|
||||
|
||||
// force clear cache should also pull latest full topology
|
||||
topo_provider.force_clear().await;
|
||||
let maybe_topo = topo_provider.get_new_topology().await;
|
||||
assert!(maybe_topo.is_some());
|
||||
let topo5 = maybe_topo.unwrap();
|
||||
assert!(topo5.node_details.contains_key(&456));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fake_node(node_id: u32) -> RoutingNode {
|
||||
RoutingNode {
|
||||
node_id,
|
||||
mix_host: "127.0.0.1:2345".parse().unwrap(),
|
||||
entry: None,
|
||||
identity_key: IdentityPubkey::from_bytes(&[0u8; 32][..]).unwrap(),
|
||||
sphinx_key: SphinxPubkey::from_bytes(&[0u8; 32][..]).unwrap(),
|
||||
supported_roles: SupportedRoles {
|
||||
mixnode: true,
|
||||
mixnet_entry: true,
|
||||
mixnet_exit: true,
|
||||
},
|
||||
performance: Percent::hundred(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use nym_mixnet_contract_common::{EpochId, EpochRewardedSet, NodeId, RewardedSet}
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||
pub struct CachedEpochRewardedSet {
|
||||
pub epoch_id: EpochId,
|
||||
|
||||
@@ -119,4 +119,22 @@ impl CachedEpochRewardedSet {
|
||||
mixnodes.extend(&self.layer3);
|
||||
mixnodes
|
||||
}
|
||||
|
||||
pub fn all_ids(&self) -> HashSet<NodeId> {
|
||||
let mut mixnodes = HashSet::with_capacity(
|
||||
self.entry_gateways.len()
|
||||
+ self.exit_gateways.len()
|
||||
+ self.layer1.len()
|
||||
+ self.layer2.len()
|
||||
+ self.layer3.len()
|
||||
+ self.standby.len(),
|
||||
);
|
||||
mixnodes.extend(&self.entry_gateways);
|
||||
mixnodes.extend(&self.exit_gateways);
|
||||
mixnodes.extend(&self.layer1);
|
||||
mixnodes.extend(&self.layer2);
|
||||
mixnodes.extend(&self.layer3);
|
||||
mixnodes.extend(&self.standby);
|
||||
mixnodes
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
use crate::node::{EntryDetails, RoutingNode, RoutingNodeError, SupportedRoles};
|
||||
use crate::{CachedEpochRewardedSet, NymTopology};
|
||||
use nym_mixnet_contract_common::reward_params::Performance;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::net::SocketAddr;
|
||||
@@ -105,6 +106,8 @@ impl TryFrom<WasmFriendlyRoutingNode> for RoutingNode {
|
||||
}
|
||||
})?,
|
||||
supported_roles: value.supported_roles,
|
||||
|
||||
performance: Performance::hundred(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ pub use nym_sphinx::{
|
||||
};
|
||||
pub use nym_statistics_common::clients::ClientStatsSender;
|
||||
pub use nym_task;
|
||||
pub use nym_topology::{HardcodedTopologyProvider, MixLayer, NymTopology, TopologyProvider};
|
||||
pub use nym_topology::{
|
||||
providers::HardcodedTopologyProvider, MixLayer, NymTopology, TopologyProvider,
|
||||
};
|
||||
pub use nym_validator_client::nym_api::Client as ApiClient;
|
||||
pub use nym_validator_client::{DirectSigningReqwestRpcNyxdClient, QueryReqwestRpcNyxdClient};
|
||||
// TODO: that's a very nasty import path. it should come from contracts instead!
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import explorerLogo from "../public/images/smiley.png";
|
||||
|
||||
export const Explorer = () => {
|
||||
return (
|
||||
<Link
|
||||
href={"https://nym.com/explorer"}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
src={explorerLogo}
|
||||
style = {{
|
||||
marginRight: "0.6rem"
|
||||
}}
|
||||
alt={"Network Explorer"}
|
||||
width={24}
|
||||
height={24}
|
||||
/>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
@@ -5,7 +5,7 @@ const links = [
|
||||
["Matrix", "https://matrix.to/#/#dev:nymtech.chat"],
|
||||
["GitHub", "https://nymtech.net/go/github/nym"],
|
||||
["Nym Wallet", "https://nymtech.net/download/wallet"],
|
||||
["Nym Explorer", "https://nym.com/explorer/"],
|
||||
["Nym Explorer", "https://explorer.nymtech.net/"],
|
||||
["Nym Blog", "https://nymtech.medium.com/"],
|
||||
["Twitter", "https://nymtech.net/go/x"],
|
||||
["Telegram", "https://nymtech.net/go/telegram"],
|
||||
|
||||
@@ -6,6 +6,10 @@ import { useTheme } from "@mui/material/styles";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
// import networkDocs from "../public/images/landing/network-docs.png";
|
||||
// import developerDocs from "../public/images/landing/developer-docs.png";
|
||||
// import sdkDocs from "../public/images/landing/sdk-docs.png";
|
||||
// import operatorGuide from "../public/images/landing/operator-guide.png";
|
||||
import networkDocs from "../public/images/landing/Vector1.png";
|
||||
import developerDocs from "../public/images/landing/Vector2.png";
|
||||
import sdkDocs from "../public/images/landing/Vector3.png";
|
||||
@@ -37,6 +41,13 @@ export const LandingPage = () => {
|
||||
href: "/developers",
|
||||
icon: sdkDocs,
|
||||
},
|
||||
// {
|
||||
// text: "SDKs",
|
||||
// description: "Rust and Typescript SDK docs",
|
||||
|
||||
// href: "/developers/rust",
|
||||
// icon: sdkDocs,
|
||||
// },
|
||||
{
|
||||
text: "APIs",
|
||||
description: "Interactive API specs for Nym infrastructure",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Box } from "@mui/material";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import matrixLogo from "../public/images/matrix-logo.png";
|
||||
|
||||
export const Matrix = () => {
|
||||
return (
|
||||
<Link
|
||||
@@ -9,14 +9,7 @@ export const Matrix = () => {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image src={matrixLogo}
|
||||
style = {{
|
||||
marginRight: "0.6rem"
|
||||
}}
|
||||
alt={"Matrix Logo"}
|
||||
width={20}
|
||||
height={24}
|
||||
/>
|
||||
<Image src={matrixLogo} alt={"Matrix Logo"} width={20} height={24} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
# Explorer API
|
||||
|
||||
The Explorer API is the backend for the [Mixnet Explorer](https://nym.com/explorer).
|
||||
The Explorer API is the backend for the [Mixnet Explorer](https://explorer.nymtech.net/).
|
||||
|
||||
**This will soon be deprecated in favour of the [Node Status API](ns-api.mdx).**
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ The `--id` in the example above is a local identifier so that you can name your
|
||||
|
||||
The `--use-reply-surbs` field denotes whether you wish to send [SURBs](../../network/concepts/anonymous-replies) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with versions of the pre-smoosh `nym-network-requester` binary which will soon be deprecated.
|
||||
|
||||
The `--provider` field needs to be filled with the Nym address of an Exit Gateway that can make network requests on your behalf. You can select one from the [mixnet explorer](https://nym.com/explorer) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).
|
||||
The `--provider` field needs to be filled with the Nym address of an Exit Gateway that can make network requests on your behalf. You can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/gateways) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).
|
||||
|
||||
## Choosing a Gateway
|
||||
By default - as in the example above - your client will choose a random gateway to connect to.
|
||||
@@ -42,6 +42,6 @@ However, there are several options for choosing a gateway, if you do not want on
|
||||
* send few ping messages to all of them, and measure response times.
|
||||
* create a weighted distribution to randomly choose one, favouring ones with lower latency.
|
||||
|
||||
You can select one from the [mixnet explorer](https://nym.com/explorer) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).
|
||||
You can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/gateways) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/).
|
||||
|
||||
> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms
|
||||
|
||||
@@ -31,7 +31,7 @@ Initialising a new client instance can be done with the following command:
|
||||
|
||||
The `--id` in the example above is a local identifier so that you can name your clients; it is **never** transmitted over the network.
|
||||
|
||||
There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mixnet explorer](https://nym.com/explorer). Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/)
|
||||
There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mixnet explorer](https://explorer.nymtech.net/network-components/gateways). Alternatively, you could use [Harbourmaster](https://harbourmaster.nymtech.net/)
|
||||
|
||||
Not passing this argument will randomly select a gateway for your client.
|
||||
|
||||
|
||||
@@ -19,4 +19,4 @@ To illustrate this: `DpB3cHAchJiNBQi5FrZx2csXb1mrHkpYh9Wzf8Rjsuko.ANNWrvHqMYuert
|
||||
|
||||
- `DpB3cHAchJiNBQi5FrZx2csXb1mrHkpYh9Wzf8Rjsuko`: is the client's identity key;
|
||||
- `ANNWrvHqMYuertHGHUrZdBntQhpzfbWekB39qez9U2Vx`: is the client's Diffie Hellman key;
|
||||
- `2BuMSfMW3zpeAjKXyKLhmY4QW1DXurrtSPEJ6CjX3SEh`: is the gateway's identity, which is what you'll need to check the state of the gateway in the [Nym Explorer](https://nym.com/explorer).
|
||||
- `2BuMSfMW3zpeAjKXyKLhmY4QW1DXurrtSPEJ6CjX3SEh`: is the gateway's identity, which is what you'll need to check the state of the gateway in the [Nym Explorer](https://explorer.nymtech.net/network-components/gateways).
|
||||
|
||||
@@ -10,7 +10,7 @@ Yes, there are..
|
||||
|
||||
**Built by Nym**
|
||||
|
||||
* [Nym Explorer](https://nym.com/explorer)
|
||||
* [Nym Explorer](https://explorer.nymtech.net/)
|
||||
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
|
||||
* [Nym Harbourmaster](https://harbourmaster.nymtech.net)
|
||||
|
||||
|
||||
+1
-1
@@ -259,7 +259,7 @@ That can be done only on an IP+destination port basis, however. Common P2P ports
|
||||
|
||||
<p>
|
||||
You also have the option of blocking this IP address and others on the Nym network if you so desire.
|
||||
The Nym project provides a <a href="https://nym.com/explorer">
|
||||
The Nym project provides a <a href="https://explorer.nymtech.net/network-components/gateways">
|
||||
web service</a> to fetch a list of all IP addresses of Nym Gateway Exit nodes that allow exiting to a
|
||||
specified IP:port combination. Please be considerate when using these options.</p>
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ From `nym-node v1.3.0` operators can choose multiple functionalities for their `
|
||||
|
||||
### Mixnet Routing
|
||||
|
||||
***Mixnet mode (5-hop) is the full anonymising option of NymVPN. Read more about the Mixnet architecture [here](../../../network/architecture)***
|
||||
***Mixnet mode (5-hop) is the full anonymising option of NymVPN. Read more about the Mixnet architecture [here](http://localhost:3000/docs/network/architecture)***
|
||||
|
||||
Nym Node has three functionalities in the Mixnet: `entry-gateway`, `mixnode` and `exit-gateway`. These are selected with a flag `--mode <MODE>` alongside `nym-node` command `run` .
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Nym Node operators running Gateway functionality are already familiar with the monitoring tool [Harbourmaster.nymtech.net](https://harbourmaster.nymtech.net). Under the hood of Nym Harbourmaster runs iterations of `nym-gateway-probe` doing various checks and displaying the results on the interface. Operators don't have to rely on the probe ran by Nym and wait for the data to refresh. With `nym-gateway-probe` everyone can check any Gateway's networking status from their own computer at any time. In one command the client queries data from:
|
||||
|
||||
- [`nym-api`](https://validator.nymtech.net/api/v1/gateways)
|
||||
- [`explorer-api`](https://mainnet-node-status-api.nymtech.cc/swagger/#/Gateways)
|
||||
- [`explorer-api`](https://explorer.nymtech.net/api/v1/gateways)
|
||||
- [`harbour-master`](https://harbourmaster.nymtech.net/)
|
||||
|
||||
|
||||
@@ -88,3 +88,4 @@ For any `nym-node --mode exit-gateway` the aim is to have this outcome:
|
||||
**If your Gateway is blacklisted, the probe will not work.**
|
||||
|
||||
If you don't provide a `--gateway` flag it will pick a random one to test.
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ $1 \ NYM = 1 \_ 000 \_ 000 \ uNYM$
|
||||
|
||||
The Reward Estimation API endpoint allows Mix Node operators to estimate the rewards they could earn for running a Nym Mix Node with a specific `MIX_ID`.
|
||||
|
||||
> The `<MIX_ID>` can be found in the "Mix ID" column of the [Network Explorer](https://nym.com/explorer).
|
||||
> The `<MIX_ID>` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active).
|
||||
|
||||
The endpoint is a particularly common for Mix Node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the Mix Node, the quality of the Mix Node's performance, and the overall demand for Mix Nodes in the network. This information can be useful for Mix Node operators in deciding whether or not to run a Mix Node and in optimizing its operations for maximum profitability.
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ The directory structure for each node will be roughly as follows:
|
||||
```
|
||||
|
||||
<Callout>
|
||||
If you `cat` the `public_sphinx.pem` key, the output will be different from the public key you will see on Nym [dashboard](https://nym.com/explorer). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding.
|
||||
If you `cat` the `public_sphinx.pem` key, the output will be different from the public key you will see on Nym [dashboard](https://explorer.nymtech.net/). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding.
|
||||
</Callout>
|
||||
|
||||
### Accidentally killing your node process on exiting session
|
||||
@@ -101,7 +101,7 @@ You don't have to do any additional configuration for your node to implement thi
|
||||
### How can I tell my node is up and running and mixing traffic?
|
||||
|
||||
First of all check the 'Mixnodes' section of either of the Nym Network Explorers:
|
||||
* [Mainnet](https://nym.com/explorer)
|
||||
* [Mainnet](https://explorer.nymtech.net/)
|
||||
* [Sandbox testnet](https://sandbox-explorer.nymtech.net/)
|
||||
|
||||
You can also check [Nym Harbourmaster](https://harbourmaster.nymtech.net) which now also includes mixnode mode.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 136 KiB |
@@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import { DocsThemeConfig, useConfig } from "nextra-theme-docs";
|
||||
// import { Footer } from "./components/footer";
|
||||
import { Footer } from "./components/footer";
|
||||
import { Matrix } from "./components/matrix-link";
|
||||
import { Explorer } from "./components/explorer-link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const config: DocsThemeConfig = {
|
||||
@@ -67,9 +66,9 @@ const config: DocsThemeConfig = {
|
||||
},
|
||||
docsRepositoryBase:
|
||||
"https://github.com/nymtech/nym/tree/develop/documentation/docs/",
|
||||
// footer: {
|
||||
// text: Footer,
|
||||
// },
|
||||
footer: {
|
||||
text: Footer,
|
||||
},
|
||||
darkMode: true,
|
||||
nextThemes: {
|
||||
defaultTheme: "dark",
|
||||
@@ -78,14 +77,8 @@ const config: DocsThemeConfig = {
|
||||
defaultMenuCollapseLevel: 1,
|
||||
autoCollapse: true,
|
||||
},
|
||||
|
||||
navbar: {
|
||||
extraContent: (
|
||||
<>
|
||||
<Explorer />
|
||||
<Matrix />
|
||||
</>
|
||||
),
|
||||
extraContent: <Matrix />,
|
||||
},
|
||||
toc: {
|
||||
float: false,
|
||||
|
||||
@@ -19,6 +19,7 @@ pub(crate) struct Config {
|
||||
pub(crate) bandwidth: BandwidthFlushingBehaviourConfig,
|
||||
}
|
||||
|
||||
// I can see this being possible expanded with say storage or client store
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CommonHandlerState {
|
||||
pub(crate) cfg: Config,
|
||||
|
||||
@@ -131,6 +131,9 @@ impl<R, S> FreshHandler<R, S> {
|
||||
|
||||
// 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
|
||||
// some considerable refactoring
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
rng: R,
|
||||
conn: S,
|
||||
|
||||
@@ -6,8 +6,9 @@ use crate::node::client_handling::websocket::connection_handler::FreshHandler;
|
||||
use nym_task::TaskClient;
|
||||
use rand::rngs::OsRng;
|
||||
use std::net::SocketAddr;
|
||||
use std::{io, process};
|
||||
use tokio::net::TcpStream;
|
||||
use std::process;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::*;
|
||||
|
||||
@@ -33,76 +34,6 @@ impl Listener {
|
||||
}
|
||||
}
|
||||
|
||||
fn active_connections(&self) -> usize {
|
||||
self.shared_state
|
||||
.metrics
|
||||
.network
|
||||
.active_ingress_websocket_connections_count()
|
||||
}
|
||||
|
||||
fn prepare_connection_handler(
|
||||
&self,
|
||||
socket: TcpStream,
|
||||
remote_address: SocketAddr,
|
||||
) -> FreshHandler<OsRng, TcpStream> {
|
||||
let shutdown = self
|
||||
.shutdown
|
||||
.fork(format!("websocket_handler_{remote_address}"));
|
||||
FreshHandler::new(
|
||||
OsRng,
|
||||
socket,
|
||||
self.shared_state.clone(),
|
||||
remote_address,
|
||||
shutdown,
|
||||
)
|
||||
}
|
||||
|
||||
fn try_handle_accepted_connection(&self, accepted: io::Result<(TcpStream, SocketAddr)>) {
|
||||
match accepted {
|
||||
Ok((socket, remote_address)) => {
|
||||
trace!("received a socket connection from {remote_address}");
|
||||
|
||||
let active = self.active_connections();
|
||||
|
||||
// 1. check if we're within the connection limit
|
||||
if active >= self.maximum_open_connections {
|
||||
warn!(
|
||||
"connection limit exceeded ({}). can't accept request from {remote_address}",
|
||||
self.maximum_open_connections
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("there are currently {active} connected clients on the gateway websocket");
|
||||
|
||||
// 2. prepare shared data for the new connection handler
|
||||
let handle = self.prepare_connection_handler(socket, remote_address);
|
||||
|
||||
// 3. increment the connection counter.
|
||||
// make sure to do it before spawning the task,
|
||||
// as another connection might get accepted before the task is scheduled
|
||||
// for execution
|
||||
self.shared_state
|
||||
.metrics
|
||||
.network
|
||||
.new_ingress_websocket_client();
|
||||
|
||||
// 4. spawn the task handling the client connection
|
||||
tokio::spawn(async move {
|
||||
// TODO: refactor it similarly to the mixnet listener on the nym-node
|
||||
let metrics_ref = handle.shared_state.metrics.clone();
|
||||
|
||||
// 4.1. handle all client requests until connection gets terminated
|
||||
handle.start_handling().await;
|
||||
|
||||
// 4.2. decrement the connection counter
|
||||
metrics_ref.network.disconnected_ingress_websocket_client();
|
||||
});
|
||||
}
|
||||
Err(err) => warn!("failed to accept client connection: {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: change the signature to pub(crate) async fn run(&self, handler: Handler)
|
||||
|
||||
pub(crate) async fn run(&mut self) {
|
||||
@@ -115,6 +46,8 @@ impl Listener {
|
||||
}
|
||||
};
|
||||
|
||||
let open_connections = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
while !self.shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
@@ -122,7 +55,38 @@ impl Listener {
|
||||
trace!("client_handling::Listener: received shutdown");
|
||||
}
|
||||
connection = tcp_listener.accept() => {
|
||||
self.try_handle_accepted_connection(connection)
|
||||
match connection {
|
||||
Ok((socket, remote_addr)) => {
|
||||
let shutdown = self.shutdown.fork(format!("websocket_handler_{remote_addr}"));
|
||||
trace!("received a socket connection from {remote_addr}");
|
||||
|
||||
if open_connections.fetch_add(1, Ordering::SeqCst) >= self.maximum_open_connections {
|
||||
warn!("connection limit exceeded ({}). can't accept request from {remote_addr}", self.maximum_open_connections);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: I think we *REALLY* need a mechanism for having a maximum number of connected
|
||||
// clients or spawned tokio tasks -> perhaps a worker system?
|
||||
let handle = FreshHandler::new(
|
||||
OsRng,
|
||||
socket,
|
||||
self.shared_state.clone(),
|
||||
remote_addr,
|
||||
shutdown,
|
||||
);
|
||||
let open_connections = open_connections.clone();
|
||||
tokio::spawn(async move {
|
||||
// TODO: refactor it similarly to the mixnet listener on the nym-node
|
||||
let metrics_ref = handle.shared_state.metrics.clone();
|
||||
metrics_ref.network.new_ingress_websocket_client();
|
||||
open_connections.fetch_add(1, Ordering::SeqCst);
|
||||
handle.start_handling().await;
|
||||
metrics_ref.network.disconnected_ingress_websocket_client();
|
||||
open_connections.fetch_sub(1, Ordering::SeqCst);
|
||||
});
|
||||
}
|
||||
Err(err) => warn!("failed to get client: {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
[package]
|
||||
name = "nym-api"
|
||||
license = "GPL-3.0"
|
||||
version = "1.1.54"
|
||||
version = "1.1.53"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
rust-version.workspace = true
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::support::caching::cache::SharedCache;
|
||||
use crate::support::legacy_helpers::legacy_host_to_ips_and_hostname;
|
||||
use nym_api_requests::legacy::{LegacyGatewayBondWithId, LegacyMixNodeBondWithLayer};
|
||||
use nym_api_requests::models::{NodeAnnotation, NymNodeDescription};
|
||||
use nym_contracts_common::NaiveFloat;
|
||||
use nym_contracts_common::{NaiveFloat, Percent};
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_mixnet_contract_common::{LegacyMixLayer, NodeId};
|
||||
use nym_node_tester_utils::node::{NodeType, TestableNode};
|
||||
@@ -231,6 +231,8 @@ impl PacketPreparer {
|
||||
mixnet_entry: false,
|
||||
mixnet_exit: false,
|
||||
},
|
||||
// We have no information about performance in legacy node formats
|
||||
performance: Percent::hundred(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,6 +265,8 @@ impl PacketPreparer {
|
||||
mixnet_entry: true,
|
||||
mixnet_exit: false,
|
||||
},
|
||||
// We have no information about performance in legacy node formats
|
||||
performance: Percent::hundred(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::nym_nodes::handlers::unstable::semi_skimmed::nodes_expanded;
|
||||
use crate::nym_nodes::handlers::unstable::skimmed::{
|
||||
entry_gateways_basic_active, entry_gateways_basic_all, exit_gateways_basic_active,
|
||||
exit_gateways_basic_all, mixnodes_basic_active, mixnodes_basic_all, nodes_basic_active,
|
||||
nodes_basic_all,
|
||||
nodes_basic_all, nodes_basic_batch,
|
||||
};
|
||||
use crate::support::http::helpers::PaginationRequest;
|
||||
use crate::support::http::state::AppState;
|
||||
@@ -52,6 +52,7 @@ pub(crate) fn nym_node_routes_unstable() -> Router<AppState> {
|
||||
"/skimmed",
|
||||
Router::new()
|
||||
.route("/", get(nodes_basic_all))
|
||||
.route("/batch", post(nodes_basic_batch))
|
||||
.route("/active", get(nodes_basic_active))
|
||||
.nest(
|
||||
"/mixnodes",
|
||||
|
||||
@@ -25,6 +25,7 @@ use tracing::trace;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub type PaginatedSkimmedNodes = AxumResult<Json<PaginatedCachedNodesResponse<SkimmedNode>>>;
|
||||
type SkimmedNodes = AxumResult<Json<CachedNodesResponse<SkimmedNode>>>;
|
||||
|
||||
/// Given all relevant caches, build part of response for JUST Nym Nodes
|
||||
fn build_nym_nodes_response<'a, NI>(
|
||||
@@ -196,7 +197,7 @@ where
|
||||
pub(super) async fn deprecated_gateways_basic(
|
||||
state: State<AppState>,
|
||||
query_params: Query<NodesParams>,
|
||||
) -> AxumResult<Json<CachedNodesResponse<SkimmedNode>>> {
|
||||
) -> SkimmedNodes {
|
||||
// 1. call '/v1/unstable/skimmed/entry-gateways/all'
|
||||
let all_gateways = entry_gateways_basic_all(state, query_params).await?;
|
||||
|
||||
@@ -223,7 +224,7 @@ pub(super) async fn deprecated_gateways_basic(
|
||||
pub(super) async fn deprecated_mixnodes_basic(
|
||||
state: State<AppState>,
|
||||
query_params: Query<NodesParams>,
|
||||
) -> AxumResult<Json<CachedNodesResponse<SkimmedNode>>> {
|
||||
) -> SkimmedNodes {
|
||||
// 1. call '/v1/unstable/nym-nodes/skimmed/mixnodes/active'
|
||||
let active_mixnodes = mixnodes_basic_active(state, query_params).await?;
|
||||
|
||||
@@ -239,7 +240,7 @@ async fn nodes_basic(
|
||||
state: State<AppState>,
|
||||
Query(_query_params): Query<NodesParams>,
|
||||
active_only: bool,
|
||||
) -> PaginatedSkimmedNodes {
|
||||
) -> AxumResult<CachedNodesResponse<SkimmedNode>> {
|
||||
// unfortunately we have to build the response semi-manually here as we need to add two sources of legacy nodes
|
||||
|
||||
// 1. grab all relevant described nym-nodes
|
||||
@@ -281,10 +282,10 @@ async fn nodes_basic(
|
||||
legacy_gateways.timestamp(),
|
||||
]);
|
||||
|
||||
Ok(Json(PaginatedCachedNodesResponse::new_full(
|
||||
Ok(CachedNodesResponse {
|
||||
refreshed_at,
|
||||
nodes,
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // not dead, used in OpenAPI docs
|
||||
@@ -326,7 +327,47 @@ pub(super) async fn nodes_basic_all(
|
||||
};
|
||||
}
|
||||
|
||||
nodes_basic(state, Query(query_params.into()), false).await
|
||||
let nodes = nodes_basic(state, Query(query_params.into()), false).await?;
|
||||
// We are never using pagination (always one page) anyways so just build it here.
|
||||
Ok(Json(PaginatedCachedNodesResponse::new_full(
|
||||
nodes.refreshed_at,
|
||||
nodes.nodes,
|
||||
)))
|
||||
}
|
||||
|
||||
/// Post request handler taking a json array of NodeId (u32) values and returning descriptors for
|
||||
/// the provided NodeId values. A successful response will contain descriptors for all nodes
|
||||
/// associated with those node IDs available in the current full topology.
|
||||
///
|
||||
/// If a provided node ID is not present in the current topology there will be no descriptor for
|
||||
/// that node in the response.
|
||||
///
|
||||
/// If no node IDs are provided the response will contain no descriptors.
|
||||
#[utoipa::path(
|
||||
tag = "Unstable Nym Nodes batch by Node ID",
|
||||
get,
|
||||
params(NodesParamsWithRole),
|
||||
path = "batch",
|
||||
context_path = "/v1/unstable/nym-nodes/skimmed",
|
||||
responses(
|
||||
(status = 200, body = PaginatedCachedNodesResponseSchema)
|
||||
)
|
||||
)]
|
||||
pub(super) async fn nodes_basic_batch(
|
||||
state: State<AppState>,
|
||||
Query(query_params): Query<NodesParamsWithRole>,
|
||||
Json(ids): Json<Vec<u32>>,
|
||||
) -> SkimmedNodes {
|
||||
let nodes = nodes_basic(state, Query(query_params.into()), false).await?;
|
||||
let requested_nodes = nodes
|
||||
.nodes
|
||||
.into_iter()
|
||||
.filter(|node| ids.contains(&node.node_id))
|
||||
.collect();
|
||||
Ok(Json(CachedNodesResponse {
|
||||
nodes: requested_nodes,
|
||||
refreshed_at: nodes.refreshed_at,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Return Nym Nodes and optionally legacy mixnodes/gateways (if `no-legacy` flag is not used)
|
||||
@@ -359,7 +400,12 @@ pub(super) async fn nodes_basic_active(
|
||||
};
|
||||
}
|
||||
|
||||
nodes_basic(state, Query(query_params.into()), true).await
|
||||
let nodes = nodes_basic(state, Query(query_params.into()), true).await?;
|
||||
// We are never using pagination (always one page) anyways so just build it here.
|
||||
Ok(Json(PaginatedCachedNodesResponse::new_full(
|
||||
nodes.refreshed_at,
|
||||
nodes.nodes,
|
||||
)))
|
||||
}
|
||||
|
||||
async fn mixnodes_basic(
|
||||
|
||||
@@ -747,7 +747,7 @@ impl StorageManager {
|
||||
&self,
|
||||
db_mixnode_id: i64,
|
||||
since: i64,
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
let count = sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count FROM
|
||||
@@ -786,7 +786,7 @@ impl StorageManager {
|
||||
&self,
|
||||
gateway_id: i64,
|
||||
since: i64,
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
let count = sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count FROM
|
||||
@@ -824,7 +824,7 @@ impl StorageManager {
|
||||
)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|result| result.exists == 1)
|
||||
.map(|result| result.exists == Some(1))
|
||||
}
|
||||
|
||||
/// Creates new entry for mixnode historical uptime
|
||||
@@ -966,7 +966,7 @@ impl StorageManager {
|
||||
&self,
|
||||
since: i64,
|
||||
until: i64,
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
) -> Result<i32, sqlx::Error> {
|
||||
let count = sqlx::query!(
|
||||
"SELECT COUNT(*) as count FROM monitor_run WHERE timestamp > ? AND timestamp < ?",
|
||||
since,
|
||||
@@ -1227,7 +1227,7 @@ impl StorageManager {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn get_mixnode_statuses_count(&self, db_id: i64) -> Result<i64, sqlx::Error> {
|
||||
pub(super) async fn get_mixnode_statuses_count(&self, db_id: i64) -> Result<i32, sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count
|
||||
@@ -1279,7 +1279,7 @@ impl StorageManager {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(super) async fn get_gateway_statuses_count(&self, db_id: i64) -> Result<i64, sqlx::Error> {
|
||||
pub(super) async fn get_gateway_statuses_count(&self, db_id: i64) -> Result<i32, sqlx::Error> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
SELECT COUNT(*) as count
|
||||
@@ -1341,7 +1341,7 @@ pub(crate) mod v3_migration {
|
||||
sqlx::query!("SELECT EXISTS (SELECT 1 FROM v3_migration_info) AS 'exists'",)
|
||||
.fetch_one(&self.connection_pool)
|
||||
.await
|
||||
.map(|result| result.exists == 1)
|
||||
.map(|result| result.exists == Some(1))
|
||||
}
|
||||
|
||||
pub(crate) async fn set_v3_migration_completion(&self) -> Result<(), sqlx::Error> {
|
||||
|
||||
@@ -679,7 +679,7 @@ impl NymApiStorage {
|
||||
&self,
|
||||
mix_id: NodeId,
|
||||
since: Option<i64>,
|
||||
) -> Result<i64, NymApiStorageError> {
|
||||
) -> Result<i32, NymApiStorageError> {
|
||||
let db_id = self.manager.get_mixnode_database_id(mix_id).await?;
|
||||
|
||||
if let Some(node_id) = db_id {
|
||||
@@ -707,7 +707,7 @@ impl NymApiStorage {
|
||||
&self,
|
||||
identity: &str,
|
||||
since: Option<i64>,
|
||||
) -> Result<i64, NymApiStorageError> {
|
||||
) -> Result<i32, NymApiStorageError> {
|
||||
let node_id = self
|
||||
.manager
|
||||
.get_gateway_database_id_by_identity(identity)
|
||||
|
||||
@@ -10,7 +10,7 @@ use nym_network_defaults::setup_env;
|
||||
use nym_network_defaults::var_names::NYM_API;
|
||||
use nym_sdk::mixnet::{self, MixnetClient};
|
||||
use nym_sphinx::chunking::monitoring;
|
||||
use nym_topology::{HardcodedTopologyProvider, NymTopology};
|
||||
use nym_topology::{providers::HardcodedTopologyProvider, NymTopology};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
set -eu
|
||||
export ENVIRONMENT=${ENVIRONMENT:-"mainnet"}
|
||||
|
||||
probe_git_ref="nym-vpn-core-v1.4.0"
|
||||
probe_git_ref="nym-vpn-core-v1.3.2"
|
||||
|
||||
crate_root=$(dirname $(realpath "$0"))
|
||||
monorepo_root=$(realpath "${crate_root}/../..")
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_daily_stats (\n mix_id, date_utc,\n total_stake, packets_received,\n packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = mixnode_daily_stats.packets_received + excluded.packets_received,\n packets_sent = mixnode_daily_stats.packets_sent + excluded.packets_sent,\n packets_dropped = mixnode_daily_stats.packets_dropped + excluded.packets_dropped\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "01ee4a30bc3104712e5bc371a45d614a89d88adf02358800433e06100c13c548"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_description (\n mix_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (mix_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "06065394c157927e4002ddd5c7c1af626ae15728d615f539470cd7c189312385"
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n date_utc as \"date_utc!\",\n SUM(total_stake) as \"total_stake!: i64\",\n SUM(packets_received) as \"total_packets_received!: i64\",\n SUM(packets_sent) as \"total_packets_sent!: i64\",\n SUM(packets_dropped) as \"total_packets_dropped!: i64\"\n FROM (\n SELECT\n date_utc,\n n.total_stake,\n n.packets_received,\n n.packets_sent,\n n.packets_dropped\n FROM nym_node_daily_mixing_stats n\n UNION ALL\n SELECT\n m.date_utc,\n m.total_stake,\n m.packets_received,\n m.packets_sent,\n m.packets_dropped\n FROM mixnode_daily_stats m\n LEFT JOIN nym_node_daily_mixing_stats ON m.mix_id = nym_node_daily_mixing_stats.node_id\n WHERE nym_node_daily_mixing_stats.node_id IS NULL\n )\n GROUP BY date_utc\n ORDER BY date_utc ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "date_utc!",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "total_stake!: i64",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_received!: i64",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_sent!: i64",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_dropped!: i64",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "124d45b9604439584650f401607c46bdbd162c7c689f74fe9ddfdfd48f5ddc07"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE mixnodes\n SET bonded = ?, last_updated_utc = ?\n WHERE id = ?;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "18abc8fde56cf86baed7b4afa38f2c63cdf90f2f3b6d81afb9000bb0968dcaea"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_packet_stats_raw (\n mix_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "21e44766729777756f6eb04bf3b81df3e591008a1e3fd664ed83ca86ac51bd8c"
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n node_id,\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n bond_info IS NOT NULL\n AND\n self_described IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "node_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "bond_info: serde_json::Value",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "227539374e7473f6f9642289c5b5d1bcd636315ab23537cb5f6d2f82a2bcb7bf"
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT gateway_identity_key\n FROM gateways\n WHERE bonded = true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "gateway_identity_key",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "25300e435780101fa207c8e26ef2f49ba5db84d63e89440bb494e8327fe73686"
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n node_id,\n ed25519_identity_pubkey,\n total_stake,\n ip_addresses as \"ip_addresses!: serde_json::Value\",\n mix_port,\n x25519_sphinx_pubkey,\n node_role as \"node_role: serde_json::Value\",\n supported_roles as \"supported_roles: serde_json::Value\",\n entry as \"entry: serde_json::Value\",\n performance,\n self_described as \"self_described: serde_json::Value\",\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n self_described IS NOT NULL\n AND\n bond_info IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "node_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "ed25519_identity_pubkey",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "total_stake",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "ip_addresses!: serde_json::Value",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "mix_port",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "x25519_sphinx_pubkey",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "node_role: serde_json::Value",
|
||||
"ordinal": 6,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "supported_roles: serde_json::Value",
|
||||
"ordinal": 7,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "entry: serde_json::Value",
|
||||
"ordinal": 8,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "performance",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "self_described: serde_json::Value",
|
||||
"ordinal": 10,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "bond_info: serde_json::Value",
|
||||
"ordinal": 11,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "283f49a65c7d70bf271702ff6a5c7ad6e68c81932d295ff18ed198c54706a57c"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_description (\n mix_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (mix_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3825020ab0ecbffe83270c57ec74fb7987a6807d3381a6068c79b127a668b190"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO mixnodes\n (mix_id, identity_key, bonded, total_stake,\n host, http_api_port, full_details,\n self_described, last_updated_utc, is_dp_delegatee)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id) DO UPDATE SET\n bonded=excluded.bonded,\n total_stake=excluded.total_stake, host=excluded.host,\n http_api_port=excluded.http_api_port,\n full_details=excluded.full_details,self_described=excluded.self_described,\n last_updated_utc=excluded.last_updated_utc,\n is_dp_delegatee = excluded.is_dp_delegatee;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 10
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3cd5cb4bfca4243925da4ddbccd811e842090e98982e1032670df77961870b32"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE gateways\n SET bonded = ?, last_updated_utc = ?\n WHERE id = ?;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 3
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3d3a1fa429e3090741c6b6a8e82e692afc04b51e8782bcbf59f1eb4116112536"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"gateway_identity_key!\",\n self_described as \"self_described?\",\n explorer_pretty_bond as \"explorer_pretty_bond?\"\n FROM gateways\n WHERE gateway_identity_key = ?\n AND bonded = true\n ORDER BY gateway_identity_key\n LIMIT 1",
|
||||
"query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"gateway_identity_key!\",\n self_described as \"self_described?\",\n explorer_pretty_bond as \"explorer_pretty_bond?\"\n FROM gateways\n WHERE gateway_identity_key = ?\n ORDER BY gateway_identity_key\n LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -34,5 +34,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "3e7e987780937873cdb393b157d7708c9f01047b0689eb0d4f7a973b328c609d"
|
||||
"hash": "3d5fc502f976f5081f01352856b8632c29c81bfafb043bb8744129cf9e0266ad"
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n total_stake\n FROM mixnodes\n WHERE mix_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "total_stake",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "3fc2baabf194b147b20be2a49401cc0c100a1d7a7c347393adde2410fa6f4dfe"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n id as \"id!\",\n gateway_identity_key as \"identity_key!\",\n bonded as \"bonded: bool\"\n FROM gateways\n WHERE bonded = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "identity_key!",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "bonded: bool",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "4b61a4bc32333c92a8f5ad4ad0017b40dc01845f554b5479f37855d89b309e6f"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO nym_node_daily_mixing_stats (\n node_id, date_utc,\n total_stake, packets_received,\n packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(node_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = nym_node_daily_mixing_stats.packets_received + excluded.packets_received,\n packets_sent = nym_node_daily_mixing_stats.packets_sent + excluded.packets_sent,\n packets_dropped = nym_node_daily_mixing_stats.packets_dropped + excluded.packets_dropped\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "5912ea335a957d217f5e2b3a63a25b31715c2098310fe7a9db688bc2fd36aad4"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO nym_nodes\n (node_id, ed25519_identity_pubkey,\n total_stake,\n ip_addresses, mix_port,\n x25519_sphinx_pubkey, node_role,\n supported_roles, entry,\n self_described,\n bond_info,\n performance, last_updated_utc\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(node_id) DO UPDATE SET\n ed25519_identity_pubkey=excluded.ed25519_identity_pubkey,\n ip_addresses=excluded.ip_addresses,\n mix_port=excluded.mix_port,\n x25519_sphinx_pubkey=excluded.x25519_sphinx_pubkey,\n node_role=excluded.node_role,\n supported_roles=excluded.supported_roles,\n entry=excluded.entry,\n self_described=excluded.self_described,\n bond_info=excluded.bond_info,\n performance=excluded.performance,\n last_updated_utc=excluded.last_updated_utc\n ;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 13
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "664e059ac2c58e1115fe214376a6b326b31c93298f20019772cce2e277a194f8"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO mixnodes\n (mix_id, identity_key, bonded, total_stake,\n host, http_api_port, blacklisted, full_details,\n self_described, last_updated_utc, is_dp_delegatee)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id) DO UPDATE SET\n bonded=excluded.bonded,\n total_stake=excluded.total_stake, host=excluded.host,\n http_api_port=excluded.http_api_port,blacklisted=excluded.blacklisted,\n full_details=excluded.full_details,self_described=excluded.self_described,\n last_updated_utc=excluded.last_updated_utc,\n is_dp_delegatee = excluded.is_dp_delegatee;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 11
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "6eb1a682cf13205cf701590021cdf795147ac3724e89df5b2f24f7215d87dce1"
|
||||
}
|
||||
+22
-16
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n gw.gateway_identity_key as \"gateway_identity_key!\",\n gw.bonded as \"bonded: bool\",\n gw.performance as \"performance!\",\n gw.self_described as \"self_described?\",\n gw.explorer_pretty_bond as \"explorer_pretty_bond?\",\n gw.last_probe_result as \"last_probe_result?\",\n gw.last_probe_log as \"last_probe_log?\",\n gw.last_testrun_utc as \"last_testrun_utc?\",\n gw.last_updated_utc as \"last_updated_utc!\",\n COALESCE(gd.moniker, \"NA\") as \"moniker!\",\n COALESCE(gd.website, \"NA\") as \"website!\",\n COALESCE(gd.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(gd.details, \"NA\") as \"details!\"\n FROM gateways gw\n LEFT JOIN gateway_description gd\n ON gw.gateway_identity_key = gd.gateway_identity_key\n ORDER BY gw.gateway_identity_key",
|
||||
"query": "SELECT\n gw.gateway_identity_key as \"gateway_identity_key!\",\n gw.bonded as \"bonded: bool\",\n gw.blacklisted as \"blacklisted: bool\",\n gw.performance as \"performance!\",\n gw.self_described as \"self_described?\",\n gw.explorer_pretty_bond as \"explorer_pretty_bond?\",\n gw.last_probe_result as \"last_probe_result?\",\n gw.last_probe_log as \"last_probe_log?\",\n gw.last_testrun_utc as \"last_testrun_utc?\",\n gw.last_updated_utc as \"last_updated_utc!\",\n COALESCE(gd.moniker, \"NA\") as \"moniker!\",\n COALESCE(gd.website, \"NA\") as \"website!\",\n COALESCE(gd.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(gd.details, \"NA\") as \"details!\"\n FROM gateways gw\n LEFT JOIN gateway_description gd\n ON gw.gateway_identity_key = gd.gateway_identity_key\n ORDER BY gw.gateway_identity_key",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -14,59 +14,64 @@
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "performance!",
|
||||
"name": "blacklisted: bool",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "self_described?",
|
||||
"name": "performance!",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "explorer_pretty_bond?",
|
||||
"name": "self_described?",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_probe_result?",
|
||||
"name": "explorer_pretty_bond?",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_probe_log?",
|
||||
"name": "last_probe_result?",
|
||||
"ordinal": 6,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_testrun_utc?",
|
||||
"name": "last_probe_log?",
|
||||
"ordinal": 7,
|
||||
"type_info": "Int64"
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_updated_utc!",
|
||||
"name": "last_testrun_utc?",
|
||||
"ordinal": 8,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "moniker!",
|
||||
"name": "last_updated_utc!",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "website!",
|
||||
"name": "moniker!",
|
||||
"ordinal": 10,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "security_contact!",
|
||||
"name": "website!",
|
||||
"ordinal": 11,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "details!",
|
||||
"name": "security_contact!",
|
||||
"ordinal": 12,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "details!",
|
||||
"ordinal": 13,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -77,6 +82,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
@@ -88,5 +94,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "3eb1d8491bda3c1d6e071b6eb364b9a979f4bdb11ea81b2d0f022555bab51ecb"
|
||||
"hash": "71a455c705f9c25d3843ff2fb8629d1320a5eb10797cdb5a435455d22c6aeac1"
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n node_id,\n self_described as \"self_described: serde_json::Value\"\n FROM\n nym_nodes\n WHERE\n self_described IS NOT NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "node_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "self_described: serde_json::Value",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "7526390c3d17622564067f153867295a279179315650f6fb363d5f3177bf70e3"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT packets_received, packets_sent, packets_dropped\n FROM mixnode_packet_stats_raw\n WHERE mix_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "packets_received",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_sent",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_dropped",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "7b3e44e1dea0568d331017216e5375684086bbeb80f3b251adc761bae0dafe92"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_packet_stats_raw (\n mix_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "84e784b7ceb479f37fa312dd9a8bb0b3debc04cd251cdfaa438bce7aca7c5992"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE gateways\n SET blacklisted = true\n WHERE gateway_identity_key = ?;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8571faad2f66e08f24acfbfe036d17ca6eb090df7f6d52ef89c5d51564f8b45c"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT mix_id as node_id, host, http_api_port\n FROM mixnodes\n WHERE bonded = true\n ",
|
||||
"query": "\n SELECT mix_id as node_id, host, http_api_port \n FROM mixnodes \n WHERE bonded = true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -28,5 +28,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "021c6c65d1ed806d8430bef7883906b42a7e4b280c8efb32db15d7c6a51d7a27"
|
||||
"hash": "8c6c1c67df2d06da74825872f448d30505801b56506668499f9da718f1d6b8f8"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO nym_node_descriptions (\n node_id, moniker, website, security_contact, details, last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (node_id) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9104e50524ad5a103bd199a0531d73b74876e9aecda2117227e2e180258d91a1"
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n node_id,\n ed25519_identity_pubkey,\n total_stake,\n ip_addresses as \"ip_addresses!: serde_json::Value\",\n mix_port,\n x25519_sphinx_pubkey,\n node_role as \"node_role: serde_json::Value\",\n supported_roles as \"supported_roles: serde_json::Value\",\n entry as \"entry: serde_json::Value\",\n performance,\n self_described as \"self_described: serde_json::Value\",\n bond_info as \"bond_info: serde_json::Value\"\n FROM\n nym_nodes\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "node_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "ed25519_identity_pubkey",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "total_stake",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "ip_addresses!: serde_json::Value",
|
||||
"ordinal": 3,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "mix_port",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "x25519_sphinx_pubkey",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "node_role: serde_json::Value",
|
||||
"ordinal": 6,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "supported_roles: serde_json::Value",
|
||||
"ordinal": 7,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "entry: serde_json::Value",
|
||||
"ordinal": 8,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "performance",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "self_described: serde_json::Value",
|
||||
"ordinal": 10,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "bond_info: serde_json::Value",
|
||||
"ordinal": 11,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "9334f0c91252fcd7ec72558a271222615bb282e5334665700709ae475a5daea2"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n total_stake\n FROM nym_nodes\n WHERE node_id = ?\n ",
|
||||
"query": "\n SELECT\n total_stake\n FROM mixnodes\n WHERE mix_id = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -16,5 +16,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "d2e07d44594ca5b44a6100482ff432c39d761f2a0ac1d6515cf73416f2eb6c61"
|
||||
"hash": "969acbff4b128d3a3dc998bb5db1a4c8b4c106767e0276435dc23fcfd6acfe4f"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO gateways\n (gateway_identity_key, bonded,\n self_described, explorer_pretty_bond,\n last_updated_utc, performance)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(gateway_identity_key) DO UPDATE SET\n bonded=excluded.bonded,\n self_described=excluded.self_described,\n explorer_pretty_bond=excluded.explorer_pretty_bond,\n last_updated_utc=excluded.last_updated_utc,\n performance = excluded.performance;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9796d354ae075eab4cbd3438839c39da94025494395ec7b093aefef696f2d0c5"
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n COALESCE(packets_received, 0) as packets_received,\n COALESCE(packets_sent, 0) as packets_sent,\n COALESCE(packets_dropped, 0) as packets_dropped\n FROM nym_nodes_packet_stats_raw\n WHERE node_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "packets_received",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_sent",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_dropped",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "97f4b340bb0f6c9c78d77b24d4f9d3d13ab61cbaac6f8c3cfc06c95e0f13252f"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO mixnode_daily_stats (\n mix_id, date_utc, total_stake, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(mix_id, date_utc) DO UPDATE SET\n total_stake = excluded.total_stake,\n packets_received = mixnode_daily_stats.packets_received + excluded.packets_received,\n packets_sent = mixnode_daily_stats.packets_sent + excluded.packets_sent,\n packets_dropped = mixnode_daily_stats.packets_dropped + excluded.packets_dropped\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a14d5767512bc88ac47b667c47a773b548ccb20bc539839766080d8455439339"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "DELETE FROM nym_nodes\n WHERE node_id = ?",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b41fc93f5dc7a397e8898776bf1335d9c26fe1447309f46623bcfee4537991b1"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE\n mixnodes\n SET\n bonded = false\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c42917c9542c1d720d92035863064741aefc9f7a7d1630f6b863ebd8174b6684"
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n date_utc as \"date_utc!\",\n packets_received as \"total_packets_received!: i64\",\n packets_sent as \"total_packets_sent!: i64\",\n packets_dropped as \"total_packets_dropped!: i64\",\n total_stake as \"total_stake!: i64\"\n FROM (\n SELECT\n date_utc,\n SUM(packets_received) as packets_received,\n SUM(packets_sent) as packets_sent,\n SUM(packets_dropped) as packets_dropped,\n SUM(total_stake) as total_stake\n FROM mixnode_daily_stats\n GROUP BY date_utc\n ORDER BY date_utc DESC\n LIMIT 30\n )\n GROUP BY date_utc\n ORDER BY date_utc\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "date_utc!",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_received!: i64",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_sent!: i64",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "total_packets_dropped!: i64",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "total_stake!: i64",
|
||||
"ordinal": 4,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c5e3cd7284b334df5aa979b1627ea1f6dc2aed00cedde25f2be3567e47064351"
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n id as \"id!\",\n identity_key as \"identity_key!\",\n bonded as \"bonded: bool\"\n FROM mixnodes\n WHERE bonded = ?",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "id!",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "identity_key!",
|
||||
"ordinal": 1,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "bonded: bool",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c7ba2621becb9ac4b5dee0ce303dadfcf19095935867a51cbd5b8362d1505fcc"
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT mix_id\n FROM mixnodes\n WHERE bonded = true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "mix_id",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c910788edefe64bbb34379702bcbde9ec6159c9fa03b13652e1f620dcd92125e"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "INSERT INTO gateways\n (gateway_identity_key, bonded, blacklisted,\n self_described, explorer_pretty_bond,\n last_updated_utc, performance)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(gateway_identity_key) DO UPDATE SET\n bonded=excluded.bonded,\n blacklisted=excluded.blacklisted,\n self_described=excluded.self_described,\n explorer_pretty_bond=excluded.explorer_pretty_bond,\n last_updated_utc=excluded.last_updated_utc,\n performance = excluded.performance;",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 7
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "d8ea93e781666e6267902170709ee2aa37f6163525bbdce1a4cebef4a285f8d9"
|
||||
}
|
||||
+21
-15
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n mn.mix_id as \"mix_id!\",\n mn.bonded as \"bonded: bool\",\n mn.is_dp_delegatee as \"is_dp_delegatee: bool\",\n mn.total_stake as \"total_stake!\",\n mn.full_details as \"full_details!\",\n mn.self_described as \"self_described\",\n mn.last_updated_utc as \"last_updated_utc!\",\n COALESCE(md.moniker, \"NA\") as \"moniker!\",\n COALESCE(md.website, \"NA\") as \"website!\",\n COALESCE(md.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(md.details, \"NA\") as \"details!\"\n FROM mixnodes mn\n LEFT JOIN mixnode_description md ON mn.mix_id = md.mix_id\n ORDER BY mn.mix_id",
|
||||
"query": "SELECT\n mn.mix_id as \"mix_id!\",\n mn.bonded as \"bonded: bool\",\n mn.blacklisted as \"blacklisted: bool\",\n mn.is_dp_delegatee as \"is_dp_delegatee: bool\",\n mn.total_stake as \"total_stake!\",\n mn.full_details as \"full_details!\",\n mn.self_described as \"self_described\",\n mn.last_updated_utc as \"last_updated_utc!\",\n COALESCE(md.moniker, \"NA\") as \"moniker!\",\n COALESCE(md.website, \"NA\") as \"website!\",\n COALESCE(md.security_contact, \"NA\") as \"security_contact!\",\n COALESCE(md.details, \"NA\") as \"details!\"\n FROM mixnodes mn\n LEFT JOIN mixnode_description md ON mn.mix_id = md.mix_id\n ORDER BY mn.mix_id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -14,49 +14,54 @@
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "is_dp_delegatee: bool",
|
||||
"name": "blacklisted: bool",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "total_stake!",
|
||||
"name": "is_dp_delegatee: bool",
|
||||
"ordinal": 3,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "full_details!",
|
||||
"name": "total_stake!",
|
||||
"ordinal": 4,
|
||||
"type_info": "Text"
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "self_described",
|
||||
"name": "full_details!",
|
||||
"ordinal": 5,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_updated_utc!",
|
||||
"name": "self_described",
|
||||
"ordinal": 6,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "last_updated_utc!",
|
||||
"ordinal": 7,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "moniker!",
|
||||
"ordinal": 7,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "website!",
|
||||
"ordinal": 8,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "security_contact!",
|
||||
"name": "website!",
|
||||
"ordinal": 9,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "details!",
|
||||
"name": "security_contact!",
|
||||
"ordinal": 10,
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"name": "details!",
|
||||
"ordinal": 11,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -67,6 +72,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
@@ -76,5 +82,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f75af377da33db1455c6e0f612e0fa9583888f343b8b59faf37fc6799b244379"
|
||||
"hash": "f0a4316081d1be9444a87b95d933d31cb4bcc4071d31d8d2f7755e2d2c2e3e35"
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n SELECT\n COALESCE(packets_received, 0) as packets_received,\n COALESCE(packets_sent, 0) as packets_sent,\n COALESCE(packets_dropped, 0) as packets_dropped\n FROM mixnode_packet_stats_raw\n WHERE mix_id = ?\n ORDER BY timestamp_utc DESC\n LIMIT 1 OFFSET 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "packets_received",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_sent",
|
||||
"ordinal": 1,
|
||||
"type_info": "Int64"
|
||||
},
|
||||
{
|
||||
"name": "packets_dropped",
|
||||
"ordinal": 2,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f1f47a4490c3e1330885ef3cf3cda054f2cf760520a46a94db22a02a9cb53dba"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO gateway_description (\n gateway_identity_key,\n moniker,\n website,\n security_contact,\n details,\n last_updated_utc\n ) VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (gateway_identity_key) DO UPDATE SET\n moniker = excluded.moniker,\n website = excluded.website,\n security_contact = excluded.security_contact,\n details = excluded.details,\n last_updated_utc = excluded.last_updated_utc\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f2a7e7229b414a6283685558d1d0731d21b1a92eb39481cf342b87c3b5b0f759"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "UPDATE\n gateways\n SET\n bonded = false\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f7e3fa31d68c028bf39cc95389f29f8758ec922dd2e7ea064a1e537e580c9ee5"
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "SELECT\n node_id as \"node_id!: i64\"\n FROM\n nym_nodes\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "node_id!: i64",
|
||||
"ordinal": 0,
|
||||
"type_info": "Int64"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "fb2fcd26974ce4c3f5055fa2ca8c266223814c19ab2a5763a0575274d684d02e"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "SQLite",
|
||||
"query": "\n INSERT INTO nym_nodes_packet_stats_raw (\n node_id, timestamp_utc, packets_received, packets_sent, packets_dropped\n ) VALUES (?, ?, ?, ?, ?)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 5
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "fcb1698d9e0e3a14524c92e7c99a811588c2bbc50d4975487a0464321a1b18c9"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user