merge 1.1.5

This commit is contained in:
Simon Wicky
2023-01-11 15:17:15 +00:00
408 changed files with 4427 additions and 2475 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ GEOIPUPDATE_LICENSE_KEY=xxx
# List of space-separated database edition IDs. Edition IDs may
# consist of letters, digits, and dashes. For example, GeoIP2-City
# would download the GeoIP2 City database (GeoIP2-City).
GEOIPUPDATE_EDITION_IDS=GeoLite2-Country
GEOIPUPDATE_EDITION_IDS=GeoLite2-City
# The number of hours between geoipupdate runs. If this is not set
# or is set to 0, geoipupdate will run once and exit.
GEOIPUPDATE_FREQUENCY=72
+48 -32
View File
@@ -4,13 +4,35 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
### Added
### Changed
## [v1.1.5] (2023-01-10)
### Added
- socks5: send status message for service ready, and network-requester error response in https://github.com/nymtech/nym/pull/2715
### Changed
- all-binaries: improved error logging in https://github.com/nymtech/nym/pull/2686
- native client: bring shutdown logic up to the same level as socks5-client in https://github.com/nymtech/nym/pull/2695
- nym-api, coconut-dkg contract: automatic, time-based dkg epoch state advancement in https://github.com/nymtech/nym/pull/2670
- DKG resharing unit test by @neacsu in https://github.com/nymtech/nym/pull/2668
- Renaming validator-api to nym-api by @futurechimp in https://github.com/nymtech/nym/pull/1863
- Modify wasm specific make targets by @neacsu in https://github.com/nymtech/nym/pull/2693
- client: create websocket handler builder by @octol in https://github.com/nymtech/nym/pull/2700
- Outfox and Lion by @durch in https://github.com/nymtech/nym/pull/2730
- Feature/multi surb transmission lanes by @jstuczyn in https://github.com/nymtech/nym/pull/2723
## [v1.1.4] (2022-12-20)
This release adds multiple Single Use Reply Blocks (SURBs) to allow arbitrarily-sized anonymized replies.
At the moment this is turned off by default, but available for use by application developers.
We will need to wait for network-requesters to upgrade to this new release, after which multi-SURB anonymization will become the default setting for the SOCKS proxy clients.
This release adds multiple Single Use Reply Blocks (SURBs) to allow arbitrarily-sized anonymized replies.
At the moment this is turned off by default, but available for use by application developers.
We will need to wait for network-requesters to upgrade to this new release, after which multi-SURB anonymization will become the default setting for the SOCKS proxy clients.
The release also include some additional work for distributed key generation in the Coconut signing authority nodes.
The release also include some additional work for distributed key generation in the Coconut signing authority nodes.
### Changed
@@ -33,7 +55,7 @@ The release also include some additional work for distributed key generation in
- network-requester: fix bug where websocket connection disconnect resulted in success error code
- clients: fix a few panics handling the gateway-client
- mixnode, gateway, validator-api: Use mainnet values as defaults for URLs and mixnet contract ([#1884])
- mixnode, gateway, validator-api: Use mainnet values as defaults for URLs and mixnet contract ([#1884])
- socks5: fixed bug where connections sometimes where closed too early
- clients: improve message logging when received message fails to get reconstructed ([#1803])
@@ -53,7 +75,7 @@ The release also include some additional work for distributed key generation in
- gateway: Renamed flag from `enabled/disabled_credentials_mode` to `only-coconut-credentials`
- "Family" feature for node families + layers
- Initial coconut functionality including credentials and distributed key generation
- Initial coconut functionality including credentials and distributed key generation
## [v1.1.1](https://github.com/nymtech/nym/tree/v1.1.1) (2022-11-29)
@@ -89,7 +111,6 @@ The release also include some additional work for distributed key generation in
[#1786]: https://github.com/nymtech/nym/pull/1786
[#1805]: https://github.com/nymtech/nym/pull/1805
## [v1.1.0](https://github.com/nymtech/nym/tree/v1.1.0) (2022-11-09)
### Added
@@ -116,7 +137,7 @@ The release also include some additional work for distributed key generation in
- gateway-client: will attempt to read now as many as 8 websocket messages at once, assuming they're already available on the socket ([#1669])
- moved `Percent` struct to `contracts-common`, change affects explorer-api
- socks5 client: graceful shutdown should fix error on disconnect in nym-connect ([#1591])
- validator-api: changed error serialization on `inclusion_probability`, `stake-saturation` and `reward-estimation` endpoints to provide more accurate information ([#1681])
- validator-api: changed error serialization on `inclusion_probability`, `stake-saturation` and `reward-estimation` endpoints to provide more accurate information ([#1681])
- validator-client: made `fee` argument optional for `execute` and `execute_multiple` ([#1541])
- wasm-client: fixed build errors on MacOS and changed example JS code to use mainnet ([#1585])
- validator-api: changes to internal SQL schema due to the mixnet contract revamp ([#1472])
@@ -144,7 +165,6 @@ The release also include some additional work for distributed key generation in
[#1724]: https://github.com/nymtech/nym/pull/1724
[#1725]: https://github.com/nymtech/nym/pull/1725
## [nym-binaries-1.0.2](https://github.com/nymtech/nym/tree/nym-binaries-1.0.2)
### Added
@@ -198,8 +218,7 @@ The release also include some additional work for distributed key generation in
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
- network explorer: tweak how active set probability is shown ([#1503])
- validator-api: rewarder set update fails without panicking on possible nymd queries ([#1520])
- network-requester, socks5 client (nym-connect): send and receive respectively a message error to be displayed about filter check failure ([#1576])
- network-requester, socks5 client (nym-connect): send and receive respectively a message error to be displayed about filter check failure ([#1576])
[#1249]: https://github.com/nymtech/nym/pull/1249
[#1256]: https://github.com/nymtech/nym/pull/1256
@@ -293,9 +312,9 @@ The release also include some additional work for distributed key generation in
- Bump minimist from 1.2.5 to 1.2.6 in /clients/tauri-client [\#1163](https://github.com/nymtech/nym/pull/1163) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump minimist from 1.2.5 to 1.2.6 in /clients/webassembly/js-example [\#1162](https://github.com/nymtech/nym/pull/1162) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump minimist from 1.2.5 to 1.2.6 in /clients/native/examples/js-examples/websocket [\#1160](https://github.com/nymtech/nym/pull/1160) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump minimist from 1.2.5 to 1.2.6 in /docker/typescript\_client/upload\_contract [\#1159](https://github.com/nymtech/nym/pull/1159) ([dependabot[bot]](https://github.com/apps/dependabot))
- Bump minimist from 1.2.5 to 1.2.6 in /docker/typescript_client/upload_contract [\#1159](https://github.com/nymtech/nym/pull/1159) ([dependabot[bot]](https://github.com/apps/dependabot))
- Feature/vesting full [\#1158](https://github.com/nymtech/nym/pull/1158) ([fmtabbara](https://github.com/fmtabbara))
- get\_current\_epoch tauri [\#1156](https://github.com/nymtech/nym/pull/1156) ([durch](https://github.com/durch))
- get_current_epoch tauri [\#1156](https://github.com/nymtech/nym/pull/1156) ([durch](https://github.com/durch))
- Cleanup [\#1155](https://github.com/nymtech/nym/pull/1155) ([durch](https://github.com/durch))
- Feature flag reward payments [\#1154](https://github.com/nymtech/nym/pull/1154) ([durch](https://github.com/durch))
- Add Query endpoints for calculating rewards [\#1152](https://github.com/nymtech/nym/pull/1152) ([durch](https://github.com/durch))
@@ -304,7 +323,7 @@ The release also include some additional work for distributed key generation in
- wallet: use Urls rather than Strings for validator urls [\#1148](https://github.com/nymtech/nym/pull/1148) ([octol](https://github.com/octol))
- Change accumulated reward to Option, migrate delegations [\#1147](https://github.com/nymtech/nym/pull/1147) ([durch](https://github.com/durch))
- wallet: fetch validators url remotely if available [\#1146](https://github.com/nymtech/nym/pull/1146) ([octol](https://github.com/octol))
- Fix delegated\_free calculation [\#1145](https://github.com/nymtech/nym/pull/1145) ([durch](https://github.com/durch))
- Fix delegated_free calculation [\#1145](https://github.com/nymtech/nym/pull/1145) ([durch](https://github.com/durch))
- Update Nym wallet dependencies to use `ts-packages` [\#1144](https://github.com/nymtech/nym/pull/1144) ([mmsinclair](https://github.com/mmsinclair))
- wallet: try validators one by one if available [\#1143](https://github.com/nymtech/nym/pull/1143) ([octol](https://github.com/octol))
- Update Network Explorer Packages and add mix node identity key copy [\#1142](https://github.com/nymtech/nym/pull/1142) ([mmsinclair](https://github.com/mmsinclair))
@@ -344,14 +363,13 @@ The release also include some additional work for distributed key generation in
- feature/pedersen-commitments [\#1048](https://github.com/nymtech/nym/pull/1048) ([danielementary](https://github.com/danielementary))
- Feature/reuse init owner [\#970](https://github.com/nymtech/nym/pull/970) ([neacsu](https://github.com/neacsu))
## [v0.12.1](https://github.com/nymtech/nym/tree/v0.12.1) (2021-12-23)
[Full Changelog](https://github.com/nymtech/nym/compare/v0.12.0...v0.12.1)
**Implemented enhancements:**
- Add version check to binaries [\#967](https://github.com/nymtech/nym/issues/967)
- Add version check to binaries [\#967](https://github.com/nymtech/nym/issues/967)
**Fixed bugs:**
@@ -381,7 +399,7 @@ The release also include some additional work for distributed key generation in
- Bugfix/remove mixnode bonding overwrite [\#917](https://github.com/nymtech/nym/pull/917) ([jstuczyn](https://github.com/jstuczyn))
- Fixes crash condition in validator API when calculating last day uptime [\#909](https://github.com/nymtech/nym/pull/909) ([jstuczyn](https://github.com/jstuczyn))
- Bugfix/monitor initial values wait [\#907](https://github.com/nymtech/nym/pull/907) ([jstuczyn](https://github.com/jstuczyn))
- Bug fix: Network Explorer: Add freegeoip API key and split out tasks for country distributions [\#806](https://github.com/nymtech/nym/pull/806) ([mmsinclair](https://github.com/mmsinclair))
- Bug fix: Network Explorer: Add freegeoip API key and split out tasks for country distributions [\#806](https://github.com/nymtech/nym/pull/806) ([mmsinclair](https://github.com/mmsinclair))
- Explorer API: port test now split out address resolution and add units tests [\#755](https://github.com/nymtech/nym/pull/755) ([mmsinclair](https://github.com/mmsinclair))
**Closed issues:**
@@ -396,7 +414,7 @@ The release also include some additional work for distributed key generation in
- help!!! [\#712](https://github.com/nymtech/nym/issues/712)
- UX feature request: show all delegated nodes in wallet [\#711](https://github.com/nymtech/nym/issues/711)
- UX feature request: add current balance on wallet pages [\#710](https://github.com/nymtech/nym/issues/710)
- got sign issue from bot [\#709](https://github.com/nymtech/nym/issues/709)
- got sign issue from bot [\#709](https://github.com/nymtech/nym/issues/709)
- As a wallet user, I would like to be able to log out of the wallet [\#706](https://github.com/nymtech/nym/issues/706)
- As a wallet user, I would like to have a "receive" page where I can see my own wallet address [\#705](https://github.com/nymtech/nym/issues/705)
- Update native client/socks client/mixnode/gateway `upgrade` command [\#689](https://github.com/nymtech/nym/issues/689)
@@ -406,7 +424,7 @@ The release also include some additional work for distributed key generation in
- nym-socks5-client crash after opening Keybase team "Browse all channels" [\#494](https://github.com/nymtech/nym/issues/494)
- Mixed Content problem [\#400](https://github.com/nymtech/nym/issues/400)
- Gateway disk quota [\#137](https://github.com/nymtech/nym/issues/137)
- Simplify message encapsulation with regards to topology [\#127](https://github.com/nymtech/nym/issues/127)
- Simplify message encapsulation with regards to topology [\#127](https://github.com/nymtech/nym/issues/127)
- Create constants for cli argument names [\#115](https://github.com/nymtech/nym/issues/115)
- Using Blake3 as a hash function [\#103](https://github.com/nymtech/nym/issues/103)
- Validator should decide which layer a node is in [\#86](https://github.com/nymtech/nym/issues/86)
@@ -462,10 +480,10 @@ The release also include some additional work for distributed key generation in
- Feature/pre cosmrs updates [\#935](https://github.com/nymtech/nym/pull/935) ([jstuczyn](https://github.com/jstuczyn))
- Feature/client on behalf [\#934](https://github.com/nymtech/nym/pull/934) ([neacsu](https://github.com/neacsu))
- Webpack wallet prod configuration [\#933](https://github.com/nymtech/nym/pull/933) ([tommyv1987](https://github.com/tommyv1987))
- Adding tx\_hash to wallet response [\#932](https://github.com/nymtech/nym/pull/932) ([futurechimp](https://github.com/futurechimp))
- Adding tx_hash to wallet response [\#932](https://github.com/nymtech/nym/pull/932) ([futurechimp](https://github.com/futurechimp))
- Release/1.0.0 pre1 [\#931](https://github.com/nymtech/nym/pull/931) ([durch](https://github.com/durch))
- Feature/identity verification [\#930](https://github.com/nymtech/nym/pull/930) ([jstuczyn](https://github.com/jstuczyn))
- Move cleaned up smart contracts to main code repo [\#929](https://github.com/nymtech/nym/pull/929) ([mfahampshire](https://github.com/mfahampshire))
- Move cleaned up smart contracts to main code repo [\#929](https://github.com/nymtech/nym/pull/929) ([mfahampshire](https://github.com/mfahampshire))
- Feature/mixnet contract further adjustments [\#928](https://github.com/nymtech/nym/pull/928) ([jstuczyn](https://github.com/jstuczyn))
- typo copy change for nodemap [\#926](https://github.com/nymtech/nym/pull/926) ([Aid19801](https://github.com/Aid19801))
- Feature/UI enhancements for Desktop Wallet [\#925](https://github.com/nymtech/nym/pull/925) ([fmtabbara](https://github.com/fmtabbara))
@@ -478,7 +496,7 @@ The release also include some additional work for distributed key generation in
- Feature/faucet page react [\#911](https://github.com/nymtech/nym/pull/911) ([fmtabbara](https://github.com/fmtabbara))
- Feature/mixnet contract refactor [\#910](https://github.com/nymtech/nym/pull/910) ([futurechimp](https://github.com/futurechimp))
- Update README.md [\#905](https://github.com/nymtech/nym/pull/905) ([tommyv1987](https://github.com/tommyv1987))
- BUG: Bond cell denom [\#904](https://github.com/nymtech/nym/pull/904) ([Aid19801](https://github.com/Aid19801))
- BUG: Bond cell denom [\#904](https://github.com/nymtech/nym/pull/904) ([Aid19801](https://github.com/Aid19801))
- 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))
@@ -496,7 +514,7 @@ The release also include some additional work for distributed key generation in
- Reverted gateway registration handshake to its 0.11.0 version [\#882](https://github.com/nymtech/nym/pull/882) ([jstuczyn](https://github.com/jstuczyn))
- Network Explorer [\#881](https://github.com/nymtech/nym/pull/881) ([mmsinclair](https://github.com/mmsinclair))
- Feature/rewarding interval updates [\#880](https://github.com/nymtech/nym/pull/880) ([jstuczyn](https://github.com/jstuczyn))
- Put client\_address and id in the correct order [\#875](https://github.com/nymtech/nym/pull/875) ([neacsu](https://github.com/neacsu))
- Put client_address and id in the correct order [\#875](https://github.com/nymtech/nym/pull/875) ([neacsu](https://github.com/neacsu))
- remove gateway selection on delegation and undelegation pages [\#873](https://github.com/nymtech/nym/pull/873) ([fmtabbara](https://github.com/fmtabbara))
- Set MSRV on all binaries to 1.56 [\#872](https://github.com/nymtech/nym/pull/872) ([jstuczyn](https://github.com/jstuczyn))
- add native window items \(copy/paste\) via tauri [\#871](https://github.com/nymtech/nym/pull/871) ([fmtabbara](https://github.com/fmtabbara))
@@ -512,7 +530,7 @@ The release also include some additional work for distributed key generation in
- Overflow checks in release [\#846](https://github.com/nymtech/nym/pull/846) ([jstuczyn](https://github.com/jstuczyn))
- fix delegate success overflow [\#842](https://github.com/nymtech/nym/pull/842) ([fmtabbara](https://github.com/fmtabbara))
- Feature NYM wallet webdriverio test [\#841](https://github.com/nymtech/nym/pull/841) ([tommyv1987](https://github.com/tommyv1987))
- Update nym\_wallet.yml [\#840](https://github.com/nymtech/nym/pull/840) ([tommyv1987](https://github.com/tommyv1987))
- Update nym_wallet.yml [\#840](https://github.com/nymtech/nym/pull/840) ([tommyv1987](https://github.com/tommyv1987))
- Feature/vouchers [\#837](https://github.com/nymtech/nym/pull/837) ([aniampio](https://github.com/aniampio))
- Apply readable ids to elements on Nym Wallet [\#836](https://github.com/nymtech/nym/pull/836) ([tommyv1987](https://github.com/tommyv1987))
- Feature/removal of monitor good nodes [\#833](https://github.com/nymtech/nym/pull/833) ([jstuczyn](https://github.com/jstuczyn))
@@ -536,8 +554,8 @@ The release also include some additional work for distributed key generation in
- Created getters for AccountData [\#787](https://github.com/nymtech/nym/pull/787) ([jstuczyn](https://github.com/jstuczyn))
- Feature/migrate hidden delegations [\#786](https://github.com/nymtech/nym/pull/786) ([neacsu](https://github.com/neacsu))
- Feature/persistent gateway storage [\#784](https://github.com/nymtech/nym/pull/784) ([jstuczyn](https://github.com/jstuczyn))
- Replaced unwrap\_or\_else with unwrap\_or\_default [\#780](https://github.com/nymtech/nym/pull/780) ([jstuczyn](https://github.com/jstuczyn))
- Add block\_height method to Delegation [\#778](https://github.com/nymtech/nym/pull/778) ([durch](https://github.com/durch))
- Replaced unwrap_or_else with unwrap_or_default [\#780](https://github.com/nymtech/nym/pull/780) ([jstuczyn](https://github.com/jstuczyn))
- Add block_height method to Delegation [\#778](https://github.com/nymtech/nym/pull/778) ([durch](https://github.com/durch))
- Make fee helpers public [\#777](https://github.com/nymtech/nym/pull/777) ([durch](https://github.com/durch))
- re-enable bonding [\#776](https://github.com/nymtech/nym/pull/776) ([fmtabbara](https://github.com/fmtabbara))
- Explorer-api: add API resource to show the delegations for each mix node [\#774](https://github.com/nymtech/nym/pull/774) ([mmsinclair](https://github.com/mmsinclair))
@@ -546,14 +564,14 @@ The release also include some additional work for distributed key generation in
- Adding deps for building the Tauri wallet under Ubuntu [\#770](https://github.com/nymtech/nym/pull/770) ([futurechimp](https://github.com/futurechimp))
- remove alert [\#767](https://github.com/nymtech/nym/pull/767) ([fmtabbara](https://github.com/fmtabbara))
- Feature/consumable bandwidth [\#766](https://github.com/nymtech/nym/pull/766) ([neacsu](https://github.com/neacsu))
- Update coconut-rs and use hash\_to\_scalar from there [\#765](https://github.com/nymtech/nym/pull/765) ([neacsu](https://github.com/neacsu))
- Update coconut-rs and use hash_to_scalar from there [\#765](https://github.com/nymtech/nym/pull/765) ([neacsu](https://github.com/neacsu))
- Feature/active sets [\#764](https://github.com/nymtech/nym/pull/764) ([jstuczyn](https://github.com/jstuczyn))
- add app alert banner [\#762](https://github.com/nymtech/nym/pull/762) ([fmtabbara](https://github.com/fmtabbara))
- Updated cosmos-sdk [\#761](https://github.com/nymtech/nym/pull/761) ([jstuczyn](https://github.com/jstuczyn))
- Feature/bond blockstamp [\#760](https://github.com/nymtech/nym/pull/760) ([neacsu](https://github.com/neacsu))
- Feature/revert migration code [\#759](https://github.com/nymtech/nym/pull/759) ([neacsu](https://github.com/neacsu))
- Bump next from 11.1.0 to 11.1.1 in /wallet-web [\#758](https://github.com/nymtech/nym/pull/758) ([dependabot[bot]](https://github.com/apps/dependabot))
- Add block\_height in the Delegation structure as well [\#757](https://github.com/nymtech/nym/pull/757) ([neacsu](https://github.com/neacsu))
- Add block_height in the Delegation structure as well [\#757](https://github.com/nymtech/nym/pull/757) ([neacsu](https://github.com/neacsu))
- Feature/add blockstamp [\#756](https://github.com/nymtech/nym/pull/756) ([neacsu](https://github.com/neacsu))
- NetworkMonitorBuilder - starting the monitor after rocket has launched [\#754](https://github.com/nymtech/nym/pull/754) ([jstuczyn](https://github.com/jstuczyn))
- Enabled validators api argument [\#753](https://github.com/nymtech/nym/pull/753) ([jstuczyn](https://github.com/jstuczyn))
@@ -565,7 +583,7 @@ The release also include some additional work for distributed key generation in
- Feature/more reliable uptime calculation [\#747](https://github.com/nymtech/nym/pull/747) ([jstuczyn](https://github.com/jstuczyn))
- Update template toml key [\#746](https://github.com/nymtech/nym/pull/746) ([neacsu](https://github.com/neacsu))
- Feature/cred after handshake [\#745](https://github.com/nymtech/nym/pull/745) ([neacsu](https://github.com/neacsu))
- Reinstate the POST method blind\_sign [\#744](https://github.com/nymtech/nym/pull/744) ([neacsu](https://github.com/neacsu))
- Reinstate the POST method blind_sign [\#744](https://github.com/nymtech/nym/pull/744) ([neacsu](https://github.com/neacsu))
- explorer-api: add pending field to port check response [\#742](https://github.com/nymtech/nym/pull/742) ([mmsinclair](https://github.com/mmsinclair))
- Feature/use delegation rates [\#741](https://github.com/nymtech/nym/pull/741) ([neacsu](https://github.com/neacsu))
- Feature/copy to clipboard [\#740](https://github.com/nymtech/nym/pull/740) ([fmtabbara](https://github.com/fmtabbara))
@@ -602,6 +620,4 @@ The release also include some additional work for distributed key generation in
- Hang coconut issuance off the validator-api [\#679](https://github.com/nymtech/nym/pull/679) ([durch](https://github.com/durch))
- Update hmac and blake3 [\#673](https://github.com/nymtech/nym/pull/673) ([durch](https://github.com/durch))
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
\* _This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)_
Generated
+224 -34
View File
@@ -23,6 +23,16 @@ dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "aead"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8"
dependencies = [
"crypto-common",
"generic-array 0.14.5",
]
[[package]]
name = "aes"
version = "0.7.5"
@@ -53,7 +63,7 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
dependencies = [
"aead",
"aead 0.4.3",
"aes 0.7.5",
"cipher 0.3.0",
"ctr 0.8.0",
@@ -81,6 +91,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "anes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -443,6 +459,12 @@ dependencies = [
"rustc_version 0.4.0",
]
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.0.73"
@@ -474,6 +496,30 @@ dependencies = [
"keystream",
]
[[package]]
name = "chacha20"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08"
dependencies = [
"cfg-if 1.0.0",
"cipher 0.4.3",
"cpufeatures",
]
[[package]]
name = "chacha20poly1305"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead 0.5.1",
"chacha20",
"cipher 0.4.3",
"poly1305",
"zeroize",
]
[[package]]
name = "chrono"
version = "0.4.19"
@@ -488,6 +534,33 @@ dependencies = [
"winapi",
]
[[package]]
name = "ciborium"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
dependencies = [
"ciborium-io",
"ciborium-ll",
"serde",
]
[[package]]
name = "ciborium-io"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
[[package]]
name = "ciborium-ll"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
dependencies = [
"ciborium-io",
"half",
]
[[package]]
name = "cipher"
version = "0.3.0"
@@ -505,6 +578,7 @@ checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e"
dependencies = [
"crypto-common",
"inout",
"zeroize",
]
[[package]]
@@ -586,7 +660,11 @@ dependencies = [
[[package]]
name = "client-core"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"async-trait",
"client-connections",
@@ -967,9 +1045,9 @@ dependencies = [
"coconut-interface",
"cosmrs",
"crypto",
"nym-api-requests",
"rand 0.7.3",
"thiserror",
"validator-api-requests",
"validator-client",
]
@@ -980,9 +1058,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"cast 0.2.7",
"clap 2.34.0",
"criterion-plot",
"criterion-plot 0.4.4",
"csv",
"itertools",
"lazy_static",
@@ -999,13 +1077,49 @@ dependencies = [
"walkdir",
]
[[package]]
name = "criterion"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
dependencies = [
"anes",
"atty",
"cast 0.3.0",
"ciborium",
"clap 3.2.8",
"criterion-plot 0.5.0",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"cast 0.2.7",
"itertools",
]
[[package]]
name = "criterion-plot"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast 0.3.0",
"itertools",
]
@@ -1116,6 +1230,7 @@ dependencies = [
"serde",
"serde_bytes",
"subtle-encoding",
"thiserror",
"x25519-dalek",
]
@@ -1133,11 +1248,12 @@ dependencies = [
[[package]]
name = "crypto-common"
version = "0.1.3"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array 0.14.5",
"rand_core 0.6.3",
"typenum",
]
@@ -1465,7 +1581,7 @@ dependencies = [
"bitvec",
"bls12_381 0.6.0",
"bs58",
"criterion",
"criterion 0.3.5",
"ff 0.11.0",
"group 0.11.0",
"lazy_static",
@@ -1650,7 +1766,7 @@ dependencies = [
[[package]]
name = "explorer-api"
version = "1.1.1"
version = "1.1.2"
dependencies = [
"chrono",
"clap 3.2.8",
@@ -1697,9 +1813,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "fastrand"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
@@ -2934,6 +3050,7 @@ dependencies = [
"rand 0.8.5",
"serde",
"task",
"thiserror",
"tokio",
"tokio-util 0.7.3",
"url",
@@ -3089,6 +3206,21 @@ dependencies = [
"libc",
]
[[package]]
name = "nym-api-requests"
version = "0.1.0"
dependencies = [
"bs58",
"coconut-interface",
"cosmrs",
"cosmwasm-std",
"getset",
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
name = "nym-bity-integration"
version = "0.1.0"
@@ -3106,7 +3238,11 @@ dependencies = [
[[package]]
name = "nym-cli"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"anyhow",
"base64",
@@ -3160,7 +3296,11 @@ dependencies = [
[[package]]
name = "nym-client"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"clap 3.2.8",
"client-connections",
@@ -3199,7 +3339,11 @@ dependencies = [
[[package]]
name = "nym-gateway"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"anyhow",
"async-trait",
@@ -3223,6 +3367,7 @@ dependencies = [
"mixnet-client",
"mixnode-common",
"network-defaults",
"nym-api-requests",
"nymsphinx",
"once_cell",
"pemstore",
@@ -3238,7 +3383,6 @@ dependencies = [
"tokio-tungstenite 0.14.0",
"tokio-util 0.7.3",
"url",
"validator-api-requests",
"validator-client",
"vergen 5.1.17",
"version-checker",
@@ -3246,7 +3390,11 @@ dependencies = [
[[package]]
name = "nym-mixnode"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"anyhow",
"bs58",
@@ -3288,7 +3436,11 @@ dependencies = [
[[package]]
name = "nym-network-requester"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"async-trait",
"clap 3.2.8",
@@ -3320,7 +3472,11 @@ dependencies = [
[[package]]
name = "nym-network-statistics"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"dirs",
"log",
@@ -3334,9 +3490,29 @@ dependencies = [
"tokio",
]
[[package]]
name = "nym-outfox"
version = "0.1.0"
dependencies = [
"blake3",
"chacha20",
"chacha20poly1305",
"criterion 0.4.0",
"curve25519-dalek",
"fastrand",
"getrandom 0.2.6",
"rayon",
"thiserror",
"zeroize",
]
[[package]]
name = "nym-socks5-client"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"clap 3.2.8",
"client-connections",
@@ -3403,7 +3579,11 @@ dependencies = [
[[package]]
name = "nym-validator-api"
<<<<<<< HEAD
version = "1.1.4"
=======
version = "1.1.5"
>>>>>>> 96444509d0f983f557c7663f0ffc615dcf053487
dependencies = [
"anyhow",
"async-trait",
@@ -3434,6 +3614,7 @@ dependencies = [
"logging",
"mixnet-contract-common",
"multisig-contract-common",
"nym-api-requests",
"nymcoconut",
"nymsphinx",
"okapi",
@@ -3459,7 +3640,6 @@ dependencies = [
"topology",
"ts-rs",
"url",
"validator-api-requests",
"validator-client",
"vergen 7.2.1",
"version-checker",
@@ -3492,7 +3672,7 @@ dependencies = [
"bincode",
"bls12_381 0.6.0",
"bs58",
"criterion",
"criterion 0.3.5",
"digest 0.9.0",
"dkg",
"doc-comment",
@@ -3541,6 +3721,7 @@ dependencies = [
"nymsphinx-types",
"pemstore",
"rand 0.7.3",
"thiserror",
"topology",
]
@@ -3615,6 +3796,7 @@ dependencies = [
"bytes",
"nymsphinx-params",
"nymsphinx-types",
"thiserror",
"tokio-util 0.7.3",
]
@@ -3624,6 +3806,7 @@ version = "0.1.0"
dependencies = [
"crypto",
"nymsphinx-types",
"thiserror",
]
[[package]]
@@ -3707,6 +3890,7 @@ name = "ordered-buffer"
version = "0.1.0"
dependencies = [
"log",
"thiserror",
]
[[package]]
@@ -4000,6 +4184,17 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug 0.3.0",
"universal-hash 0.5.0",
]
[[package]]
name = "polyval"
version = "0.5.3"
@@ -4009,7 +4204,7 @@ dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"opaque-debug 0.3.0",
"universal-hash",
"universal-hash 0.4.1",
]
[[package]]
@@ -6189,10 +6384,10 @@ version = "0.1.0"
dependencies = [
"anyhow",
"mixnet-contract-common",
"nym-api-requests",
"nym-types",
"nym-wallet-types",
"ts-rs",
"validator-api-requests",
"validator-client",
"vesting-contract-common",
"walkdir",
@@ -6367,6 +6562,16 @@ dependencies = [
"subtle 2.4.1",
]
[[package]]
name = "universal-hash"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
dependencies = [
"crypto-common",
"subtle 2.4.1",
]
[[package]]
name = "untrusted"
version = "0.7.1"
@@ -6398,21 +6603,6 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "validator-api-requests"
version = "0.1.0"
dependencies = [
"bs58",
"coconut-interface",
"cosmrs",
"cosmwasm-std",
"getset",
"mixnet-contract-common",
"schemars",
"serde",
"ts-rs",
]
[[package]]
name = "validator-client"
version = "0.1.0"
@@ -6437,6 +6627,7 @@ dependencies = [
"mixnet-contract-common",
"multisig-contract-common",
"network-defaults",
"nym-api-requests",
"prost 0.10.3",
"reqwest",
"serde",
@@ -6446,7 +6637,6 @@ dependencies = [
"tokio",
"ts-rs",
"url",
"validator-api-requests",
"vesting-contract",
"vesting-contract-common",
]
@@ -6905,9 +7095,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]]
name = "zeroize"
version = "1.4.3"
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
dependencies = [
"zeroize_derive",
]
+4 -3
View File
@@ -74,8 +74,9 @@ members = [
"mixnode",
"service-providers/network-requester",
"service-providers/network-statistics",
"validator-api",
"validator-api/validator-api-requests",
"nym-api",
"nym-api/nym-api-requests",
"nym-outfox",
"tools/nym-cli",
"tools/ts-rs-cli"
]
@@ -87,7 +88,7 @@ default-members = [
"service-providers/network-requester",
"service-providers/network-statistics",
"mixnode",
"validator-api",
"nym-api",
"explorer-api",
]
+1 -4
View File
@@ -28,7 +28,7 @@ clippy-coconut:
cargo clippy --workspace --features coconut -- -D warnings
clippy-wasm:
cargo clippy --workspace --features wasm -- -D warnings
cargo clippy --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --workspace -- -D warnings
clippy-all-contracts:
@@ -49,9 +49,6 @@ test-main:
test-coconut:
cargo test --workspace --features coconut
test-wasm:
cargo test --workspace --features wasm
test-main-expensive:
cargo test --workspace -- --ignored
+2 -1
View File
@@ -1,8 +1,9 @@
[package]
name = "client-core"
version = "1.1.4"
version = "1.1.5"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
edition = "2021"
rust-version = "1.66"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -36,19 +36,19 @@ use nymsphinx::addressing::nodes::NodeIdentity;
use std::sync::Arc;
use std::time::Duration;
use tap::TapFallible;
use task::{ShutdownListener, ShutdownNotifier};
use task::{TaskClient, TaskManager};
use url::Url;
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
pub mod non_wasm_helpers;
pub struct ClientInput {
pub shared_lane_queue_lengths: LaneQueueLengths,
pub connection_command_sender: ConnectionCommandSender,
pub input_sender: InputMessageSender,
}
pub struct ClientOutput {
pub shared_lane_queue_lengths: LaneQueueLengths,
pub received_buffer_request_sender: ReceivedBufferRequestSender,
}
@@ -85,7 +85,7 @@ pub struct BaseClientBuilder<'a, B> {
gateway_config: &'a GatewayEndpointConfig,
debug_config: &'a DebugConfig,
disabled_credentials: bool,
validator_api_endpoints: Vec<Url>,
nym_api_endpoints: Vec<Url>,
reply_storage_backend: B,
bandwidth_controller: Option<BandwidthController>,
@@ -106,7 +106,7 @@ where
gateway_config: base_config.get_gateway_endpoint_config(),
debug_config: base_config.get_debug_config(),
disabled_credentials: base_config.get_disabled_credentials_mode(),
validator_api_endpoints: base_config.get_validator_api_endpoints(),
nym_api_endpoints: base_config.get_nym_api_endpoints(),
bandwidth_controller,
reply_storage_backend,
key_manager,
@@ -120,15 +120,15 @@ where
bandwidth_controller: Option<BandwidthController>,
reply_storage_backend: B,
disabled_credentials: bool,
validator_api_endpoints: Vec<Url>,
nym_api_endpoints: Vec<Url>,
) -> BaseClientBuilder<'a, B> {
BaseClientBuilder {
gateway_config,
debug_config,
disabled_credentials,
validator_api_endpoints,
bandwidth_controller,
nym_api_endpoints,
reply_storage_backend,
bandwidth_controller,
key_manager,
}
}
@@ -151,7 +151,7 @@ where
self_address: Recipient,
topology_accessor: TopologyAccessor,
mix_tx: BatchMixMessageSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) {
info!("Starting loop cover traffic stream...");
@@ -185,7 +185,7 @@ where
reply_controller_receiver: ReplyControllerReceiver,
lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver,
shutdown: ShutdownListener,
shutdown: TaskClient,
) {
info!("Starting real traffic stream...");
@@ -212,7 +212,7 @@ where
mixnet_receiver: MixnetMessageReceiver,
reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) {
info!("Starting received messages buffer controller...");
ReceivedMessagesBufferController::new(
@@ -229,7 +229,7 @@ where
&mut self,
mixnet_message_sender: MixnetMessageSender,
ack_sender: AcknowledgementSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Result<GatewayClient, ClientCoreError<B>> {
let gateway_id = self.gateway_config.gateway_id.clone();
if gateway_id.is_empty() {
@@ -281,13 +281,13 @@ where
// future responsible for periodically polling directory server and updating
// the current global view of topology
async fn start_topology_refresher(
validator_api_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
refresh_rate: Duration,
topology_accessor: TopologyAccessor,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Result<(), ClientCoreError<B>> {
let topology_refresher_config = TopologyRefresherConfig::new(
validator_api_urls,
nym_api_urls,
refresh_rate,
env!("CARGO_PKG_VERSION").to_string(),
);
@@ -317,7 +317,7 @@ where
// requests?
fn start_mix_traffic_controller(
gateway_client: GatewayClient,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> BatchMixMessageSender {
info!("Starting mix traffic controller...");
let (mix_traffic_controller, mix_tx) = MixTrafficController::new(gateway_client);
@@ -327,7 +327,7 @@ where
async fn setup_persistent_reply_storage(
backend: B,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Result<CombinedReplyStorage, ClientCoreError<B>> {
let persistent_storage = PersistentReplyStorage::new(backend);
let mem_store = persistent_storage
@@ -367,29 +367,31 @@ where
let shared_topology_accessor = TopologyAccessor::new();
// Shutdown notifier for signalling tasks to stop
let shutdown = ShutdownNotifier::default();
let task_manager = TaskManager::default();
// channels responsible for dealing with reply-related fun
let (reply_controller_sender, reply_controller_receiver) =
reply_controller::new_control_channels();
reply_controller::requests::new_control_channels();
let self_address = self.as_mix_recipient();
// the components are started in very specific order. Unless you know what you are doing,
// do not change that.
let gateway_client = self
.start_gateway_client(mixnet_messages_sender, ack_sender, shutdown.subscribe())
.start_gateway_client(mixnet_messages_sender, ack_sender, task_manager.subscribe())
.await?;
let reply_storage =
Self::setup_persistent_reply_storage(self.reply_storage_backend, shutdown.subscribe())
.await?;
let reply_storage = Self::setup_persistent_reply_storage(
self.reply_storage_backend,
task_manager.subscribe(),
)
.await?;
Self::start_topology_refresher(
self.validator_api_endpoints.clone(),
self.nym_api_endpoints.clone(),
self.debug_config.topology_refresh_rate,
shared_topology_accessor.clone(),
shutdown.subscribe(),
task_manager.subscribe(),
)
.await?;
@@ -399,7 +401,7 @@ where
mixnet_messages_receiver,
reply_storage.key_storage(),
reply_controller_sender.clone(),
shutdown.subscribe(),
task_manager.subscribe(),
);
// The sphinx_message_sender is the transmitter for any component generating sphinx packets
@@ -407,7 +409,7 @@ where
// traffic stream.
// The MixTrafficController then sends the actual traffic
let sphinx_message_sender =
Self::start_mix_traffic_controller(gateway_client, shutdown.subscribe());
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
// Channels that the websocket listener can use to signal downstream to the real traffic
// controller that connections are closed.
@@ -435,11 +437,11 @@ where
input_receiver,
sphinx_message_sender.clone(),
reply_storage,
reply_controller_sender,
reply_controller_sender.clone(),
reply_controller_receiver,
shared_lane_queue_lengths.clone(),
client_connection_rx,
shutdown.subscribe(),
task_manager.subscribe(),
);
if !self.debug_config.disable_loop_cover_traffic_stream {
@@ -449,7 +451,7 @@ where
self_address,
shared_topology_accessor,
sphinx_message_sender,
shutdown.subscribe(),
task_manager.subscribe(),
);
}
@@ -459,17 +461,18 @@ where
Ok(BaseClient {
client_input: ClientInputStatus::AwaitingProducer {
client_input: ClientInput {
shared_lane_queue_lengths,
connection_command_sender: client_connection_tx,
input_sender,
},
},
client_output: ClientOutputStatus::AwaitingConsumer {
client_output: ClientOutput {
shared_lane_queue_lengths,
received_buffer_request_sender,
},
},
shutdown_notifier: shutdown,
reply_controller_sender,
task_manager,
})
}
}
@@ -478,5 +481,8 @@ pub struct BaseClient {
pub client_input: ClientInputStatus,
pub client_output: ClientOutputStatus,
pub shutdown_notifier: ShutdownNotifier,
// it feels very wrong to put this channel here, but I can't think of any other way of passing it to the native client
pub reply_controller_sender: ReplyControllerSender,
pub task_manager: TaskManager,
}
@@ -213,7 +213,7 @@ impl LoopCoverTrafficStream<OsRng> {
tokio::task::yield_now().await;
}
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
// we should set initial delay only when we actually start the stream
let sampled =
sample_poisson_duration(&mut self.rng, self.average_cover_message_sending_delay);
@@ -0,0 +1,14 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(not(target_arch = "wasm32"))]
mod non_wasm;
#[cfg(target_arch = "wasm32")]
mod wasm;
#[cfg(not(target_arch = "wasm32"))]
pub use non_wasm::*;
#[cfg(target_arch = "wasm32")]
pub use wasm::*;
@@ -0,0 +1,13 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use tokio::time::*;
pub type IntervalStream = tokio_stream::wrappers::IntervalStream;
pub(crate) fn get_time_now() -> Instant {
Instant::now()
}
pub(crate) fn new_interval_stream(polling_rate: Duration) -> IntervalStream {
tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(polling_rate))
}
@@ -0,0 +1,16 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::time::Duration;
use wasm_timer;
pub use wasm_timer::*;
pub type IntervalStream = gloo_timers::future::IntervalStream;
pub(crate) fn get_time_now() -> Instant {
wasm_timer::Instant::now()
}
pub(crate) fn new_interval_stream(polling_rate: Duration) -> IntervalStream {
gloo_timers::future::IntervalStream::new(polling_rate.as_millis() as u32)
}
@@ -51,8 +51,8 @@ impl MixTrafficController {
};
match result {
Err(e) => {
error!("Failed to send sphinx packet(s) to the gateway! - {:?}", e);
Err(err) => {
error!("Failed to send sphinx packet(s) to the gateway! - {err}");
self.consecutive_gateway_failure_count += 1;
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// todo: in the future this should initiate a 'graceful' shutdown or try
@@ -67,11 +67,11 @@ impl MixTrafficController {
}
}
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
spawn_future(async move {
debug!("Started MixTrafficController with graceful shutdown support");
while !shutdown.is_shutdown() {
loop {
tokio::select! {
mix_packets = self.mix_rx.recv() => match mix_packets {
Some(mix_packets) => {
@@ -82,8 +82,9 @@ impl MixTrafficController {
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("MixTrafficController: Received shutdown");
break;
}
}
}
+2
View File
@@ -3,6 +3,7 @@
pub mod base_client;
pub mod cover_traffic_stream;
pub(crate) mod helpers;
pub mod inbound_messages;
pub mod key_manager;
pub mod mix_traffic;
@@ -10,3 +11,4 @@ pub mod real_messages_control;
pub mod received_buffer;
pub mod replies;
pub mod topology_control;
pub(crate) mod transmission_buffer;
@@ -72,7 +72,7 @@ impl AcknowledgementListener {
}
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started AcknowledgementListener with graceful shutdown support");
while !shutdown.is_shutdown() {
@@ -84,7 +84,7 @@ impl AcknowledgementListener {
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("AcknowledgementListener: Received shutdown");
}
}
@@ -249,7 +249,7 @@ impl ActionController {
}
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started ActionController with graceful shutdown support");
while !shutdown.is_shutdown() {
@@ -270,7 +270,7 @@ impl ActionController {
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("ActionController: Received shutdown");
}
}
@@ -109,7 +109,7 @@ where
};
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started InputMessageListener with graceful shutdown support");
while !shutdown.is_shutdown() {
@@ -123,7 +123,7 @@ where
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("InputMessageListener: Received shutdown");
}
}
@@ -249,7 +249,7 @@ where
}
}
pub(super) fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
pub(super) fn start_with_shutdown(self, shutdown: task::TaskClient) {
let mut acknowledgement_listener = self.acknowledgement_listener;
let mut input_message_listener = self.input_message_listener;
let mut retransmission_request_listener = self.retransmission_request_listener;
@@ -137,7 +137,7 @@ where
.await
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started RetransmissionRequestListener with graceful shutdown support");
while !shutdown.is_shutdown() {
@@ -37,7 +37,7 @@ impl SentNotificationListener {
.unwrap();
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started SentNotificationListener with graceful shutdown support");
while !shutdown.is_shutdown() {
@@ -51,7 +51,7 @@ impl SentNotificationListener {
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("SentNotificationListener: Received shutdown");
}
}
@@ -20,6 +20,7 @@ use nymsphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
use nymsphinx::preparer::{MessagePreparer, PreparedFragment};
use nymsphinx::Delay;
use rand::{CryptoRng, Rng};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use thiserror::Error;
@@ -278,7 +279,7 @@ where
reply_surb: ReplySurb,
amount: u32,
) -> Result<(), SurbWrappedPreparationError> {
debug!("requesting {amount} reply SURBs from {from:?}");
debug!("requesting {amount} reply SURBs from {from}");
let surbs_request =
ReplyMessage::new_surb_request_message(self.config.sender_address, amount);
@@ -294,19 +295,11 @@ where
)))
}
// the only difference between this method and `try_send_reply_chunks` is that
// here we are not creating acks as acks are already in memory waiting to get cleared.
// we are only updating their existing delays
pub(crate) async fn try_send_retransmission_reply_chunks(
pub(crate) async fn send_retransmission_reply_chunks(
&mut self,
fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurb>,
prepared_fragments: Vec<PreparedFragment>,
lane: TransmissionLane,
) -> Result<(), SurbWrappedPreparationError> {
let prepared_fragments = self
.prepare_reply_chunks_for_sending(fragments.clone(), reply_surbs)
.await?;
) {
let mut real_messages = Vec::with_capacity(prepared_fragments.len());
for prepared in prepared_fragments {
@@ -315,33 +308,58 @@ where
}
self.forward_messages(real_messages, lane).await;
Ok(())
}
pub(crate) async fn try_send_reply_chunks(
pub(crate) async fn try_send_reply_chunks_on_lane(
&mut self,
target: AnonymousSenderTag,
fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurb>,
lane: TransmissionLane,
) -> Result<(), SurbWrappedPreparationError> {
// TODO: technically this is performing an unnecessary cloning, but in the grand scheme of things
// is it really that bad?
self.try_send_reply_chunks(
target,
fragments.into_iter().map(|f| (lane, f)).collect(),
reply_surbs,
)
.await
}
pub(crate) async fn try_send_reply_chunks(
&mut self,
target: AnonymousSenderTag,
fragments: Vec<(TransmissionLane, Fragment)>,
reply_surbs: Vec<ReplySurb>,
) -> Result<(), SurbWrappedPreparationError> {
let prepared_fragments = self
.prepare_reply_chunks_for_sending(fragments.clone(), reply_surbs)
.prepare_reply_chunks_for_sending(
fragments.iter().map(|(_, f)| f.clone()).collect(),
reply_surbs,
)
.await?;
let mut pending_acks = Vec::with_capacity(fragments.len());
let mut real_messages = Vec::with_capacity(fragments.len());
let mut to_forward: HashMap<_, Vec<_>> = HashMap::new();
for (raw, prepared) in fragments.into_iter().zip(prepared_fragments.into_iter()) {
let lane = raw.0;
let fragment = raw.1;
let real_message = RealMessage::new(prepared.mix_packet, prepared.fragment_identifier);
let delay = prepared.total_delay;
let pending_ack = PendingAcknowledgement::new_anonymous(raw, delay, target, false);
let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false);
real_messages.push(real_message);
let entry = to_forward.entry(lane).or_default();
entry.push(real_message);
pending_acks.push(pending_ack);
}
self.forward_messages(real_messages, lane).await;
for (lane, real_messages) in to_forward {
self.forward_messages(real_messages, lane).await;
}
self.insert_pending_acks(pending_acks);
Ok(())
}
@@ -467,7 +485,7 @@ where
Ok(prepared_fragment)
}
async fn prepare_reply_chunks_for_sending(
pub(crate) async fn prepare_reply_chunks_for_sending(
&mut self,
fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurb>,
@@ -263,7 +263,7 @@ impl RealMessagesController<OsRng> {
}
}
pub fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
let mut out_queue_control = self.out_queue_control;
let ack_control = self.ack_control;
let mut reply_control = self.reply_control;
@@ -1,9 +1,11 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use self::sending_delay_controller::SendingDelayController;
use crate::client::mix_traffic::BatchMixMessageSender;
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
use crate::client::topology_control::TopologyAccessor;
use crate::client::transmission_buffer::TransmissionBuffer;
use client_connections::{
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
};
@@ -32,22 +34,7 @@ use tokio::time;
#[cfg(target_arch = "wasm32")]
use wasm_timer;
use self::{
sending_delay_controller::SendingDelayController, transmission_buffer::TransmissionBuffer,
};
mod sending_delay_controller;
mod transmission_buffer;
#[cfg(not(target_arch = "wasm32"))]
fn get_time_now() -> time::Instant {
time::Instant::now()
}
#[cfg(target_arch = "wasm32")]
fn get_time_now() -> wasm_timer::Instant {
wasm_timer::Instant::now()
}
/// Configurable parameters of the `OutQueueControl`
pub(crate) struct Config {
@@ -138,7 +125,7 @@ where
/// Buffer containing all incoming real messages keyed by transmission lane, that we will send
/// out to the mixnet.
transmission_buffer: TransmissionBuffer,
transmission_buffer: TransmissionBuffer<RealMessage>,
/// Incoming channel for being notified of closed connections, so that we can close lanes
/// corresponding to connections. To avoid sending traffic unnecessary
@@ -165,6 +152,10 @@ impl From<PreparedFragment> for RealMessage {
}
impl RealMessage {
pub(crate) fn packet_size(&self) -> usize {
self.mix_packet.sphinx_packet().len()
}
pub(crate) fn new(mix_packet: MixPacket, fragment_id: FragmentIdentifier) -> Self {
RealMessage {
mix_packet,
@@ -210,7 +201,7 @@ where
real_receiver,
rng,
topology_access,
transmission_buffer: Default::default(),
transmission_buffer: TransmissionBuffer::new(),
client_connection_rx,
lane_queue_lengths,
}
@@ -300,7 +291,7 @@ where
};
if let Err(err) = self.mix_tx.send(vec![next_message]).await {
log::error!("Failed to send: {}", err);
log::error!("Failed to send: {err}");
}
// notify ack controller about sending our message only after we actually managed to push it
@@ -364,7 +355,9 @@ where
fn pop_next_message(&mut self) -> Option<RealMessage> {
// Pop the next message from the transmission buffer
let (lane, real_next) = self.transmission_buffer.pop_next_message_at_random()?;
let (lane, real_next) = self
.transmission_buffer
.pop_next_message_at_random(&mut self.rng)?;
// Update the published queue length
let lane_length = self.transmission_buffer.lane_length(&lane);
@@ -505,7 +498,7 @@ where
}
#[cfg(not(target_arch = "wasm32"))]
fn log_status(&self, shutdown: &mut task::ShutdownListener) {
fn log_status(&self, shutdown: &mut task::TaskClient) {
use crate::error::ClientCoreStatusMessage;
let packets = self.transmission_buffer.total_size();
@@ -550,7 +543,7 @@ where
}
}
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(super) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started OutQueueControl with graceful shutdown support");
#[cfg(not(target_arch = "wasm32"))]
@@ -561,7 +554,7 @@ where
while !shutdown.is_shutdown() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("OutQueueControl: Received shutdown");
}
_ = status_timer.tick() => {
@@ -1,14 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::get_time_now;
use crate::client::helpers::{get_time_now, Instant};
use std::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time;
#[cfg(target_arch = "wasm32")]
use wasm_timer;
// The minimum time between increasing the average delay between packets. If we hit the ceiling in
// the available buffer space we want to take somewhat swift action, but we still need to give a
// short time to give the channel a chance reduce pressure.
@@ -39,19 +34,11 @@ pub(crate) struct SendingDelayController {
lower_bound: u32,
/// To make sure we don't change the multiplier to fast, we limit a change to some duration
#[cfg(not(target_arch = "wasm32"))]
time_when_changed: time::Instant,
#[cfg(target_arch = "wasm32")]
time_when_changed: wasm_timer::Instant,
time_when_changed: Instant,
/// If we have a long enough time without any backpressure detected we try reducing the sending
/// delay multiplier
#[cfg(not(target_arch = "wasm32"))]
time_when_backpressure_detected: time::Instant,
#[cfg(target_arch = "wasm32")]
time_when_backpressure_detected: wasm_timer::Instant,
time_when_backpressure_detected: Instant,
}
impl Default for SendingDelayController {
@@ -77,10 +64,12 @@ impl SendingDelayController {
self.current_multiplier
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn min_multiplier(&self) -> u32 {
self.lower_bound
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn max_multiplier(&self) -> u32 {
self.upper_bound
}
@@ -407,21 +407,20 @@ impl RequestReceiver {
}
}
async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started RequestReceiver with graceful shutdown support");
while !shutdown.is_shutdown() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("RequestReceiver: Received shutdown");
}
request = self.query_receiver.next() => {
match request {
Some(message) => self.handle_message(message).await,
None => {
log::trace!("RequestReceiver: Stopping since channel closed");
break;
},
if let Some(message) = request {
self.handle_message(message).await
} else {
log::trace!("RequestReceiver: Stopping since channel closed");
break;
}
},
}
@@ -447,20 +446,19 @@ impl FragmentedMessageReceiver {
}
}
async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started FragmentedMessageReceiver with graceful shutdown support");
while !shutdown.is_shutdown() {
tokio::select! {
new_messages = self.mixnet_packet_receiver.next() => match new_messages {
Some(new_messages) => {
new_messages = self.mixnet_packet_receiver.next() => {
if let Some(new_messages) = new_messages {
self.received_buffer.handle_new_received(new_messages).await;
}
None => {
} else {
log::trace!("FragmentedMessageReceiver: Stopping since channel closed");
break;
}
},
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("FragmentedMessageReceiver: Received shutdown");
}
}
@@ -498,7 +496,7 @@ impl ReceivedMessagesBufferController {
}
}
pub fn start_with_shutdown(self, shutdown: task::ShutdownListener) {
pub fn start_with_shutdown(self, shutdown: task::TaskClient) {
let mut fragmented_message_receiver = self.fragmented_message_receiver;
let mut request_receiver = self.request_receiver;
@@ -4,8 +4,8 @@
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
use crate::client::replies::reply_storage::CombinedReplyStorage;
use client_connections::TransmissionLane;
use futures::channel::mpsc;
use client_connections::{ConnectionId, TransmissionLane};
use futures::channel::oneshot;
use futures::StreamExt;
use log::{debug, error, info, trace, warn};
use nymsphinx::addressing::clients::Recipient;
@@ -15,116 +15,16 @@ use nymsphinx::chunking::fragment::{Fragment, FragmentIdentifier};
use rand::{CryptoRng, Rng};
use std::cmp::{max, min};
use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Weak};
use std::time::Duration;
use time::OffsetDateTime;
#[cfg(not(target_arch = "wasm32"))]
type IntervalStream = tokio_stream::wrappers::IntervalStream;
use crate::client::helpers::new_interval_stream;
use crate::client::transmission_buffer::TransmissionBuffer;
pub(crate) use requests::{ReplyControllerMessage, ReplyControllerReceiver, ReplyControllerSender};
#[cfg(target_arch = "wasm32")]
type IntervalStream = gloo_timers::future::IntervalStream;
pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerReceiver) {
let (tx, rx) = mpsc::unbounded();
(tx.into(), rx)
}
#[derive(Debug, Clone)]
pub(crate) struct ReplyControllerSender(mpsc::UnboundedSender<ReplyControllerMessage>);
impl From<mpsc::UnboundedSender<ReplyControllerMessage>> for ReplyControllerSender {
fn from(inner: mpsc::UnboundedSender<ReplyControllerMessage>) -> Self {
ReplyControllerSender(inner)
}
}
impl ReplyControllerSender {
pub(crate) fn send_retransmission_data(
&self,
recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>,
extra_surb_request: bool,
) {
self.0
.unbounded_send(ReplyControllerMessage::RetransmitReply {
recipient,
timed_out_ack,
extra_surb_request,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_reply(
&self,
recipient: AnonymousSenderTag,
message: Vec<u8>,
lane: TransmissionLane,
) {
self.0
.unbounded_send(ReplyControllerMessage::SendReply {
recipient,
message,
lane,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_additional_surbs(
&self,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
) {
self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbs {
sender_tag,
reply_surbs,
from_surb_request,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_additional_surbs_request(&self, recipient: Recipient, amount: u32) {
self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbsRequest {
recipient: Box::new(recipient),
amount,
})
.expect("ReplyControllerReceiver has died!")
}
}
pub(crate) type ReplyControllerReceiver = mpsc::UnboundedReceiver<ReplyControllerMessage>;
#[derive(Debug)]
pub(crate) enum ReplyControllerMessage {
RetransmitReply {
recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>,
extra_surb_request: bool,
},
SendReply {
recipient: AnonymousSenderTag,
message: Vec<u8>,
lane: TransmissionLane,
},
AdditionalSurbs {
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
},
// Should this also be handled in here? it's technically a completely different side of the pipe
// let's see how it works when combined, might split it before creating PR
AdditionalSurbsRequest {
recipient: Box<Recipient>,
amount: u32,
},
}
pub mod requests;
pub struct Config {
min_surb_request_size: u32,
@@ -172,7 +72,7 @@ pub struct ReplyController<R> {
// of surbs required to send the message through
// expected_reliability: f32,
request_receiver: ReplyControllerReceiver,
pending_replies: HashMap<AnonymousSenderTag, VecDeque<Fragment>>,
pending_replies: HashMap<AnonymousSenderTag, TransmissionBuffer<Fragment>>,
/// Retransmission packets that have already timed out and are waiting for additional reply SURBs
/// so that they could be sent back to the network. Once we receive more SURBs, we should send them ASAP.
@@ -204,17 +104,28 @@ where
}
}
/// Inserts the pending replies into the BACK of the queue fn insert_pending_replies<V: Into<VecDeque<Fragment>>>(
fn insert_pending_replies<V: Into<VecDeque<Fragment>>>(
fn insert_pending_replies<I: IntoIterator<Item = Fragment>>(
&mut self,
recipient: &AnonymousSenderTag,
fragments: V,
fragments: I,
lane: TransmissionLane,
) {
if let Some(existing) = self.pending_replies.get_mut(recipient) {
existing.append(&mut fragments.into())
} else {
self.pending_replies.insert(*recipient, fragments.into());
}
self.pending_replies
.entry(*recipient)
.or_insert_with(TransmissionBuffer::new)
.store(&lane, fragments)
}
fn re_insert_pending_replies(
&mut self,
recipient: &AnonymousSenderTag,
fragments: Vec<(TransmissionLane, Fragment)>,
) {
// the buffer should ALWAYS exist at this point, if it doesn't, it's a bug...
self.pending_replies
.entry(*recipient)
.or_insert_with(TransmissionBuffer::new)
.store_multiple(fragments)
}
fn re_insert_pending_retransmission(
@@ -244,7 +155,7 @@ where
let pending_queue_size = self
.pending_replies
.get(target)
.map(|pending_queue| pending_queue.len())
.map(|pending_queue| pending_queue.total_size())
.unwrap_or_default();
let retransmission_queue = self
@@ -299,43 +210,62 @@ where
}
trace!("handling reply to {:?}", recipient_tag);
let fragments = self.message_handler.split_reply_message(data);
let mut fragments = self.message_handler.split_reply_message(data);
let total_size = fragments.len();
trace!("This reply requires {:?} SURBs", total_size);
let required_surbs = fragments.len();
trace!("This reply requires {:?} SURBs", required_surbs);
// TODO: edge case:
// we're making a lot of requests and have to request a lot of surbs
// (but at some point we run out of surbs for surb requests)
let (surbs, _surbs_left) = self
let available_surbs = self
.full_reply_storage
.surbs_storage_ref()
.get_reply_surbs(&recipient_tag, required_surbs);
.available_surbs(&recipient_tag);
let min_surbs_threshold = self
.full_reply_storage
.surbs_storage_ref()
.min_surb_threshold();
if let Some(reply_surbs) = surbs {
if let Err(err) = self
.message_handler
.try_send_reply_chunks(recipient_tag, fragments, reply_surbs, lane)
.await
{
let err = err.return_unused_surbs(
self.full_reply_storage.surbs_storage_ref(),
&recipient_tag,
);
warn!("failed to send reply to {:?} - {err}", recipient_tag);
// TODO: should we buffer that data to try again?
}
let max_to_send = if available_surbs > min_surbs_threshold {
min(fragments.len(), available_surbs - min_surbs_threshold)
} else {
// we don't have enough surbs for this reply
self.insert_pending_replies(&recipient_tag, fragments);
0
};
if self.should_request_more_surbs(&recipient_tag) {
self.request_reply_surbs_for_queue_clearing(recipient_tag)
.await;
if max_to_send > 0 {
let (surbs, _surbs_left) = self
.full_reply_storage
.surbs_storage_ref()
.get_reply_surbs(&recipient_tag, max_to_send);
if let Some(reply_surbs) = surbs {
let to_send = fragments.drain(..max_to_send).collect::<Vec<_>>();
if let Err(err) = self
.message_handler
.try_send_reply_chunks_on_lane(
recipient_tag,
to_send.clone(),
reply_surbs,
lane,
)
.await
{
let err = err.return_unused_surbs(
self.full_reply_storage.surbs_storage_ref(),
&recipient_tag,
);
warn!("failed to send reply to {recipient_tag}: {err}");
self.insert_pending_replies(&recipient_tag, to_send, lane);
}
}
}
// if there's leftover data we didn't send because we didn't have enough (or any) surbs - buffer it
if !fragments.is_empty() {
self.insert_pending_replies(&recipient_tag, fragments, lane);
}
if self.should_request_more_surbs(&recipient_tag) {
self.request_reply_surbs_for_queue_clearing(recipient_tag)
.await;
}
}
async fn request_additional_reply_surbs(
@@ -398,35 +328,18 @@ where
};
let mut to_take = Vec::new();
let mut to_remove = Vec::new();
// TODO: once rust 1.66.0 is stabilised on 15.12.22, just change it to
// `.pop_front()` to directly take ownership
for (k, data) in pending.iter() {
let upgraded = match data.upgrade() {
Some(upgraded) => upgraded,
None => {
// we got the ack while the data was waiting in the queue
to_remove.push(*k);
continue;
while to_take.len() < max_to_clear {
if let Some((_, data)) = pending.pop_first() {
// no need to do anything if we failed to upgrade the reference,
// it means we got the ack while the data was waiting in the queue
if let Some(upgraded) = data.upgrade() {
to_take.push(upgraded)
}
};
to_take.push(upgraded);
// we have taken as many entries as we could have
if to_take.len() >= max_to_clear {
} else {
// our map is empty!
break;
}
// TODO: use if upgraded.is_extra_surb_request() to bypass the limit
}
for ack in &to_take {
pending.remove(&ack.inner_fragment_identifier());
}
for id in to_remove {
pending.remove(&id);
}
if to_take.is_empty() {
@@ -447,46 +360,47 @@ where
let to_send_vec = to_take.iter().map(|ack| ack.fragment_data()).collect();
if let Err(err) = self
let prepared_fragments = match self
.message_handler
.try_send_retransmission_reply_chunks(
to_send_vec,
surbs_for_reply,
TransmissionLane::Retransmission,
)
.prepare_reply_chunks_for_sending(to_send_vec, surbs_for_reply)
.await
{
let err = err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
self.re_insert_pending_retransmission(&target, to_take);
Ok(prepared) => prepared,
Err(err) => {
let err =
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
self.re_insert_pending_retransmission(&target, to_take);
warn!(
"failed to clear pending retransmission queue for {:?} - {err}",
target
);
}
warn!(
"failed to clear pending retransmission queue for {:?} - {err}",
target
);
return;
}
};
// we can't fail at this point, so drop all references to acks so that timer updates wouldn't blow up
drop(to_take);
self.message_handler
.send_retransmission_reply_chunks(prepared_fragments, TransmissionLane::Retransmission)
.await;
}
fn pop_at_most_pending_replies(
&mut self,
from: &AnonymousSenderTag,
amount: usize,
) -> Option<VecDeque<Fragment>> {
) -> Option<Vec<(TransmissionLane, Fragment)>> {
// if possible, pop all pending replies, if not, pop only entries for which we'd have a reply surb
let total = self.pending_replies.get(from)?.len();
let total = self.pending_replies.get(from)?.total_size();
trace!("pending queue has {total} elements");
if total == 0 {
return None;
}
if total < amount {
self.pending_replies.remove(from)
} else {
Some(
self.pending_replies
.get_mut(from)?
.drain(..amount)
.collect(),
)
}
self.pending_replies
.get_mut(from)?
.pop_at_most_n_next_messages_at_random(amount)
}
async fn try_clear_pending_queue(&mut self, target: AnonymousSenderTag) {
@@ -510,9 +424,9 @@ where
// we're guaranteed to not get more entries than we have reply surbs for
if let Some(to_send) = self.pop_at_most_pending_replies(&target, max_to_clear) {
let to_send_vec = to_send.iter().cloned().collect::<Vec<_>>();
let to_send_clone = to_send.clone();
if to_send_vec.is_empty() {
if to_send_clone.is_empty() {
panic!(
"please let the devs know if you ever see this message (reply_controller.rs)"
);
@@ -521,27 +435,22 @@ where
let (surbs_for_reply, _) = self
.full_reply_storage
.surbs_storage_ref()
.get_reply_surbs(&target, to_send_vec.len());
.get_reply_surbs(&target, to_send_clone.len());
let Some(surbs_for_reply) = surbs_for_reply else {
error!("somehow different task has stolen our reply surbs! - this should have been impossible");
self.insert_pending_replies(&target, to_send);
self.re_insert_pending_replies(&target, to_send);
return;
};
if let Err(err) = self
.message_handler
.try_send_reply_chunks(
target,
to_send_vec,
surbs_for_reply,
TransmissionLane::General,
)
.try_send_reply_chunks(target, to_send_clone, surbs_for_reply)
.await
{
let err =
err.return_unused_surbs(self.full_reply_storage.surbs_storage_ref(), &target);
self.insert_pending_replies(&target, to_send);
self.re_insert_pending_replies(&target, to_send);
warn!("failed to clear pending queue for {:?} - {err}", target);
}
} else {
@@ -712,6 +621,30 @@ where
}
}
// to be honest this doesn't make a lot of sense in the context of `connection_id`,
// it should really be asked per tag
fn handle_lane_queue_length(
&self,
connection_id: ConnectionId,
response_channel: oneshot::Sender<usize>,
) {
// TODO: if we ever have duplicate ids for different senders, it means our rng is super weak
// thus I don't think we have to worry about it?
let lane = TransmissionLane::ConnectionId(connection_id);
for buf in self.pending_replies.values() {
if let Some(length) = buf.lane_length(&lane) {
if response_channel.send(length).is_err() {
error!("the requester for lane queue length has dropped the response channel!")
}
return;
}
}
// make sure that if we didn't find that lane, we reply with 0
if response_channel.send(0).is_err() {
error!("the requester for lane queue length has dropped the response channel!")
}
}
async fn handle_request(&mut self, request: ReplyControllerMessage) {
match request {
ReplyControllerMessage::RetransmitReply {
@@ -735,19 +668,26 @@ where
self.handle_received_surbs(sender_tag, reply_surbs, from_surb_request)
.await
}
ReplyControllerMessage::LaneQueueLength {
connection_id,
response_channel,
} => self.handle_lane_queue_length(connection_id, response_channel),
ReplyControllerMessage::AdditionalSurbsRequest { recipient, amount } => {
self.handle_surb_request(*recipient, amount).await
}
}
}
// TODO: modify this method to more accurately determine the amount of surbs it needs to request
// it should take into consideration the average latency, sending rate and queue size.
// it should request as many surbs as it takes to saturate its sending rate before next batch arrives
async fn request_reply_surbs_for_queue_clearing(&mut self, target: AnonymousSenderTag) {
trace!("requesting surbs for queues clearing");
let pending_queue_size = self
.pending_replies
.get(&target)
.map(|pending_queue| pending_queue.len())
.map(|pending_queue| pending_queue.total_size())
.unwrap_or_default();
let retransmission_queue = self
@@ -787,7 +727,7 @@ where
}
let Some(last_received) = self.full_reply_storage.surbs_storage_ref().surbs_last_received_at(pending_reply_target) else {
error!("we have {} pending replies for {pending_reply_target}, but we somehow never received any reply surbs from them!", vals.len());
error!("we have {} pending replies for {pending_reply_target}, but we somehow never received any reply surbs from them!", vals.total_size());
to_remove.push(*pending_reply_target);
continue;
};
@@ -883,28 +823,25 @@ where
}
}
fn create_interval_stream(polling_rate: Duration) -> IntervalStream {
#[cfg(not(target_arch = "wasm32"))]
return tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(polling_rate));
// #[cfg(not(target_arch = "wasm32"))]
// async fn log_status(&self) {
// todo!()
// }
#[cfg(target_arch = "wasm32")]
return gloo_timers::future::IntervalStream::new(polling_rate.as_millis() as u32);
}
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: task::ShutdownListener) {
pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: task::TaskClient) {
debug!("Started ReplyController with graceful shutdown support");
let polling_rate = Duration::from_secs(5);
let mut stale_inspection = Self::create_interval_stream(polling_rate);
let mut stale_inspection = new_interval_stream(polling_rate);
// this is in the order of hours/days so we don't have to poll it that often
let polling_rate = Duration::from_secs(self.config.max_reply_surb_age.as_secs() / 10);
let mut invalidation_inspection = Self::create_interval_stream(polling_rate);
let mut invalidation_inspection = new_interval_stream(polling_rate);
while !shutdown.is_shutdown() {
tokio::select! {
biased;
_ = shutdown.recv() => {
_ = shutdown.recv_with_delay() => {
log::trace!("ReplyController: Received shutdown");
},
req = self.request_receiver.next() => match req {
@@ -0,0 +1,136 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
use client_connections::{ConnectionId, TransmissionLane};
use futures::channel::{mpsc, oneshot};
use log::error;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
use nymsphinx::anonymous_replies::ReplySurb;
use std::sync::Weak;
pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerReceiver) {
let (tx, rx) = mpsc::unbounded();
(tx.into(), rx)
}
#[derive(Debug, Clone)]
pub struct ReplyControllerSender(mpsc::UnboundedSender<ReplyControllerMessage>);
impl From<mpsc::UnboundedSender<ReplyControllerMessage>> for ReplyControllerSender {
fn from(inner: mpsc::UnboundedSender<ReplyControllerMessage>) -> Self {
ReplyControllerSender(inner)
}
}
impl ReplyControllerSender {
pub(crate) fn send_retransmission_data(
&self,
recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>,
extra_surb_request: bool,
) {
self.0
.unbounded_send(ReplyControllerMessage::RetransmitReply {
recipient,
timed_out_ack,
extra_surb_request,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_reply(
&self,
recipient: AnonymousSenderTag,
message: Vec<u8>,
lane: TransmissionLane,
) {
self.0
.unbounded_send(ReplyControllerMessage::SendReply {
recipient,
message,
lane,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_additional_surbs(
&self,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
) {
self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbs {
sender_tag,
reply_surbs,
from_surb_request,
})
.expect("ReplyControllerReceiver has died!")
}
pub(crate) fn send_additional_surbs_request(&self, recipient: Recipient, amount: u32) {
self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbsRequest {
recipient: Box::new(recipient),
amount,
})
.expect("ReplyControllerReceiver has died!")
}
pub async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> usize {
let (response_tx, response_rx) = oneshot::channel();
self.0
.unbounded_send(ReplyControllerMessage::LaneQueueLength {
connection_id,
response_channel: response_tx,
})
.expect("ReplyControllerReceiver has died!");
match response_rx.await {
Ok(length) => length,
Err(_) => {
error!("The reply controller has dropped our response channel!");
// TODO: should we panic here instead? this message implies something weird and unrecoverable has happened
0
}
}
}
}
pub(crate) type ReplyControllerReceiver = mpsc::UnboundedReceiver<ReplyControllerMessage>;
#[derive(Debug)]
pub(crate) enum ReplyControllerMessage {
RetransmitReply {
recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>,
extra_surb_request: bool,
},
SendReply {
recipient: AnonymousSenderTag,
message: Vec<u8>,
lane: TransmissionLane,
},
AdditionalSurbs {
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
from_surb_request: bool,
},
// this one doesn't belong here either...
LaneQueueLength {
connection_id: ConnectionId,
response_channel: oneshot::Sender<usize>,
},
// Should this also be handled in here? it's technically a completely different side of the pipe
// let's see how it works when combined, might split it before creating PR
AdditionalSurbsRequest {
recipient: Box<Recipient>,
amount: u32,
},
}
@@ -37,7 +37,7 @@ where
pub async fn flush_on_shutdown(
mut self,
mem_state: CombinedReplyStorage,
mut shutdown: task::ShutdownListener,
mut shutdown: task::TaskClient,
) {
use log::{debug, error, info, warn};
@@ -136,19 +136,15 @@ impl Default for TopologyAccessor {
}
pub struct TopologyRefresherConfig {
validator_api_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
refresh_rate: Duration,
client_version: String,
}
impl TopologyRefresherConfig {
pub fn new(
validator_api_urls: Vec<Url>,
refresh_rate: Duration,
client_version: String,
) -> Self {
pub fn new(nym_api_urls: Vec<Url>, refresh_rate: Duration, client_version: String) -> Self {
TopologyRefresherConfig {
validator_api_urls,
nym_api_urls,
refresh_rate,
client_version,
}
@@ -159,7 +155,7 @@ pub struct TopologyRefresher {
validator_client: validator_client::client::ApiClient,
client_version: String,
validator_api_urls: Vec<Url>,
nym_api_urls: Vec<Url>,
topology_accessor: TopologyAccessor,
refresh_rate: Duration,
@@ -169,14 +165,12 @@ pub struct TopologyRefresher {
impl TopologyRefresher {
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
cfg.validator_api_urls.shuffle(&mut thread_rng());
cfg.nym_api_urls.shuffle(&mut thread_rng());
TopologyRefresher {
validator_client: validator_client::client::ApiClient::new(
cfg.validator_api_urls[0].clone(),
),
validator_client: validator_client::client::ApiClient::new(cfg.nym_api_urls[0].clone()),
client_version: cfg.client_version,
validator_api_urls: cfg.validator_api_urls,
nym_api_urls: cfg.nym_api_urls,
topology_accessor,
refresh_rate: cfg.refresh_rate,
currently_used_api: 0,
@@ -184,15 +178,15 @@ impl TopologyRefresher {
}
}
fn use_next_validator_api(&mut self) {
if self.validator_api_urls.len() == 1 {
warn!("There's only a single validator API available - it won't be possible to use a different one");
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.validator_api_urls.len();
self.currently_used_api = (self.currently_used_api + 1) % self.nym_api_urls.len();
self.validator_client
.change_validator_api(self.validator_api_urls[self.currently_used_api].clone())
.change_nym_api(self.nym_api_urls[self.currently_used_api].clone())
}
/// Verifies whether nodes a reasonably distributed among all mix layers.
@@ -288,7 +282,7 @@ impl TopologyRefresher {
let new_topology = self.get_current_compatible_topology().await;
if new_topology.is_none() {
self.use_next_validator_api();
self.use_next_nym_api();
}
if new_topology.is_none() && self.was_latest_valid {
@@ -310,7 +304,7 @@ impl TopologyRefresher {
self.topology_accessor.ensure_is_routable().await
}
pub fn start_with_shutdown(mut self, mut shutdown: task::ShutdownListener) {
pub fn start_with_shutdown(mut self, mut shutdown: task::TaskClient) {
spawn_future(async move {
debug!("Started TopologyRefresher with graceful shutdown support");
@@ -1,38 +1,57 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::client::helpers::{get_time_now, Instant};
use crate::client::real_messages_control::real_traffic_stream::RealMessage;
use client_connections::TransmissionLane;
use nymsphinx::chunking::fragment::Fragment;
use rand::{seq::SliceRandom, Rng};
use std::{
collections::{HashMap, HashSet, VecDeque},
time::Duration,
};
#[cfg(not(target_arch = "wasm32"))]
use tokio::time;
#[cfg(target_arch = "wasm32")]
use wasm_timer;
use super::{get_time_now, RealMessage};
// The number of lanes included in the oldest set. Used when we need to prioritize traffic.
const OLDEST_LANE_SET_SIZE: usize = 4;
// As a way of prune connections we also check for timeouts.
const MSG_CONSIDERED_STALE_AFTER_SECS: u64 = 10 * 60;
#[derive(Default)]
pub(crate) struct TransmissionBuffer {
buffer: HashMap<TransmissionLane, LaneBufferEntry>,
pub(crate) trait SizedData {
fn data_size(&self) -> usize;
}
impl TransmissionBuffer {
impl SizedData for RealMessage {
fn data_size(&self) -> usize {
self.packet_size()
}
}
impl SizedData for Fragment {
fn data_size(&self) -> usize {
// note that raw `Fragment` is smaller than sphinx packet payload
// as it doesn't include surb-ack or the [shared] key materials
self.payload_size()
}
}
#[derive(Default)]
pub(crate) struct TransmissionBuffer<T> {
buffer: HashMap<TransmissionLane, LaneBufferEntry<T>>,
}
impl<T> TransmissionBuffer<T> {
pub(crate) fn new() -> Self {
TransmissionBuffer {
buffer: HashMap::new(),
}
}
#[allow(unused)]
pub(crate) fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub(crate) fn remove(&mut self, lane: &TransmissionLane) -> Option<LaneBufferEntry> {
pub(crate) fn remove(&mut self, lane: &TransmissionLane) -> Option<LaneBufferEntry<T>> {
self.buffer.remove(lane)
}
@@ -57,20 +76,22 @@ impl TransmissionBuffer {
.collect()
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn total_size(&self) -> usize {
self.buffer.values().map(LaneBufferEntry::len).sum()
}
#[cfg(not(target_arch = "wasm32"))]
pub(crate) fn total_size_in_bytes(&self) -> usize {
pub(crate) fn total_size_in_bytes(&self) -> usize
where
T: SizedData,
{
self.buffer
.values()
.map(|lane_buffer_entry| {
lane_buffer_entry
.real_messages
.items
.iter()
.map(|real_message| real_message.mix_packet.sphinx_packet().len())
.map(|item| item.data_size())
.sum::<usize>()
})
.sum()
@@ -92,42 +113,51 @@ impl TransmissionBuffer {
.collect()
}
pub(crate) fn store(&mut self, lane: &TransmissionLane, real_messages: Vec<RealMessage>) {
pub(crate) fn store<I: IntoIterator<Item = T>>(&mut self, lane: &TransmissionLane, items: I) {
if let Some(lane_buffer_entry) = self.buffer.get_mut(lane) {
lane_buffer_entry.append(real_messages);
lane_buffer_entry.extend(items);
} else {
self.buffer
.insert(*lane, LaneBufferEntry::new(real_messages));
.insert(*lane, LaneBufferEntry::new(items.into_iter().collect()));
}
}
fn pick_random_lane(&self) -> Option<&TransmissionLane> {
let lanes: Vec<&TransmissionLane> = self.buffer.keys().collect();
lanes.choose(&mut rand::thread_rng()).copied()
pub(crate) fn store_multiple(&mut self, items: Vec<(TransmissionLane, T)>) {
for (lane, item) in items {
self.buffer
.entry(lane)
.or_insert_with(LaneBufferEntry::new_empty)
.push_item(item)
}
}
fn pick_random_small_lane(&self) -> Option<&TransmissionLane> {
fn pick_random_lane<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<&TransmissionLane> {
let lanes: Vec<&TransmissionLane> = self.buffer.keys().collect();
lanes.choose(rng).copied()
}
fn pick_random_small_lane<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<&TransmissionLane> {
let lanes: Vec<&TransmissionLane> = self
.buffer
.iter()
.filter(|(_, v)| v.is_small())
.map(|(k, _)| k)
.collect();
lanes.choose(&mut rand::thread_rng()).copied()
lanes.choose(rng).copied()
}
// 2/3 chance to pick from the old lanes
fn pick_random_old_lane(&self) -> Option<TransmissionLane> {
fn pick_random_old_lane<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<TransmissionLane> {
let rand = &mut rand::thread_rng();
if rand.gen_ratio(2, 3) {
let lanes = self.get_oldest_set();
lanes.choose(rand).copied()
} else {
self.pick_random_lane().copied()
self.pick_random_lane(rng).copied()
}
}
fn pop_front_from_lane(&mut self, lane: &TransmissionLane) -> Option<RealMessage> {
fn pop_front_from_lane(&mut self, lane: &TransmissionLane) -> Option<T> {
let real_msgs_queued = self.buffer.get_mut(lane)?;
let real_next = real_msgs_queued.pop_front()?;
real_msgs_queued.messages_transmitted += 1;
@@ -137,19 +167,48 @@ impl TransmissionBuffer {
Some(real_next)
}
pub(crate) fn pop_next_message_at_random(&mut self) -> Option<(TransmissionLane, RealMessage)> {
pub(crate) fn pop_at_most_n_next_messages_at_random(
&mut self,
n: usize,
) -> Option<Vec<(TransmissionLane, T)>> {
// let start = Instant::now();
if self.buffer.is_empty() {
return None;
}
let rng = &mut rand::thread_rng();
let mut items = Vec::with_capacity(n);
while items.len() < n {
let Some(next) = self.pop_next_message_at_random(rng) else {
break
};
items.push(next)
}
// todo!("time time taken");
Some(items)
}
pub(crate) fn pop_next_message_at_random<R: Rng + ?Sized>(
&mut self,
// turns out the caller always have access to some rng, so no point in instantiating new one
rng: &mut R,
) -> Option<(TransmissionLane, T)> {
if self.buffer.is_empty() {
return None;
}
// Very basic heuristic where we prioritize according to small lanes first, the older lanes
// to try to finish lanes when possible, then the rest.
let lane = if let Some(small_lane) = self.pick_random_small_lane() {
let lane = if let Some(small_lane) = self.pick_random_small_lane(rng) {
*small_lane
} else if let Some(old_lane) = self.pick_random_old_lane() {
} else if let Some(old_lane) = self.pick_random_old_lane(rng) {
old_lane
} else {
*self.pick_random_lane()?
*self.pick_random_lane(rng)?
};
let msg = self.pop_front_from_lane(&lane)?;
@@ -171,35 +230,46 @@ impl TransmissionBuffer {
}
}
pub(crate) struct LaneBufferEntry {
pub real_messages: VecDeque<RealMessage>,
pub(crate) struct LaneBufferEntry<T> {
pub items: VecDeque<T>,
pub messages_transmitted: usize,
#[cfg(not(target_arch = "wasm32"))]
pub time_for_last_activity: time::Instant,
#[cfg(target_arch = "wasm32")]
pub time_for_last_activity: wasm_timer::Instant,
pub time_for_last_activity: Instant,
}
impl LaneBufferEntry {
fn new(real_messages: Vec<RealMessage>) -> Self {
impl<T> LaneBufferEntry<T> {
fn new_empty() -> Self {
LaneBufferEntry {
real_messages: real_messages.into(),
items: VecDeque::new(),
messages_transmitted: 0,
time_for_last_activity: get_time_now(),
}
}
fn append(&mut self, real_messages: Vec<RealMessage>) {
self.real_messages.append(&mut real_messages.into());
fn new(items: VecDeque<T>) -> Self {
LaneBufferEntry {
items,
messages_transmitted: 0,
time_for_last_activity: get_time_now(),
}
}
fn push_item(&mut self, item: T) {
self.items.push_back(item);
// I'm not updating time here on purpose. This method is called just after `new_empty`,
// where the time is already set. Furthermore, this method is called there multiple times at once
}
fn extend<I: IntoIterator<Item = T>>(&mut self, items: I) {
self.items.extend(items);
self.time_for_last_activity = get_time_now();
}
fn pop_front(&mut self) -> Option<RealMessage> {
self.real_messages.pop_front()
fn pop_front(&mut self) -> Option<T> {
self.items.pop_front()
}
fn is_small(&self) -> bool {
self.real_messages.len() < 100
self.items.len() < 100
}
fn is_stale(&self) -> bool {
@@ -208,10 +278,10 @@ impl LaneBufferEntry {
}
fn len(&self) -> usize {
self.real_messages.len()
self.items.len()
}
fn is_empty(&self) -> bool {
self.real_messages.is_empty()
self.items.is_empty()
}
}
+7 -6
View File
@@ -176,8 +176,8 @@ impl<T> Config<T> {
self.client.validator_urls = validator_urls;
}
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
self.client.validator_api_urls = validator_api_urls;
pub fn set_custom_nym_apis(&mut self, nym_api_urls: Vec<Url>) {
self.client.nym_api_urls = nym_api_urls;
}
pub fn set_high_default_traffic_volume(&mut self) {
@@ -237,8 +237,8 @@ impl<T> Config<T> {
self.client.validator_urls.clone()
}
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
self.client.validator_api_urls.clone()
pub fn get_nym_api_endpoints(&self) -> Vec<Url> {
self.client.nym_api_urls.clone()
}
pub fn get_gateway_id(&self) -> String {
@@ -425,7 +425,8 @@ pub struct Client<T> {
validator_urls: Vec<Url>,
/// Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls: Vec<Url>,
#[serde(alias = "validator_api_urls")]
nym_api_urls: Vec<Url>,
/// Path to file containing private identity key.
private_identity_key_file: PathBuf,
@@ -476,7 +477,7 @@ impl<T: NymConfig> Default for Client<T> {
id: "".to_string(),
disabled_credentials_mode: true,
validator_urls: vec![],
validator_api_urls: vec![],
nym_api_urls: vec![],
private_identity_key_file: Default::default(),
public_identity_key_file: Default::default(),
private_encryption_key_file: Default::default(),
+2 -2
View File
@@ -30,8 +30,8 @@ pub enum ClientCoreError<B: ReplyStorageBackend> {
#[error("Failed to setup gateway")]
FailedToSetupGateway,
#[error("List of validator apis is empty")]
ListOfValidatorApisIsEmpty,
#[error("List of nym apis is empty")]
ListOfNymApisIsEmpty,
#[error("Could not load existing gateway configuration: {0}")]
CouldNotLoadExistingGatewayConfiguration(std::io::Error),
+4 -4
View File
@@ -24,12 +24,12 @@ pub(super) async fn query_gateway_details<B>(
where
B: ReplyStorageBackend,
{
let validator_api = validator_servers
let nym_api = validator_servers
.choose(&mut thread_rng())
.ok_or(ClientCoreError::ListOfValidatorApisIsEmpty)?;
let validator_client = validator_client::client::ApiClient::new(validator_api.clone());
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let validator_client = validator_client::client::ApiClient::new(nym_api.clone());
log::trace!("Fetching list of gateways from: {}", validator_api);
log::trace!("Fetching list of gateways from: {}", nym_api);
let gateways = validator_client.get_cached_gateways().await?;
let valid_gateways = gateways
.into_iter()
+5 -8
View File
@@ -96,7 +96,7 @@ where
{
println!("Configuring gateway");
let gateway =
query_gateway_details(config.get_validator_api_endpoints(), user_chosen_gateway_id).await?;
query_gateway_details(config.get_nym_api_endpoints(), user_chosen_gateway_id).await?;
log::debug!("Querying gateway gives: {}", gateway);
// Registering with gateway by setting up and writing shared keys to disk
@@ -120,11 +120,8 @@ where
T: NymConfig,
{
println!("Using gateway provided by user, keeping existing keys");
let gateway = query_gateway_details(
config.get_validator_api_endpoints(),
Some(user_chosen_gateway_id),
)
.await?;
let gateway =
query_gateway_details(config.get_nym_api_endpoints(), Some(user_chosen_gateway_id)).await?;
log::debug!("Querying gateway gives: {}", gateway);
Ok(gateway.into())
}
@@ -209,8 +206,8 @@ pub fn output_to_json<T: Serialize>(init_results: &T, output_file: &str) {
match std::fs::File::create(output_file) {
Ok(file) => match serde_json::to_writer_pretty(file, init_results) {
Ok(_) => println!("Saved: {}", output_file),
Err(err) => eprintln!("Could not save {}: {}", output_file, err),
Err(err) => eprintln!("Could not save {}: {err}", output_file),
},
Err(err) => eprintln!("Could not save {}: {}", output_file, err),
Err(err) => eprintln!("Could not save {}: {err}", output_file),
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.4"
version = "1.1.5"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+2 -2
View File
@@ -31,8 +31,8 @@ validator_urls = [
]
# Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [
{{#each client.validator_api_urls }}
nym_api_urls = [
{{#each client.nym_api_urls }}
'{{this}}',
{{/each}}
]
+30 -21
View File
@@ -1,6 +1,8 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use crate::client::config::Config;
use crate::error::ClientError;
use crate::websocket;
@@ -11,6 +13,7 @@ use client_core::client::base_client::{
use client_core::client::inbound_messages::InputMessage;
use client_core::client::key_manager::KeyManager;
use client_core::client::received_buffer::{ReceivedBufferMessage, ReconstructedMessagesReceiver};
use client_core::client::replies::reply_controller::requests::ReplyControllerSender;
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
use futures::channel::mpsc;
use gateway_client::bandwidth::BandwidthController;
@@ -18,7 +21,7 @@ use log::*;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
use nymsphinx::receiver::ReconstructedMessage;
use task::{wait_for_signal, ShutdownNotifier};
use task::TaskManager;
pub(crate) mod config;
@@ -56,7 +59,7 @@ impl SocketClient {
.expect("No nymd validator endpoint provided");
let api_url = config
.get_base()
.get_validator_api_endpoints()
.get_nym_api_endpoints()
.pop()
.expect("No validator api endpoint provided");
// overwrite env configuration with config URLs
@@ -84,52 +87,51 @@ impl SocketClient {
config: &Config,
client_input: ClientInput,
client_output: ClientOutput,
self_address: Recipient,
self_address: &Recipient,
reply_controller_sender: ReplyControllerSender,
shutdown: task::TaskClient,
) {
info!("Starting websocket listener...");
let ClientInput {
shared_lane_queue_lengths,
connection_command_sender,
input_sender,
} = client_input;
let received_buffer_request_sender = client_output.received_buffer_request_sender;
let ClientOutput {
shared_lane_queue_lengths,
received_buffer_request_sender,
} = client_output;
let websocket_handler = websocket::Handler::new(
let websocket_handler = websocket::HandlerBuilder::new(
input_sender,
connection_command_sender,
received_buffer_request_sender,
self_address,
shared_lane_queue_lengths,
reply_controller_sender,
);
websocket::Listener::new(config.get_listening_port()).start(websocket_handler);
websocket::Listener::new(config.get_listening_port()).start(websocket_handler, shutdown);
}
/// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent)
pub async fn run_socket_forever(self) -> Result<(), ClientError> {
pub async fn run_socket_forever(self) -> Result<(), Box<dyn Error + Send + Sync>> {
let mut shutdown = self.start_socket().await?;
wait_for_signal().await;
println!(
"Received signal - the client will terminate now (threads are not yet nicely stopped, if you see stack traces that's alright)."
);
let res = task::wait_for_signal_and_error(&mut shutdown).await;
log::info!("Sending shutdown");
shutdown.signal_shutdown().ok();
// Some of these components have shutdown signalling implemented as part of socks5 work,
// but since it's not fully implemented (yet) for all the components of the native client,
// we don't try to wait and instead just stop immediately.
log::info!("Waiting for tasks to finish... (Press ctrl-c to force)");
shutdown.wait_for_shutdown().await;
log::info!("Stopping nym-client");
Ok(())
res
}
pub async fn start_socket(self) -> Result<ShutdownNotifier, ClientError> {
pub async fn start_socket(self) -> Result<TaskManager, ClientError> {
if !self.config.get_socket_type().is_websocket() {
return Err(ClientError::InvalidSocketMode);
}
@@ -150,12 +152,19 @@ impl SocketClient {
let client_input = started_client.client_input.register_producer();
let client_output = started_client.client_output.register_consumer();
Self::start_websocket_listener(&self.config, client_input, client_output, self_address);
Self::start_websocket_listener(
&self.config,
client_input,
client_output,
&self_address,
started_client.reply_controller_sender,
started_client.task_manager.subscribe(),
);
info!("Client startup finished!");
info!("The address of this client is: {}", self_address);
Ok(started_client.shutdown_notifier)
Ok(started_client.task_manager)
}
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
@@ -192,7 +201,7 @@ impl SocketClient {
Ok(DirectClient {
client_input,
reconstructed_receiver,
_shutdown_notifier: started_client.shutdown_notifier,
_shutdown_notifier: started_client.task_manager,
})
}
}
@@ -202,7 +211,7 @@ pub struct DirectClient {
reconstructed_receiver: ReconstructedMessagesReceiver,
// we need to keep reference to this guy otherwise things will start dropping
_shutdown_notifier: ShutdownNotifier,
_shutdown_notifier: TaskManager,
}
impl DirectClient {
+5 -4
View File
@@ -1,8 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use crate::client::config::{Config, SocketType};
use crate::error::ClientError;
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use completions::{fig_generate, ArgShell};
@@ -86,7 +87,7 @@ pub(crate) struct OverrideConfig {
enabled_credentials_mode: bool,
}
pub(crate) async fn execute(args: &Cli) -> Result<(), ClientError> {
pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
let bin_name = "nym-native-client";
match &args.command {
@@ -114,13 +115,13 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
if let Some(raw_validators) = args.api_validators {
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
.set_custom_nym_apis(config::parse_validators(&raw_validators));
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
.expect("api validator not set");
config
.get_base_mut()
.set_custom_validator_apis(config::parse_validators(&raw_validators));
.set_custom_nym_apis(config::parse_validators(&raw_validators));
}
if args.disable_socket {
+6 -4
View File
@@ -1,6 +1,8 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use crate::{
client::{config::Config, SocketClient},
commands::{override_config, OverrideConfig},
@@ -89,14 +91,14 @@ fn version_check(cfg: &Config) -> bool {
}
}
pub(crate) async fn execute(args: &Run) -> Result<(), ClientError> {
pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn Error + Send + Sync>> {
let id = &args.id;
let mut config = match Config::load_from_file(Some(id)) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
return Err(ClientError::FailedToLoadConfig(id.to_string()));
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
return Err(Box::new(ClientError::FailedToLoadConfig(id.to_string())));
}
};
@@ -109,7 +111,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), ClientError> {
if !version_check(&config) {
error!("failed the local version check");
return Err(ClientError::FailedLocalVersionCheck);
return Err(Box::new(ClientError::FailedLocalVersionCheck));
}
SocketClient::new(config).run_socket_forever().await
+3 -3
View File
@@ -59,7 +59,7 @@ pub(crate) struct Upgrade {
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {:?}", err);
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
@@ -110,7 +110,7 @@ fn minor_0_12_upgrade(
.set_custom_version(to_version.to_string().as_ref());
config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {:?}", err);
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
@@ -146,7 +146,7 @@ pub(crate) fn execute(args: &Upgrade) {
let id = &args.id;
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {:?}", err);
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
+3 -2
View File
@@ -1,8 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::error::Error;
use clap::{crate_version, Parser};
use error::ClientError;
use logging::setup_logging;
use network_defaults::setup_env;
@@ -12,7 +13,7 @@ pub mod error;
pub mod websocket;
#[tokio::main]
async fn main() -> Result<(), ClientError> {
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
setup_logging();
println!("{}", banner());
+115 -102
View File
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use client_connections::{
ConnectionCommand, ConnectionCommandSender, LaneQueueLengths, TransmissionLane,
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
};
use client_core::client::replies::reply_controller::requests::ReplyControllerSender;
use client_core::client::{
inbound_messages::{InputMessage, InputMessageSender},
received_buffer::{
@@ -16,7 +17,9 @@ use log::*;
use nymsphinx::addressing::clients::Recipient;
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
use nymsphinx::receiver::ReconstructedMessage;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::time::Instant;
use tokio_tungstenite::{
accept_async,
tungstenite::{protocol::Message as WsMessage, Error as WsError},
@@ -35,19 +38,36 @@ impl Default for ReceivedResponseType {
}
}
pub(crate) struct Handler {
pub(crate) struct HandlerBuilder {
msg_input: InputMessageSender,
client_connection_tx: ConnectionCommandSender,
buffer_requester: ReceivedBufferRequestSender,
self_full_address: Recipient,
socket: Option<WebSocketStream<TcpStream>>,
received_response_type: ReceivedResponseType,
lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender,
}
// clone is used to use handler on a new connection, which initially is `None`
impl Clone for Handler {
fn clone(&self) -> Self {
impl HandlerBuilder {
pub(crate) fn new(
msg_input: InputMessageSender,
client_connection_tx: ConnectionCommandSender,
buffer_requester: ReceivedBufferRequestSender,
self_full_address: &Recipient,
lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender,
) -> Self {
Self {
msg_input,
client_connection_tx,
buffer_requester,
self_full_address: *self_full_address,
lane_queue_lengths,
reply_controller_sender,
}
}
// TODO: make sure we only ever have one active handler
pub fn create_active_handler(&self) -> Handler {
Handler {
msg_input: self.msg_input.clone(),
client_connection_tx: self.client_connection_tx.clone(),
@@ -56,10 +76,22 @@ impl Clone for Handler {
socket: None,
received_response_type: Default::default(),
lane_queue_lengths: self.lane_queue_lengths.clone(),
reply_controller_sender: self.reply_controller_sender.clone(),
}
}
}
pub(crate) struct Handler {
msg_input: InputMessageSender,
client_connection_tx: ConnectionCommandSender,
buffer_requester: ReceivedBufferRequestSender,
self_full_address: Recipient,
socket: Option<WebSocketStream<TcpStream>>,
received_response_type: ReceivedResponseType,
lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender,
}
impl Drop for Handler {
fn drop(&mut self) {
if self
@@ -73,22 +105,46 @@ impl Drop for Handler {
}
impl Handler {
pub(crate) fn new(
msg_input: InputMessageSender,
client_connection_tx: ConnectionCommandSender,
buffer_requester: ReceivedBufferRequestSender,
self_full_address: Recipient,
lane_queue_lengths: LaneQueueLengths,
) -> Self {
Handler {
msg_input,
client_connection_tx,
buffer_requester,
self_full_address,
socket: None,
received_response_type: Default::default(),
lane_queue_lengths,
async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> Option<ServerResponse> {
let req_start = Instant::now();
// get the base queue length
// Note that this does _NOT_ take into account the packets that have been received but not
// yet reach `OutQueueControl`, so it might be a tad low.
let conn_lane = TransmissionLane::ConnectionId(connection_id);
let Ok(base_length) = self
.lane_queue_lengths
.lock()
.map(|guard| guard.get(&conn_lane).unwrap_or_default()) else {
// I'd argue we should panic here as this error it not recoverable
error!("The lane queue length lock is poisoned!!");
return None
};
// get the number of pending replies waiting for reply surbs
let reply_queue_length = self
.reply_controller_sender
.get_lane_queue_length(connection_id)
.await;
let queue_length = base_length + reply_queue_length;
let time_taken = req_start.elapsed();
let msg =
format!("it took {time_taken:?} to get lane length for connection {connection_id}. The length is: {queue_length} = {base_length} (already queued up) + {reply_queue_length} (waiting for reply SURBs)");
if time_taken > Duration::from_millis(1) {
info!("{msg}");
} else if time_taken > Duration::from_millis(10) {
warn!("{msg}");
} else if time_taken > Duration::from_millis(50) {
error!("{msg}");
}
Some(ServerResponse::LaneQueueLength {
lane: connection_id,
queue_length,
})
}
async fn handle_send(
@@ -115,27 +171,11 @@ impl Handler {
.expect("InputMessageReceiver has stopped receiving!");
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
let connection_id = match lane {
TransmissionLane::General
| TransmissionLane::ReplySurbRequest
| TransmissionLane::Retransmission
| TransmissionLane::AdditionalReplySurbs => return None,
TransmissionLane::ConnectionId(id) => id,
let TransmissionLane::ConnectionId(connection_id) = lane else {
return None
};
// on receiving a send, we reply back the current lane queue length for that connection id.
// Note that this does _NOT_ take into account the packets that have been received but not
// yet reach `OutQueueControl`, so it might be a tad low.
if let Ok(lane_queue_lengths) = self.lane_queue_lengths.lock() {
let queue_length = lane_queue_lengths.get(&lane).unwrap_or(0);
return Some(ServerResponse::LaneQueueLength {
lane: connection_id,
queue_length,
});
}
log::warn!("Failed to get the lane queue length lock, not responding back with the current queue length");
None
self.get_lane_queue_length(connection_id).await
}
async fn handle_send_anonymous(
@@ -162,27 +202,11 @@ impl Handler {
.expect("InputMessageReceiver has stopped receiving!");
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
let connection_id = match lane {
TransmissionLane::General
| TransmissionLane::ReplySurbRequest
| TransmissionLane::Retransmission
| TransmissionLane::AdditionalReplySurbs => return None,
TransmissionLane::ConnectionId(id) => id,
let TransmissionLane::ConnectionId(connection_id) = lane else {
return None
};
// on receiving a send, we reply back the current lane queue length for that connection id.
// Note that this does _NOT_ take into account the packets that have been received but not
// yet reach `OutQueueControl`, so it might be a tad low.
if let Ok(lane_queue_lengths) = self.lane_queue_lengths.lock() {
let queue_length = lane_queue_lengths.get(&lane).unwrap_or(0);
return Some(ServerResponse::LaneQueueLength {
lane: connection_id,
queue_length,
});
}
log::warn!("Failed to get the lane queue length lock, not responding back with the current queue length");
None
self.get_lane_queue_length(connection_id).await
}
async fn handle_reply(
@@ -205,27 +229,11 @@ impl Handler {
.expect("InputMessageReceiver has stopped receiving!");
// Only reply back with a `LaneQueueLength` if the sender providided a connection id
let connection_id = match lane {
TransmissionLane::General
| TransmissionLane::ReplySurbRequest
| TransmissionLane::Retransmission
| TransmissionLane::AdditionalReplySurbs => return None,
TransmissionLane::ConnectionId(id) => id,
let TransmissionLane::ConnectionId(connection_id) = lane else {
return None
};
// on receiving a send, we reply back the current lane queue length for that connection id.
// Note that this does _NOT_ take into account the packets that have been received but not
// yet reach `OutQueueControl`, so it might be a tad low.
if let Ok(lane_queue_lengths) = self.lane_queue_lengths.lock() {
let queue_length = lane_queue_lengths.get(&lane).unwrap_or(0);
return Some(ServerResponse::LaneQueueLength {
lane: connection_id,
queue_length,
});
}
log::warn!("Failed to get the lane queue length lock, not responding back with the current queue length");
None
self.get_lane_queue_length(connection_id).await
}
fn handle_self_address(&self) -> ServerResponse {
@@ -239,20 +247,8 @@ impl Handler {
None
}
fn handle_get_lane_queue_length(&self, connection_id: u64) -> Option<ServerResponse> {
let Ok(lane_queue_lengths) = self.lane_queue_lengths.lock() else {
log::warn!(
"Failed to get the lane queue length lock, not responding back with the current queue length"
);
return None;
};
let lane = TransmissionLane::ConnectionId(connection_id);
let queue_length = lane_queue_lengths.get(&lane).unwrap_or(0);
Some(ServerResponse::LaneQueueLength {
lane: connection_id,
queue_length,
})
async fn handle_get_lane_queue_length(&self, connection_id: u64) -> Option<ServerResponse> {
self.get_lane_queue_length(connection_id).await
}
async fn handle_request(&mut self, request: ClientRequest) -> Option<ServerResponse> {
@@ -281,7 +277,7 @@ impl Handler {
ClientRequest::SelfAddress => Some(self.handle_self_address()),
ClientRequest::ClosedConnection(id) => self.handle_closed_connection(id),
ClientRequest::GetLaneQueueLength(id) => self.handle_get_lane_queue_length(id),
ClientRequest::GetLaneQueueLength(id) => self.handle_get_lane_queue_length(id).await,
}
}
@@ -362,8 +358,12 @@ impl Handler {
}
}
async fn listen_for_requests(&mut self, mut msg_receiver: ReconstructedMessagesReceiver) {
loop {
async fn listen_for_requests(
&mut self,
mut msg_receiver: ReconstructedMessagesReceiver,
mut task_client: task::TaskClient,
) {
while !task_client.is_shutdown() {
tokio::select! {
// we can either get a client request from the websocket
socket_msg = self.next_websocket_request() => {
@@ -373,7 +373,7 @@ impl Handler {
let socket_msg = match socket_msg.unwrap() {
Ok(socket_msg) => socket_msg,
Err(err) => {
warn!("failed to obtain message from websocket stream! stopping connection handler: {}", err);
warn!("failed to obtain message from websocket stream! stopping connection handler: {err}");
break;
}
};
@@ -397,21 +397,33 @@ impl Handler {
error!("mix messages sender was unexpectedly closed! this shouldn't have ever happened! (unless we're shutting down - TODO: implement proper graceful shutdown handler)");
return
};
if let Err(e) = self.push_websocket_received_plaintexts(mix_messages).await {
warn!("failed to send sphinx packets back to the client - {:?}, assuming the connection is dead", e);
if let Err(err) = self.push_websocket_received_plaintexts(mix_messages).await {
warn!("failed to send sphinx packets back to the client - {err}, assuming the connection is dead");
break;
}
}
_ = task_client.recv() => {
log::trace!("Websocket handler: Received shutdown");
}
}
}
log::debug!("Websocket handler: Exiting");
}
// consume self to make sure `drop` is called after this is done
pub(crate) async fn handle_connection(mut self, socket: TcpStream) {
pub(crate) async fn handle_connection(
mut self,
socket: TcpStream,
mut task_client: task::TaskClient,
) {
// We don't want a crash in the connection handler to trigger a shutdown of the whole
// process.
task_client.mark_as_success();
let ws_stream = match accept_async(socket).await {
Ok(ws_stream) => ws_stream,
Err(err) => {
warn!("error while performing the websocket handshake - {:?}", err);
warn!("error while performing the websocket handshake - {err}");
return;
}
};
@@ -426,7 +438,8 @@ impl Handler {
))
.expect("the buffer request failed!");
self.listen_for_requests(reconstructed_receiver).await;
self.listen_for_requests(reconstructed_receiver, task_client)
.await;
}
}
+28 -9
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::handler::Handler;
use super::handler::HandlerBuilder;
use log::*;
use std::{net::SocketAddr, process, sync::Arc};
use tokio::io::AsyncWriteExt;
@@ -32,11 +32,11 @@ impl Listener {
}
}
pub(crate) async fn run(&mut self, handler: Handler) {
pub(crate) async fn run(&mut self, handler: HandlerBuilder, mut task_client: task::TaskClient) {
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
Ok(listener) => listener,
Err(err) => {
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
error!("Failed to bind to {} - {err}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address);
process::exit(1);
}
};
@@ -45,10 +45,23 @@ impl Listener {
loop {
tokio::select! {
// When the handler finishes we check if shutdown is signalled
_ = notify.notified() => {
if task_client.is_shutdown() {
log::trace!("Websocket listener: detected shutdown after connection closed");
break;
}
// our connection terminated - we are open to a new one now!
self.state = State::AwaitingConnection;
}
// ... but when there is no connected client at the time of shutdown being
// signalled, we handle it here.
_ = task_client.recv() => {
if !self.state.is_connected() {
log::trace!("Not connected: shutting down");
break;
}
}
new_conn = tcp_listener.accept() => {
match new_conn {
Ok((mut socket, remote_addr)) => {
@@ -63,31 +76,37 @@ impl Listener {
Ok(_) => trace!(
"closed the connection between attempting websocket handshake"
),
Err(e) => warn!("failed to cleanly close the connection - {:?}", e),
Err(err) => warn!("failed to cleanly close the connection - {err}"),
};
} else {
// even though we're spawning a new task with the handler here, we will only ever spawn a single one.
// it's done so that any new connections to this listener could be rejected rather than left
// hanging because the executor doesn't come back here
let notify_clone = Arc::clone(&notify);
let fresh_handler = handler.clone();
let fresh_handler = handler.create_active_handler();
let task_client_handler = task_client.clone();
tokio::spawn(async move {
fresh_handler.handle_connection(socket).await;
fresh_handler.handle_connection(socket, task_client_handler).await;
notify_clone.notify_one();
});
self.state = State::Connected;
}
}
Err(e) => warn!("failed to get client: {:?}", e),
Err(err) => warn!("failed to get client: {err}"),
}
}
}
}
log::debug!("Websocket listener: Exiting");
}
pub(crate) fn start(mut self, handler: Handler) -> JoinHandle<()> {
pub(crate) fn start(
mut self,
handler: HandlerBuilder,
shutdown: task::TaskClient,
) -> JoinHandle<()> {
info!("Running websocket on {:?}", self.address.to_string());
tokio::spawn(async move { self.run(handler).await })
tokio::spawn(async move { self.run(handler, shutdown).await })
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub(crate) use handler::Handler;
pub(crate) use handler::HandlerBuilder;
pub(crate) use listener::Listener;
pub(crate) mod handler;
@@ -132,7 +132,7 @@ impl ClientRequest {
Err(err) => {
return Err(error::Error::new(
ErrorKind::MalformedRequest,
format!("malformed recipient: {:?}", err),
format!("malformed recipient: {err}"),
))
}
};
@@ -210,7 +210,7 @@ impl ClientRequest {
Err(err) => {
return Err(error::Error::new(
ErrorKind::MalformedRequest,
format!("malformed recipient: {:?}", err),
format!("malformed recipient: {err}"),
))
}
};
@@ -173,7 +173,7 @@ impl ServerResponse {
Err(err) => {
return Err(error::Error::new(
ErrorKind::MalformedResponse,
format!("malformed Recipient: {:?}", err),
format!("malformed Recipient: {err}"),
))
}
};
@@ -249,7 +249,7 @@ impl ServerResponse {
Err(err) => {
return Err(error::Error::new(
ErrorKind::MalformedResponse,
format!("malformed error message: {:?}", err),
format!("malformed error message: {err}"),
))
}
};
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.4"
version = "1.1.5"
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"
+2 -2
View File
@@ -31,8 +31,8 @@ validator_urls = [
]
# Addresses to APIs running on validator from which the client gets the view of the network.
validator_api_urls = [
{{#each client.validator_api_urls }}
nym_api_urls = [
{{#each client.nym_api_urls }}
'{{this}}',
{{/each}}
]
+11 -9
View File
@@ -19,7 +19,7 @@ use gateway_client::bandwidth::BandwidthController;
use log::*;
use nymsphinx::addressing::clients::Recipient;
use std::error::Error;
use task::{wait_for_signal_and_error, ShutdownListener, ShutdownNotifier};
use task::{wait_for_signal_and_error, TaskClient, TaskManager};
pub mod config;
@@ -67,7 +67,7 @@ impl NymClient {
.expect("No nymd validator endpoint provided");
let api_url = config
.get_base()
.get_validator_api_endpoints()
.get_nym_api_endpoints()
.pop()
.expect("No validator api endpoint provided");
// overwrite env configuration with config URLs
@@ -96,19 +96,21 @@ impl NymClient {
client_input: ClientInput,
client_output: ClientOutput,
self_address: Recipient,
shutdown: ShutdownListener,
shutdown: TaskClient,
) {
info!("Starting socks5 listener...");
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
let allowed_users: Vec<User> = Vec::new();
let ClientInput {
shared_lane_queue_lengths,
connection_command_sender,
input_sender,
} = client_input;
let received_buffer_request_sender = client_output.received_buffer_request_sender;
let ClientOutput {
shared_lane_queue_lengths,
received_buffer_request_sender,
} = client_output;
let authenticator = Authenticator::new(auth_methods, allowed_users);
let mut sphinx_socks = SphinxSocksServer::new(
@@ -164,7 +166,7 @@ impl NymClient {
let mut shutdown = self.start().await?;
// Listen to status messages from task, that we forward back to the caller
shutdown.start_status_listener(sender);
shutdown.start_status_listener(sender).await;
let res = tokio::select! {
biased;
@@ -200,7 +202,7 @@ impl NymClient {
res
}
pub async fn start(self) -> Result<ShutdownNotifier, Socks5ClientError> {
pub async fn start(self) -> Result<TaskManager, Socks5ClientError> {
let base_builder = BaseClientBuilder::new_from_base_config(
self.config.get_base(),
self.key_manager,
@@ -222,12 +224,12 @@ impl NymClient {
client_input,
client_output,
self_address,
started_client.shutdown_notifier.subscribe(),
started_client.task_manager.subscribe(),
);
info!("Client startup finished!");
info!("The address of this client is: {}", self_address);
Ok(started_client.shutdown_notifier)
Ok(started_client.task_manager)
}
}
+2 -2
View File
@@ -116,11 +116,11 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
if let Some(raw_validators) = args.api_validators {
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
.set_custom_nym_apis(parse_validators(&raw_validators));
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
config
.get_base_mut()
.set_custom_validator_apis(parse_validators(&raw_validators));
.set_custom_nym_apis(parse_validators(&raw_validators));
}
if args.use_anonymous_sender_tag {
+4 -4
View File
@@ -43,9 +43,9 @@ pub(crate) struct Run {
#[clap(long)]
nymd_validators: Option<String>,
/// Comma separated list of rest endpoints of the API validators
/// Comma separated list of rest endpoints of the Nym APIs
#[clap(long)]
api_validators: Option<String>,
nym_apis: Option<String>,
/// Port for the socket to listen on
#[clap(short, long)]
@@ -71,7 +71,7 @@ impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self {
OverrideConfig {
nymd_validators: run_config.nymd_validators,
api_validators: run_config.api_validators,
api_validators: run_config.nym_apis,
port: run_config.port,
use_anonymous_sender_tag: run_config.use_anonymous_sender_tag,
fastmode: run_config.fastmode,
@@ -110,7 +110,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), Box<dyn std::error::Error
let mut config = match Config::load_from_file(Some(id)) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err);
error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {err})", id);
return Err(Box::new(Socks5ClientError::FailedToLoadConfig(
id.to_string(),
)));
+3 -3
View File
@@ -58,7 +58,7 @@ pub(crate) struct Upgrade {
fn parse_config_version(config: &Config) -> Version {
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
eprintln!("failed to parse client version! - {:?}", err);
eprintln!("failed to parse client version! - {err}");
process::exit(1)
});
@@ -109,7 +109,7 @@ fn minor_0_12_upgrade(
.set_custom_version(to_version.to_string().as_ref());
config.save_to_file(None).unwrap_or_else(|err| {
eprintln!("failed to overwrite config file! - {:?}", err);
eprintln!("failed to overwrite config file! - {err}");
print_failed_upgrade(config_version, &to_version);
process::exit(1);
});
@@ -145,7 +145,7 @@ pub(crate) fn execute(args: &Upgrade) {
let id = &args.id;
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
eprintln!("failed to load existing config file! - {:?}", err);
eprintln!("failed to load existing config file! - {err}");
process::exit(1)
});
+7
View File
@@ -1,6 +1,7 @@
use crate::socks::types::SocksProxyError;
use client_core::client::replies::reply_storage::fs_backend;
use client_core::error::ClientCoreError;
use socks5_requests::ConnectionId;
#[derive(thiserror::Error, Debug)]
pub enum Socks5ClientError {
@@ -21,4 +22,10 @@ pub enum Socks5ClientError {
#[error("Fail to bind address")]
FailToBindAddress,
#[error("Network requester: connection id {connection_id}: {error}")]
NetworkRequesterError {
connection_id: ConnectionId,
error: String,
},
}
+4 -4
View File
@@ -20,7 +20,7 @@ use socks5_requests::{ConnectionId, Message, RemoteAddress, Request};
use std::io;
use std::net::SocketAddr;
use std::pin::Pin;
use task::ShutdownListener;
use task::TaskClient;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
use tokio::{self, net::TcpStream};
use std::time::{SystemTime, UNIX_EPOCH};
@@ -165,7 +165,7 @@ pub(crate) struct SocksClient {
self_address: Recipient,
started_proxy: bool,
lane_queue_lengths: LaneQueueLengths,
shutdown_listener: ShutdownListener,
shutdown_listener: TaskClient,
}
impl Drop for SocksClient {
@@ -191,7 +191,7 @@ impl SocksClient {
controller_sender: ControllerSender,
self_address: &Recipient,
lane_queue_lengths: LaneQueueLengths,
mut shutdown_listener: ShutdownListener,
mut shutdown_listener: TaskClient,
) -> Self {
// If this task fails and exits, we don't want to send shutdown signal
shutdown_listener.mark_as_success();
@@ -221,7 +221,7 @@ impl SocksClient {
}
pub async fn send_error(&mut self, err: SocksProxyError) -> Result<(), SocksProxyError> {
let error_text = format!("{}", err);
let error_text = format!("{err}");
let Some(ref version) = self.socks_version else {
log::error!("Trying to send error without knowing the version");
return Ok(());
+26 -15
View File
@@ -9,13 +9,15 @@ use client_core::client::received_buffer::{ReceivedBufferMessage, ReceivedBuffer
use nymsphinx::receiver::ReconstructedMessage;
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
use socks5_requests::Message;
use task::ShutdownListener;
use task::TaskClient;
use crate::error::Socks5ClientError;
pub(crate) struct MixnetResponseListener {
buffer_requester: ReceivedBufferRequestSender,
mix_response_receiver: ReconstructedMessagesReceiver,
controller_sender: ControllerSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl Drop for MixnetResponseListener {
@@ -25,9 +27,9 @@ impl Drop for MixnetResponseListener {
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
{
if self.shutdown.is_shutdown_poll() {
log::debug!("The buffer request failed: {}", err);
log::debug!("The buffer request failed: {err}");
} else {
log::error!("The buffer request failed: {}", err);
log::error!("The buffer request failed: {err}");
}
}
}
@@ -37,7 +39,7 @@ impl MixnetResponseListener {
pub(crate) fn new(
buffer_requester: ReceivedBufferRequestSender,
controller_sender: ControllerSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
let (mix_response_sender, mix_response_receiver) = mpsc::unbounded();
buffer_requester
@@ -52,7 +54,10 @@ impl MixnetResponseListener {
}
}
async fn on_message(&self, reconstructed_message: ReconstructedMessage) {
fn on_message(
&self,
reconstructed_message: ReconstructedMessage,
) -> Result<(), Socks5ClientError> {
let raw_message = reconstructed_message.message;
if reconstructed_message.sender_tag.is_some() {
warn!("this message was sent anonymously - it couldn't have come from the service provider");
@@ -60,12 +65,12 @@ impl MixnetResponseListener {
let response = match Message::try_from_bytes(&raw_message) {
Err(err) => {
warn!("failed to parse received response - {:?}", err);
return;
warn!("failed to parse received response - {err}");
return Ok(());
}
Ok(Message::Request(_)) => {
warn!("unexpected request");
return;
return Ok(());
}
Ok(Message::Response(data)) => data,
Ok(Message::NetworkRequesterResponse(r)) => {
@@ -73,7 +78,10 @@ impl MixnetResponseListener {
"Network requester failed on connection id {} with error: {}",
r.connection_id, r.network_requester_error
);
return;
return Err(Socks5ClientError::NetworkRequesterError {
connection_id: r.connection_id,
error: r.network_requester_error,
});
}
};
@@ -84,18 +92,21 @@ impl MixnetResponseListener {
response.is_closed,
))
.unwrap();
Ok(())
}
pub(crate) async fn run(&mut self) {
while !self.shutdown.is_shutdown() {
tokio::select! {
received_responses = self.mix_response_receiver.next() => match received_responses {
Some(received_responses) => {
received_responses = self.mix_response_receiver.next() => {
if let Some(received_responses) = received_responses {
for reconstructed_message in received_responses {
self.on_message(reconstructed_message).await;
if let Err(err) = self.on_message(reconstructed_message) {
self.shutdown.send_status_msg(Box::new(err));
}
}
},
None => {
} else {
log::trace!("MixnetResponseListener: Stopping since channel closed");
break;
}
+4 -4
View File
@@ -13,7 +13,7 @@ use nymsphinx::addressing::clients::Recipient;
use proxy_helpers::connection_controller::{BroadcastActiveConnections, Controller};
use std::net::SocketAddr;
use tap::TapFallible;
use task::ShutdownListener;
use task::TaskClient;
use tokio::net::TcpListener;
/// A Socks5 server that listens for connections.
@@ -24,7 +24,7 @@ pub struct SphinxSocksServer {
self_address: Recipient,
client_config: client::Config,
lane_queue_lengths: LaneQueueLengths,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl SphinxSocksServer {
@@ -36,7 +36,7 @@ impl SphinxSocksServer {
self_address: Recipient,
lane_queue_lengths: LaneQueueLengths,
client_config: client::Config,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
// hardcode ip as we (presumably) ONLY want to listen locally. If we change it, we can
// just modify the config
@@ -103,7 +103,7 @@ impl SphinxSocksServer {
tokio::spawn(async move {
if let Err(err) = client.run().await {
error!("Error! {}", err);
error!("Error! {err}");
if client.send_error(err).await.is_err() {
warn!("Failed to send error code");
};
+1 -1
View File
@@ -40,7 +40,7 @@ pub enum SocksProxyError {
impl std::fmt::Display for SocksProxyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SocksProxyError::GenericError(err) => write!(f, "GenericError - {}", err),
SocksProxyError::GenericError(err) => write!(f, "GenericError - {err}"),
SocksProxyError::UnsupportedProxyVersion(version) => {
write!(f, "Unsupported proxy version {}", version)
}
+4 -4
View File
@@ -86,7 +86,7 @@ export default class ValidatorClient implements INymClient {
static async connect(
mnemonic: string,
nymdUrl: string,
validatorApiUrl: string,
nymApiUrl: string,
prefix: string,
mixnetContract: string,
vestingContract: string,
@@ -94,19 +94,19 @@ export default class ValidatorClient implements INymClient {
): Promise<ValidatorClient> {
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix, denom);
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, nymApiUrl, prefix, denom);
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract, denom);
}
static async connectForQuery(
nymdUrl: string,
validatorApiUrl: string,
nymApiUrl: string,
prefix: string,
mixnetContract: string,
vestingContract: string,
denom: string,
): Promise<ValidatorClient> {
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
const queryClient = await QueryClient.connectWithNym(nymdUrl, nymApiUrl);
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract, denom);
}
@@ -6,13 +6,13 @@
import axios from 'axios';
import { GatewayBond, MixNodeBond } from './types';
export const VALIDATOR_API_VERSION = '/v1';
export const VALIDATOR_API_GATEWAYS_PATH = `${VALIDATOR_API_VERSION}/gateways`;
export const VALIDATOR_API_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes`;
export const VALIDATOR_API_ACTIVE_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes/active`;
export const VALIDATOR_API_REWARDED_MIXNODES_PATH = `${VALIDATOR_API_VERSION}/mixnodes/rewarded`;
export const NYM_API_VERSION = '/v1';
export const NYM_API_GATEWAYS_PATH = `${NYM_API_VERSION}/gateways`;
export const NYM_API_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes`;
export const NYM_API_ACTIVE_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes/active`;
export const NYM_API_REWARDED_MIXNODES_PATH = `${NYM_API_VERSION}/mixnodes/rewarded`;
export interface IValidatorApiQuery {
export interface INymApiQuery {
getCachedMixnodes(): Promise<MixNodeBond[]>;
getCachedGateways(): Promise<GatewayBond[]>;
@@ -22,16 +22,16 @@ export interface IValidatorApiQuery {
getRewardedMixnodes(): Promise<MixNodeBond[]>;
}
export default class ValidatorApiQuerier implements IValidatorApiQuery {
validatorApiUrl: string;
export default class NymApiQuerier implements INymApiQuery {
nymApiUrl: string;
constructor(validatorApiUrl: string) {
this.validatorApiUrl = validatorApiUrl;
constructor(nymApiUrl: string) {
this.nymApiUrl = nymApiUrl;
}
async getCachedMixnodes(): Promise<MixNodeBond[]> {
const url = new URL(this.validatorApiUrl);
url.pathname += VALIDATOR_API_MIXNODES_PATH;
const url = new URL(this.nymApiUrl);
url.pathname += NYM_API_MIXNODES_PATH;
const response = await axios.get(url.toString());
if (response.status === 200) {
@@ -41,8 +41,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
}
async getCachedGateways(): Promise<GatewayBond[]> {
const url = new URL(this.validatorApiUrl);
url.pathname += VALIDATOR_API_GATEWAYS_PATH;
const url = new URL(this.nymApiUrl);
url.pathname += NYM_API_GATEWAYS_PATH;
const response = await axios.get(url.toString());
if (response.status === 200) {
@@ -52,8 +52,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
}
async getActiveMixnodes(): Promise<MixNodeBond[]> {
const url = new URL(this.validatorApiUrl);
url.pathname += VALIDATOR_API_ACTIVE_MIXNODES_PATH;
const url = new URL(this.nymApiUrl);
url.pathname += NYM_API_ACTIVE_MIXNODES_PATH;
const response = await axios.get(url.toString());
if (response.status === 200) {
@@ -63,8 +63,8 @@ export default class ValidatorApiQuerier implements IValidatorApiQuery {
}
async getRewardedMixnodes(): Promise<MixNodeBond[]> {
const url = new URL(this.validatorApiUrl);
url.pathname += VALIDATOR_API_REWARDED_MIXNODES_PATH;
const url = new URL(this.nymApiUrl);
url.pathname += NYM_API_REWARDED_MIXNODES_PATH;
const response = await axios.get(url.toString());
if (response.status === 200) {
+11 -11
View File
@@ -29,7 +29,7 @@ import {
PagedMixnodeResponse,
RewardingStatus,
} from './types';
import ValidatorApiQuerier, { IValidatorApiQuery } from './validator-api-querier';
import NymApiQuerier, { INymApiQuery as INymApiQuery } from './nym-api-querier';
export interface ICosmWasmQuery {
// methods exposed by `CosmWasmClient`
@@ -93,22 +93,22 @@ export interface INymdQuery {
): Promise<RewardingStatus>;
}
export interface IQueryClient extends ICosmWasmQuery, INymdQuery, IValidatorApiQuery {}
export interface IQueryClient extends ICosmWasmQuery, INymdQuery, INymApiQuery { }
export default class QueryClient extends CosmWasmClient implements IQueryClient {
private nymdQuerier: NymdQuerier;
private validatorApiQuerier: ValidatorApiQuerier;
private nymApiQuerier: NymApiQuerier;
private constructor(tmClient: Tendermint34Client, validatorApiUrl: string) {
private constructor(tmClient: Tendermint34Client, nymApiUrl: string) {
super(tmClient);
this.nymdQuerier = new NymdQuerier(this);
this.validatorApiQuerier = new ValidatorApiQuerier(validatorApiUrl);
this.nymApiQuerier = new NymApiQuerier(nymApiUrl);
}
public static async connectWithNym(nymdUrl: string, validatorApiUrl: string): Promise<QueryClient> {
public static async connectWithNym(nymdUrl: string, nymApiUrl: string): Promise<QueryClient> {
const tmClient = await Tendermint34Client.connect(nymdUrl);
return new QueryClient(tmClient, validatorApiUrl);
return new QueryClient(tmClient, nymApiUrl);
}
getContractVersion(mixnetContractAddress: string): Promise<MixnetContractVersion> {
@@ -194,18 +194,18 @@ export default class QueryClient extends CosmWasmClient implements IQueryClient
}
getCachedGateways(): Promise<GatewayBond[]> {
return this.validatorApiQuerier.getCachedGateways();
return this.nymApiQuerier.getCachedGateways();
}
getCachedMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getCachedMixnodes();
return this.nymApiQuerier.getCachedMixnodes();
}
getActiveMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getActiveMixnodes();
return this.nymApiQuerier.getActiveMixnodes();
}
getRewardedMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getRewardedMixnodes();
return this.nymApiQuerier.getRewardedMixnodes();
}
}
+10 -10
View File
@@ -33,7 +33,7 @@ import {
PagedMixnodeResponse,
RewardingStatus,
} from './types';
import ValidatorApiQuerier from './validator-api-querier';
import NymApiQuerier from './nym-api-querier';
// methods exposed by `SigningCosmWasmClient`
export interface ICosmWasmSigning {
@@ -199,13 +199,13 @@ export interface ISigningClient extends IQueryClient, ICosmWasmSigning, INymSign
export default class SigningClient extends SigningCosmWasmClient implements ISigningClient {
private nymdQuerier: NymdQuerier;
private validatorApiQuerier: ValidatorApiQuerier;
private nymApiQuerier: NymApiQuerier;
clientAddress: string;
private constructor(
clientAddress: string,
validatorApiUrl: string,
nymApiUrl: string,
tmClient: Tendermint34Client,
wallet: DirectSecp256k1HdWallet,
signerOptions: SigningCosmWasmClientOptions,
@@ -213,13 +213,13 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
super(tmClient, wallet, signerOptions);
this.clientAddress = clientAddress;
this.nymdQuerier = new NymdQuerier(this);
this.validatorApiQuerier = new ValidatorApiQuerier(validatorApiUrl);
this.nymApiQuerier = new NymApiQuerier(nymApiUrl);
}
public static async connectWithNymSigner(
wallet: DirectSecp256k1HdWallet,
nymdUrl: string,
validatorApiUrl: string,
nymApiUrl: string,
prefix: string,
denom: string,
): Promise<SigningClient> {
@@ -229,7 +229,7 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
gasPrice: nymGasPrice(denom),
};
const tmClient = await Tendermint34Client.connect(nymdUrl);
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
return new SigningClient(address, nymApiUrl, tmClient, wallet, signerOptions);
}
// query related:
@@ -317,19 +317,19 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
}
getCachedGateways(): Promise<GatewayBond[]> {
return this.validatorApiQuerier.getCachedGateways();
return this.nymApiQuerier.getCachedGateways();
}
getCachedMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getCachedMixnodes();
return this.nymApiQuerier.getCachedMixnodes();
}
getActiveMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getActiveMixnodes();
return this.nymApiQuerier.getActiveMixnodes();
}
getRewardedMixnodes(): Promise<MixNodeBond[]> {
return this.validatorApiQuerier.getRewardedMixnodes();
return this.nymApiQuerier.getRewardedMixnodes();
}
// signing related:
@@ -1,4 +1,4 @@
import ValidatorClient from '../../dist';
import ValidatorClient from '../../validator/index';
import expect from 'expect';
describe('Query: balances', () => {
+2 -2
View File
@@ -17,7 +17,7 @@ pub struct Config {
/// ID specifies the human readable ID of this particular client.
pub(crate) id: String,
pub(crate) validator_api_url: Url,
pub(crate) nym_api_url: Url,
pub(crate) disabled_credentials_mode: bool,
@@ -38,7 +38,7 @@ impl Config {
) -> Self {
Config {
id,
validator_api_url: validator_server
nym_api_url: validator_server
.parse()
.expect("provided url was malformed"),
disabled_credentials_mode: true,
+4 -4
View File
@@ -14,7 +14,7 @@ use nymsphinx::addressing::clients::Recipient;
use nymsphinx::anonymous_replies::requests::AnonymousSenderTag;
use rand::rngs::OsRng;
use std::sync::Arc;
use task::ShutdownNotifier;
use task::TaskManager;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::future_to_promise;
use wasm_utils::{console_error, console_log};
@@ -30,7 +30,7 @@ pub struct NymClient {
// even though we don't use graceful shutdowns, other components rely on existence of this struct
// and if it's dropped, everything will start going offline
_shutdown: ShutdownNotifier,
_task_manager: TaskManager,
}
#[wasm_bindgen]
@@ -99,7 +99,7 @@ impl NymClientBuilder {
self.bandwidth_controller,
self.reply_surb_storage_backend,
self.disabled_credentials,
vec![self.config.validator_api_url.clone()],
vec![self.config.nym_api_url.clone()],
);
let self_address = base_builder.as_mix_recipient().to_string();
@@ -121,7 +121,7 @@ impl NymClientBuilder {
Ok(JsValue::from(NymClient {
self_address,
client_input: Arc::new(client_input),
_shutdown: started_client.shutdown_notifier,
_task_manager: started_client.task_manager,
}))
})
}
+1 -2
View File
@@ -1,9 +1,8 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::collections::HashMap;
use futures::channel::mpsc;
use std::collections::HashMap;
pub type ConnectionId = u64;
@@ -22,7 +22,7 @@ use rand::rngs::OsRng;
use std::convert::TryFrom;
use std::sync::Arc;
use std::time::Duration;
use task::ShutdownListener;
use task::TaskClient;
use tungstenite::protocol::Message;
#[cfg(feature = "coconut")]
@@ -67,7 +67,7 @@ pub struct GatewayClient {
reconnection_backoff: Duration,
/// Listen to shutdown messages.
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl GatewayClient {
@@ -83,7 +83,7 @@ impl GatewayClient {
ack_sender: AcknowledgementSender,
response_timeout_duration: Duration,
bandwidth_controller: Option<BandwidthController<PersistentStorage>>,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
GatewayClient {
authenticated: false,
@@ -135,7 +135,7 @@ impl GatewayClient {
// perfectly fine here, because it's not meant to be used
let (ack_tx, _) = mpsc::unbounded();
let (mix_tx, _) = mpsc::unbounded();
let shutdown = ShutdownListener::dummy();
let shutdown = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
GatewayClient {
@@ -305,11 +305,11 @@ impl GatewayClient {
if let Some(shared_keys) = &self.shared_key {
if let Some(plaintext) = try_decrypt_binary_message(bin_msg, shared_keys) {
if let Err(err) = self.packet_router.route_received(vec![plaintext]) {
log::warn!("Route received failed: {:?}", err);
log::warn!("Route received failed: {err}");
}
}
} else if let Err(err) = self.packet_router.route_received(vec![bin_msg]) {
log::warn!("Route received failed: {:?}", err);
log::warn!("Route received failed: {err}");
}
}
Message::Text(txt_msg) => {
@@ -9,7 +9,7 @@ use futures::channel::mpsc;
use log::*;
use nymsphinx::addressing::nodes::MAX_NODE_ADDRESS_UNPADDED_LEN;
use nymsphinx::params::packet_sizes::PacketSize;
use task::ShutdownListener;
use task::TaskClient;
pub type MixnetMessageSender = mpsc::UnboundedSender<Vec<Vec<u8>>>;
pub type MixnetMessageReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
@@ -21,14 +21,14 @@ pub type AcknowledgementReceiver = mpsc::UnboundedReceiver<Vec<Vec<u8>>>;
pub struct PacketRouter {
ack_sender: AcknowledgementSender,
mixnet_message_sender: MixnetMessageSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl PacketRouter {
pub fn new(
ack_sender: AcknowledgementSender,
mixnet_message_sender: MixnetMessageSender,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
PacketRouter {
ack_sender,
@@ -89,14 +89,14 @@ impl PacketRouter {
}
// This should never happen during ordinary operation the way it's currently used.
// Abort to be on the safe side
panic!("Failed to send mixnet message: {:?}", err);
panic!("Failed to send mixnet message: {err}");
}
}
if !received_acks.is_empty() {
trace!("routing acks");
if let Err(e) = self.ack_sender.unbounded_send(received_acks) {
error!("failed to send ack: {:?}", e);
if let Err(err) = self.ack_sender.unbounded_send(received_acks) {
error!("failed to send ack: {err}");
};
}
Ok(())
@@ -10,7 +10,7 @@ use futures::{SinkExt, StreamExt};
use gateway_requests::registration::handshake::SharedKeys;
use log::*;
use std::sync::Arc;
use task::ShutdownListener;
use task::TaskClient;
use tungstenite::Message;
#[cfg(not(target_arch = "wasm32"))]
@@ -84,7 +84,7 @@ impl PartiallyDelegated {
conn: WsConn,
packet_router: PacketRouter,
shared_key: Arc<SharedKeys>,
mut shutdown: ShutdownListener,
mut shutdown: TaskClient,
) -> Self {
// when called for, it NEEDS TO yield back the stream so that we could merge it and
// read control request responses.
@@ -115,7 +115,7 @@ impl PartiallyDelegated {
};
if let Err(err) = Self::route_socket_messages(ws_msgs, &mut packet_router, shared_key.as_ref()) {
log::warn!("Route socket messages failed: {:?}", err);
log::warn!("Route socket messages failed: {err}");
}
}
};
@@ -122,7 +122,7 @@ impl Client {
// We could have as well used conn.send_all(receiver.map(Ok)), but considering we don't care
// about neither receiver nor the connection, it doesn't matter which one gets consumed
if let Err(err) = receiver.map(Ok).forward(conn).await {
warn!("Failed to forward packets to {} - {:?}", address, err);
warn!("Failed to forward packets to {} - {err}", address);
}
debug!(
@@ -59,7 +59,7 @@ impl PacketForwarder {
self.mixnet_client
.send_without_response(next_hop, sphinx_packet, packet_mode)
{
debug!("failed to forward the packet - {}", err)
debug!("failed to forward the packet - {err}")
}
}
}
@@ -29,7 +29,7 @@ futures = "0.3"
coconut-interface = { path = "../../coconut-interface" }
network-defaults = { path = "../../network-defaults" }
validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
nym-api-requests = { path = "../../../nym-api/nym-api-requests", features = ["coconut"] }
# required for nymd-client
# at some point it might be possible to make it wasm-compatible
@@ -1,16 +1,16 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{validator_api, ValidatorClientError};
use crate::{nym_api, ValidatorClientError};
use coconut_dkg_common::types::NodeIndex;
use coconut_interface::VerificationKey;
use mixnet_contract_common::mixnode::MixNodeDetails;
use mixnet_contract_common::MixId;
use mixnet_contract_common::{GatewayBond, IdentityKeyRef};
use validator_api_requests::coconut::{
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{
use nym_api_requests::models::{
GatewayCoreStatusResponse, MixnodeCoreStatusResponse, MixnodeStatusResponse,
RewardEstimationResponse, StakeSaturationResponse,
};
@@ -37,10 +37,10 @@ use mixnet_contract_common::{
#[cfg(feature = "nymd-client")]
use network_defaults::NymNetworkDetails;
#[cfg(feature = "nymd-client")]
use nym_api_requests::models::MixNodeBondAnnotated;
#[cfg(feature = "nymd-client")]
use std::str::FromStr;
use url::Url;
#[cfg(feature = "nymd-client")]
use validator_api_requests::models::MixNodeBondAnnotated;
#[cfg(feature = "nymd-client")]
#[must_use]
@@ -142,7 +142,7 @@ pub struct Client<C> {
proposals_page_limit: Option<u32>,
// ideally they would have been read-only, but unfortunately rust doesn't have such features
pub validator_api: validator_api::Client,
pub nym_api: nym_api::Client,
pub nymd: NymdClient<C>,
}
@@ -152,7 +152,7 @@ impl Client<SigningNymdClient> {
config: Config,
mnemonic: bip39::Mnemonic,
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nym_api_client = nym_api::Client::new(config.api_url.clone());
let nymd_client = NymdClient::connect_with_mnemonic(
config.nymd_config.clone(),
config.nymd_url.as_str(),
@@ -169,7 +169,7 @@ impl Client<SigningNymdClient> {
dealers_page_limit: config.dealers_page_limit,
verification_key_page_limit: config.verification_key_page_limit,
proposals_page_limit: config.proposals_page_limit,
validator_api: validator_api_client,
nym_api: nym_api_client,
nymd: nymd_client,
})
}
@@ -192,7 +192,7 @@ impl Client<SigningNymdClient> {
#[cfg(feature = "nymd-client")]
impl Client<QueryNymdClient> {
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
let validator_api_client = validator_api::Client::new(config.api_url.clone());
let nym_api_client = nym_api::Client::new(config.api_url.clone());
let nymd_client =
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
@@ -205,7 +205,7 @@ impl Client<QueryNymdClient> {
dealers_page_limit: config.dealers_page_limit,
verification_key_page_limit: config.verification_key_page_limit,
proposals_page_limit: config.proposals_page_limit,
validator_api: validator_api_client,
nym_api: nym_api_client,
nymd: nymd_client,
})
}
@@ -731,53 +731,53 @@ impl<C> Client<C> {
// validator-api wrappers
#[cfg(feature = "nymd-client")]
impl<C> Client<C> {
pub fn change_validator_api(&mut self, new_endpoint: Url) {
self.validator_api.change_url(new_endpoint)
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api.change_url(new_endpoint)
}
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes().await?)
Ok(self.nym_api.get_mixnodes().await?)
}
pub async fn get_cached_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes_detailed().await?)
Ok(self.nym_api.get_mixnodes_detailed().await?)
}
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes().await?)
Ok(self.nym_api.get_rewarded_mixnodes().await?)
}
pub async fn get_cached_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes_detailed().await?)
Ok(self.nym_api.get_rewarded_mixnodes_detailed().await?)
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes().await?)
Ok(self.nym_api.get_active_mixnodes().await?)
}
pub async fn get_cached_active_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes_detailed().await?)
Ok(self.nym_api.get_active_mixnodes_detailed().await?)
}
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.validator_api.get_gateways().await?)
Ok(self.nym_api.get_gateways().await?)
}
pub async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self.validator_api.blind_sign(request_body).await?)
Ok(self.nym_api.blind_sign(request_body).await?)
}
}
@@ -827,42 +827,40 @@ impl CoconutApiClient {
#[derive(Clone)]
pub struct ApiClient {
pub validator_api: validator_api::Client,
pub nym_api_client: nym_api::Client,
// TODO: perhaps if we really need it at some (currently I don't see any reasons for it)
// we could re-implement the communication with the REST API on port 1317
}
impl ApiClient {
pub fn new(api_url: Url) -> Self {
let validator_api_client = validator_api::Client::new(api_url);
let nym_api_client = nym_api::Client::new(api_url);
ApiClient {
validator_api: validator_api_client,
}
ApiClient { nym_api_client }
}
pub fn change_validator_api(&mut self, new_endpoint: Url) {
self.validator_api.change_url(new_endpoint);
pub fn change_nym_api(&mut self, new_endpoint: Url) {
self.nym_api_client.change_url(new_endpoint);
}
pub async fn get_cached_active_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_active_mixnodes().await?)
Ok(self.nym_api_client.get_active_mixnodes().await?)
}
pub async fn get_cached_rewarded_mixnodes(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_rewarded_mixnodes().await?)
Ok(self.nym_api_client.get_rewarded_mixnodes().await?)
}
pub async fn get_cached_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorClientError> {
Ok(self.validator_api.get_mixnodes().await?)
Ok(self.nym_api_client.get_mixnodes().await?)
}
pub async fn get_cached_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
Ok(self.validator_api.get_gateways().await?)
Ok(self.nym_api_client.get_gateways().await?)
}
pub async fn get_gateway_core_status_count(
@@ -871,7 +869,7 @@ impl ApiClient {
since: Option<i64>,
) -> Result<GatewayCoreStatusResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.get_gateway_core_status_count(identity, since)
.await?)
}
@@ -882,7 +880,7 @@ impl ApiClient {
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.get_mixnode_core_status_count(mix_id, since)
.await?)
}
@@ -891,7 +889,7 @@ impl ApiClient {
&self,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, ValidatorClientError> {
Ok(self.validator_api.get_mixnode_status(mix_id).await?)
Ok(self.nym_api_client.get_mixnode_status(mix_id).await?)
}
pub async fn get_mixnode_reward_estimation(
@@ -899,7 +897,7 @@ impl ApiClient {
mix_id: MixId,
) -> Result<RewardEstimationResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.get_mixnode_reward_estimation(mix_id)
.await?)
}
@@ -909,7 +907,7 @@ impl ApiClient {
mix_id: MixId,
) -> Result<StakeSaturationResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.get_mixnode_stake_saturation(mix_id)
.await?)
}
@@ -918,7 +916,7 @@ impl ApiClient {
&self,
request_body: &BlindSignRequestBody,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self.validator_api.blind_sign(request_body).await?)
Ok(self.nym_api_client.blind_sign(request_body).await?)
}
pub async fn partial_bandwidth_credential(
@@ -926,7 +924,7 @@ impl ApiClient {
request_body: &str,
) -> Result<BlindedSignatureResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.partial_bandwidth_credential(request_body)
.await?)
}
@@ -936,7 +934,7 @@ impl ApiClient {
request_body: &VerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
Ok(self
.validator_api
.nym_api_client
.verify_bandwidth_credential(request_body)
.await?)
}
@@ -1,15 +1,15 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::validator_api;
use crate::nym_api;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ValidatorClientError {
#[error("There was an issue with the validator api request - {source}")]
ValidatorAPIError {
NymAPIError {
#[from]
source: validator_api::error::ValidatorAPIError,
source: nym_api::error::NymAPIError,
},
#[error("One of the provided URLs was malformed - {0}")]
@@ -5,14 +5,14 @@ pub mod client;
#[cfg(feature = "nymd-client")]
pub mod connection_tester;
mod error;
pub mod nym_api;
#[cfg(feature = "nymd-client")]
pub mod nymd;
pub mod validator_api;
#[cfg(feature = "nymd-client")]
pub use crate::client::{ApiClient, CoconutApiClient};
pub use crate::error::ValidatorClientError;
pub use validator_api_requests::*;
pub use nym_api_requests::*;
#[cfg(feature = "nymd-client")]
pub use client::{Client, Config};
@@ -1,8 +1,8 @@
use nym_api_requests::models::RequestError;
use thiserror::Error;
use validator_api_requests::models::RequestError;
#[derive(Error, Debug)]
pub enum ValidatorAPIError {
pub enum NymAPIError {
#[error("There was an issue with the REST request - {source}")]
ReqwestClientError {
#[from]
@@ -12,6 +12,6 @@ pub enum ValidatorAPIError {
#[error("Request failed with error message - {0}")]
GenericRequestFailure(String),
#[error("The validator API has failed to resolve our request. It returned status code {status} and additional error message: {}", error.message())]
#[error("The nym API has failed to resolve our request. It returned status code {status} and additional error message: {}", error.message())]
ApiRequestFailure { status: u16, error: RequestError },
}
@@ -1,22 +1,23 @@
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::validator_api::error::ValidatorAPIError;
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use crate::nym_api::error::NymAPIError;
use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use mixnet_contract_common::mixnode::MixNodeDetails;
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixId};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::{
ComputeRewardEstParam, GatewayCoreStatusResponse, GatewayStatusReportResponse,
GatewayUptimeHistoryResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
MixnodeCoreStatusResponse, MixnodeStatusReportResponse, MixnodeStatusResponse,
MixnodeUptimeHistoryResponse, RequestError, RewardEstimationResponse, StakeSaturationResponse,
UptimeResponse,
};
use reqwest::Response;
use serde::{Deserialize, Serialize};
use url::Url;
use validator_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
};
use validator_api_requests::models::{
GatewayCoreStatusResponse, GatewayStatusReportResponse, GatewayUptimeHistoryResponse,
InclusionProbabilityResponse, MixNodeBondAnnotated, MixnodeCoreStatusResponse,
MixnodeStatusReportResponse, MixnodeStatusResponse, MixnodeUptimeHistoryResponse, RequestError,
RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
};
pub mod error;
pub mod routes;
@@ -53,7 +54,7 @@ impl Client {
&self,
path: PathSegments<'_>,
params: Params<'_, K, V>,
) -> Result<Response, ValidatorAPIError>
) -> Result<Response, NymAPIError>
where
K: AsRef<str>,
V: AsRef<str>,
@@ -62,11 +63,11 @@ impl Client {
Ok(self.reqwest_client.get(url).send().await?)
}
async fn query_validator_api<T, K, V>(
async fn query_nym_api<T, K, V>(
&self,
path: PathSegments<'_>,
params: Params<'_, K, V>,
) -> Result<T, ValidatorAPIError>
) -> Result<T, NymAPIError>
where
for<'a> T: Deserialize<'a>,
K: AsRef<str>,
@@ -76,16 +77,16 @@ impl Client {
if res.status().is_success() {
Ok(res.json().await?)
} else {
Err(ValidatorAPIError::GenericRequestFailure(res.text().await?))
Err(NymAPIError::GenericRequestFailure(res.text().await?))
}
}
// This works for endpoints returning Result<Json<T>, ErrorResponse>
async fn query_validator_api_fallible<T, K, V>(
async fn query_nym_api_fallible<T, K, V>(
&self,
path: PathSegments<'_>,
params: Params<'_, K, V>,
) -> Result<T, ValidatorAPIError>
) -> Result<T, NymAPIError>
where
for<'a> T: Deserialize<'a>,
K: AsRef<str>,
@@ -97,19 +98,19 @@ impl Client {
Ok(res.json().await?)
} else {
let request_error: RequestError = res.json().await?;
Err(ValidatorAPIError::ApiRequestFailure {
Err(NymAPIError::ApiRequestFailure {
status: status.as_u16(),
error: request_error,
})
}
}
async fn post_validator_api<B, T, K, V>(
async fn post_nym_api<B, T, K, V>(
&self,
path: PathSegments<'_>,
params: Params<'_, K, V>,
json_body: &B,
) -> Result<T, ValidatorAPIError>
) -> Result<T, NymAPIError>
where
B: Serialize + ?Sized,
for<'a> T: Deserialize<'a>,
@@ -121,21 +122,17 @@ impl Client {
if response.status().is_success() {
Ok(response.json().await?)
} else {
Err(ValidatorAPIError::GenericRequestFailure(
response.text().await?,
))
Err(NymAPIError::GenericRequestFailure(response.text().await?))
}
}
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
pub async fn get_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.query_nym_api(&[routes::API_VERSION, routes::MIXNODES], NO_PARAMS)
.await
}
pub async fn get_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
pub async fn get_mixnodes_detailed(&self) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -147,13 +144,13 @@ impl Client {
.await
}
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorAPIError> {
self.query_validator_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
pub async fn get_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
self.query_nym_api(&[routes::API_VERSION, routes::GATEWAYS], NO_PARAMS)
.await
}
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
self.query_validator_api(
pub async fn get_active_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.query_nym_api(
&[routes::API_VERSION, routes::MIXNODES, routes::ACTIVE],
NO_PARAMS,
)
@@ -162,8 +159,8 @@ impl Client {
pub async fn get_active_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -176,8 +173,8 @@ impl Client {
.await
}
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, ValidatorAPIError> {
self.query_validator_api(
pub async fn get_rewarded_mixnodes(&self) -> Result<Vec<MixNodeDetails>, NymAPIError> {
self.query_nym_api(
&[routes::API_VERSION, routes::MIXNODES, routes::REWARDED],
NO_PARAMS,
)
@@ -187,8 +184,8 @@ impl Client {
pub async fn get_mixnode_report(
&self,
mix_id: MixId,
) -> Result<MixnodeStatusReportResponse, ValidatorAPIError> {
self.query_validator_api(
) -> Result<MixnodeStatusReportResponse, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -204,8 +201,8 @@ impl Client {
pub async fn get_gateway_report(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<GatewayStatusReportResponse, ValidatorAPIError> {
self.query_validator_api(
) -> Result<GatewayStatusReportResponse, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -221,8 +218,8 @@ impl Client {
pub async fn get_mixnode_history(
&self,
mix_id: MixId,
) -> Result<MixnodeUptimeHistoryResponse, ValidatorAPIError> {
self.query_validator_api(
) -> Result<MixnodeUptimeHistoryResponse, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -238,8 +235,8 @@ impl Client {
pub async fn get_gateway_history(
&self,
identity: IdentityKeyRef<'_>,
) -> Result<GatewayUptimeHistoryResponse, ValidatorAPIError> {
self.query_validator_api(
) -> Result<GatewayUptimeHistoryResponse, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -254,8 +251,8 @@ impl Client {
pub async fn get_rewarded_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeBondAnnotated>, ValidatorAPIError> {
self.query_validator_api(
) -> Result<Vec<MixNodeBondAnnotated>, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS,
@@ -272,9 +269,9 @@ impl Client {
&self,
identity: IdentityKeyRef<'_>,
since: Option<i64>,
) -> Result<GatewayCoreStatusResponse, ValidatorAPIError> {
) -> Result<GatewayCoreStatusResponse, NymAPIError> {
if let Some(since) = since {
self.query_validator_api(
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -286,7 +283,7 @@ impl Client {
)
.await
} else {
self.query_validator_api(
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -303,9 +300,9 @@ impl Client {
&self,
mix_id: MixId,
since: Option<i64>,
) -> Result<MixnodeCoreStatusResponse, ValidatorAPIError> {
) -> Result<MixnodeCoreStatusResponse, NymAPIError> {
if let Some(since) = since {
self.query_validator_api(
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -317,7 +314,7 @@ impl Client {
)
.await
} else {
self.query_validator_api(
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -334,8 +331,8 @@ impl Client {
pub async fn get_mixnode_status(
&self,
mix_id: MixId,
) -> Result<MixnodeStatusResponse, ValidatorAPIError> {
self.query_validator_api(
) -> Result<MixnodeStatusResponse, NymAPIError> {
self.query_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -351,8 +348,8 @@ impl Client {
pub async fn get_mixnode_reward_estimation(
&self,
mix_id: MixId,
) -> Result<RewardEstimationResponse, ValidatorAPIError> {
self.query_validator_api_fallible(
) -> Result<RewardEstimationResponse, NymAPIError> {
self.query_nym_api_fallible(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -365,11 +362,30 @@ impl Client {
.await
}
pub async fn compute_mixnode_reward_estimation(
&self,
mix_id: MixId,
request_body: &ComputeRewardEstParam,
) -> Result<RewardEstimationResponse, NymAPIError> {
self.post_nym_api(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
routes::MIXNODE,
&mix_id.to_string(),
routes::COMPUTE_REWARD_ESTIMATION,
],
NO_PARAMS,
request_body,
)
.await
}
pub async fn get_mixnode_stake_saturation(
&self,
mix_id: MixId,
) -> Result<StakeSaturationResponse, ValidatorAPIError> {
self.query_validator_api_fallible(
) -> Result<StakeSaturationResponse, NymAPIError> {
self.query_nym_api_fallible(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -385,8 +401,8 @@ impl Client {
pub async fn get_mixnode_inclusion_probability(
&self,
mix_id: MixId,
) -> Result<InclusionProbabilityResponse, ValidatorAPIError> {
self.query_validator_api_fallible(
) -> Result<InclusionProbabilityResponse, NymAPIError> {
self.query_nym_api_fallible(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -402,8 +418,8 @@ impl Client {
pub async fn get_mixnode_avg_uptime(
&self,
mix_id: MixId,
) -> Result<UptimeResponse, ValidatorAPIError> {
self.query_validator_api_fallible(
) -> Result<UptimeResponse, NymAPIError> {
self.query_nym_api_fallible(
&[
routes::API_VERSION,
routes::STATUS_ROUTES,
@@ -419,8 +435,8 @@ impl Client {
pub async fn blind_sign(
&self,
request_body: &BlindSignRequestBody,
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api(
) -> Result<BlindedSignatureResponse, NymAPIError> {
self.post_nym_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
@@ -436,8 +452,8 @@ impl Client {
pub async fn partial_bandwidth_credential(
&self,
request_body: &str,
) -> Result<BlindedSignatureResponse, ValidatorAPIError> {
self.post_validator_api(
) -> Result<BlindedSignatureResponse, NymAPIError> {
self.post_nym_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
@@ -453,8 +469,8 @@ impl Client {
pub async fn verify_bandwidth_credential(
&self,
request_body: &VerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorAPIError> {
self.post_validator_api(
) -> Result<VerifyCredentialResponse, NymAPIError> {
self.post_nym_api(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
@@ -1,9 +1,9 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use network_defaults::VALIDATOR_API_VERSION;
use network_defaults::NYM_API_VERSION;
pub const API_VERSION: &str = VALIDATOR_API_VERSION;
pub const API_VERSION: &str = NYM_API_VERSION;
pub const MIXNODES: &str = "mixnodes";
pub const GATEWAYS: &str = "gateways";
@@ -28,6 +28,7 @@ pub const STATUS: &str = "status";
pub const REPORT: &str = "report";
pub const HISTORY: &str = "history";
pub const REWARD_ESTIMATION: &str = "reward-estimation";
pub const COMPUTE_REWARD_ESTIMATION: &str = "compute-reward-estimation";
pub const AVG_UPTIME: &str = "avg_uptime";
pub const STAKE_SATURATION: &str = "stake-saturation";
pub const INCLUSION_CHANCE: &str = "inclusion-probability";
@@ -8,13 +8,13 @@ use coconut_dkg_common::dealer::{
DealerDetailsResponse, PagedDealerResponse, PagedDealingsResponse,
};
use coconut_dkg_common::msg::QueryMsg as DkgQueryMsg;
use coconut_dkg_common::types::EpochState;
use coconut_dkg_common::types::Epoch;
use coconut_dkg_common::verification_key::PagedVKSharesResponse;
use cosmrs::AccountId;
#[async_trait]
pub trait DkgQueryClient {
async fn get_current_epoch_state(&self) -> Result<EpochState, NymdError>;
async fn get_current_epoch(&self) -> Result<Epoch, NymdError>;
async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NymdError>;
async fn get_dealer_details(
&self,
@@ -49,7 +49,7 @@ impl<C> DkgQueryClient for NymdClient<C>
where
C: CosmWasmClient + Send + Sync,
{
async fn get_current_epoch_state(&self) -> Result<EpochState, NymdError> {
async fn get_current_epoch(&self) -> Result<Epoch, NymdError> {
let request = DkgQueryMsg::GetCurrentEpochState {};
self.client
.query_contract_smart(self.coconut_dkg_contract_address(), &request)
@@ -12,6 +12,7 @@ use contracts_common::dealings::ContractSafeBytes;
#[async_trait]
pub trait DkgSigningClient {
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError>;
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
@@ -37,6 +38,21 @@ impl<C> DkgSigningClient for NymdClient<C>
where
C: SigningCosmWasmClient + Send + Sync,
{
async fn advance_dkg_epoch_state(&self, fee: Option<Fee>) -> Result<ExecuteResult, NymdError> {
let req = DkgExecuteMsg::AdvanceEpochState {};
self.client
.execute(
self.address(),
self.coconut_dkg_contract_address(),
&req,
fee.unwrap_or_default(),
"advancing DKG state",
vec![],
)
.await
}
async fn register_dealer(
&self,
bte_key: EncodedBTEPublicKeyWithProof,
+2 -2
View File
@@ -16,9 +16,9 @@ pub enum ContextError {
#[error("failed to create client - {0}")]
NymdError(String),
#[error("{0}")]
#[error(transparent)]
NymdErrorPassthrough(#[from] validator_client::nymd::error::NymdError),
#[error("{0}")]
#[error(transparent)]
ValidatorClientError(#[from] validator_client::ValidatorClientError),
}
+14 -14
View File
@@ -7,8 +7,8 @@ use network_defaults::{
NymNetworkDetails,
};
use tap::prelude::*;
pub use validator_client::nym_api::Client as NymApiClient;
use validator_client::nymd::{self, AccountId, NymdClient, QueryNymdClient, SigningNymdClient};
pub use validator_client::validator_api::Client as ValidatorApiClient;
use crate::context::errors::ContextError;
@@ -16,14 +16,14 @@ pub mod errors;
pub type SigningClient = validator_client::nymd::NymdClient<SigningNymdClient>;
pub type QueryClient = validator_client::nymd::NymdClient<QueryNymdClient>;
pub type SigningClientWithValidatorAPI = validator_client::Client<SigningNymdClient>;
pub type QueryClientWithValidatorAPI = validator_client::Client<QueryNymdClient>;
pub type SigningClientWithNymd = validator_client::Client<SigningNymdClient>;
pub type QueryClientWithNymd = validator_client::Client<QueryNymdClient>;
#[derive(Debug)]
pub struct ClientArgs {
pub config_env_file: Option<std::path::PathBuf>,
pub nymd_url: Option<String>,
pub validator_api_url: Option<String>,
pub nym_api_url: Option<String>,
pub mnemonic: Option<bip39::Mnemonic>,
pub mixnet_contract_address: Option<AccountId>,
pub vesting_contract_address: Option<AccountId>,
@@ -38,8 +38,8 @@ pub fn get_network_details(args: &ClientArgs) -> Result<NymNetworkDetails, Conte
if let Some(nymd_url) = args.nymd_url.as_ref() {
std::env::set_var(NYMD_VALIDATOR, nymd_url);
}
if let Some(validator_api_url) = args.validator_api_url.as_ref() {
std::env::set_var(API_VALIDATOR, validator_api_url);
if let Some(nym_api_url) = args.nym_api_url.as_ref() {
std::env::set_var(API_VALIDATOR, nym_api_url);
}
if let Some(mixnet_contract_address) = args.mixnet_contract_address.as_ref() {
std::env::set_var(MIXNET_CONTRACT_ADDRESS, mixnet_contract_address.to_string());
@@ -59,7 +59,7 @@ pub fn create_signing_client(
network_details: &NymNetworkDetails,
) -> Result<SigningClient, ContextError> {
let client_config = nymd::Config::try_from_nym_network_details(network_details)
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
// get mnemonic
let mnemonic = match std::env::var("MNEMONIC") {
@@ -88,7 +88,7 @@ pub fn create_query_client(
network_details: &NymNetworkDetails,
) -> Result<QueryClient, ContextError> {
let client_config = nymd::Config::try_from_nym_network_details(network_details)
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
let nymd_url = network_details
.endpoints
@@ -103,12 +103,12 @@ pub fn create_query_client(
}
}
pub fn create_signing_client_with_validator_api(
pub fn create_signing_client_with_nym_api(
args: ClientArgs,
network_details: &NymNetworkDetails,
) -> Result<SigningClientWithValidatorAPI, ContextError> {
) -> Result<SigningClientWithNymd, ContextError> {
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
// get mnemonic
let mnemonic = match std::env::var("MNEMONIC") {
@@ -126,11 +126,11 @@ pub fn create_signing_client_with_validator_api(
}
}
pub fn create_query_client_with_validator_api(
pub fn create_query_client_with_nym_api(
network_details: &NymNetworkDetails,
) -> Result<QueryClientWithValidatorAPI, ContextError> {
) -> Result<QueryClientWithNymd, ContextError> {
let client_config = validator_client::Config::try_from_nym_network_details(network_details)
.tap_err(|e| log::error!("Failed to get client config - {:?}", e))?;
.tap_err(|err| log::error!("Failed to get client config - {err}"))?;
match validator_client::client::Client::new_query(client_config) {
Ok(client) => Ok(client),
@@ -4,7 +4,7 @@
use clap::Parser;
use log::info;
use crate::context::SigningClientWithValidatorAPI;
use crate::context::SigningClientWithNymd;
use crate::utils::{pretty_cosmwasm_coin, show_error_passthrough};
use comfy_table::Table;
@@ -14,7 +14,7 @@ use mixnet_contract_common::{Delegation, PendingEpochEvent, PendingEpochEventKin
#[derive(Debug, Parser)]
pub struct Args {}
pub async fn execute(_args: Args, client: SigningClientWithValidatorAPI) {
pub async fn execute(_args: Args, client: SigningClientWithNymd) {
info!(
"Getting delegations for account {}...",
client.nymd.address()
@@ -48,14 +48,14 @@ pub async fn execute(_args: Args, client: SigningClientWithValidatorAPI) {
}
}
async fn to_iso_timestamp(block_height: u32, client: &SigningClientWithValidatorAPI) -> String {
async fn to_iso_timestamp(block_height: u32, client: &SigningClientWithNymd) -> String {
match client.nymd.get_block_timestamp(Some(block_height)).await {
Ok(res) => res.to_rfc3339(),
Err(_e) => "-".to_string(),
}
}
async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientWithValidatorAPI) {
async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientWithNymd) {
let mut table = Table::new();
table.set_header(vec!["Timestamp", "Mix Id", "Delegation", "Proxy"]);
@@ -75,10 +75,7 @@ async fn print_delegations(delegations: Vec<Delegation>, client: &SigningClientW
println!("{table}");
}
async fn print_delegation_events(
events: Vec<PendingEpochEvent>,
client: &SigningClientWithValidatorAPI,
) {
async fn print_delegation_events(events: Vec<PendingEpochEvent>, client: &SigningClientWithNymd) {
let mut table = Table::new();
table.set_header(vec![
@@ -4,7 +4,7 @@
use clap::Parser;
use comfy_table::Table;
use crate::context::QueryClientWithValidatorAPI;
use crate::context::QueryClientWithNymd;
use crate::utils::{pretty_cosmwasm_coin, show_error};
#[derive(Debug, Parser)]
@@ -14,8 +14,8 @@ pub struct Args {
pub identity_key: Option<String>,
}
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
match client.validator_api.get_gateways().await {
pub async fn query(args: Args, client: &QueryClientWithNymd) {
match client.nym_api.get_gateways().await {
Ok(res) => match args.identity_key {
Some(identity_key) => {
let node = res.iter().find(|node| {
@@ -4,7 +4,7 @@
use clap::Parser;
use comfy_table::Table;
use crate::context::QueryClientWithValidatorAPI;
use crate::context::QueryClientWithNymd;
use crate::utils::{pretty_decimal_with_denom, show_error};
#[derive(Debug, Parser)]
@@ -14,8 +14,8 @@ pub struct Args {
pub identity_key: Option<String>,
}
pub async fn query(args: Args, client: &QueryClientWithValidatorAPI) {
match client.validator_api.get_mixnodes().await {
pub async fn query(args: Args, client: &QueryClientWithNymd) {
match client.nym_api.get_mixnodes().await {
Ok(res) => match args.identity_key {
Some(identity_key) => {
let node = res.iter().find(|node| {
@@ -11,6 +11,6 @@ pub enum Errors {
#[error("signature error - {0}")]
SignatureError(#[from] k256::ecdsa::signature::Error),
#[error("{0}")]
#[error(transparent)]
CosmrsError(#[from] cosmrs::ErrorReport),
}
@@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize};
pub struct InstantiateMsg {
pub group_addr: String,
pub multisig_addr: String,
pub admin: String,
pub mix_denom: String,
}
@@ -6,15 +6,48 @@ use std::fmt::{Display, Formatter};
pub use crate::dealer::{DealerDetails, PagedDealerResponse};
pub use contracts_common::dealings::ContractSafeBytes;
pub use cosmwasm_std::{Addr, Coin};
pub use cosmwasm_std::{Addr, Coin, Timestamp};
pub type EncodedBTEPublicKeyWithProof = String;
pub type EncodedBTEPublicKeyWithProofRef<'a> = &'a str;
pub type NodeIndex = u64;
// The time sign-up is open for dealers to join (2 minutes)
pub const PUBLIC_KEY_SUBMISSION_TIME_SECS: u64 = 60 * 2;
pub const DEALING_EXCHANGE_TIME_SECS: u64 = 60 * 5;
pub const VERIFICATION_KEY_SUBMISSION_TIME_SECS: u64 = 60 * 5;
pub const VERIFICATION_KEY_VALIDATION_TIME_SECS: u64 = 60;
pub const VERIFICATION_KEY_FINALIZATION_TIME_SECS: u64 = 60;
// The time an epoch lasts (2 weeks)
pub const IN_PROGRESS_TIME_SECS: u64 = 60 * 60 * 24 * 14;
// 2 public attributes, 2 private attributes, 1 fixed for coconut credential
pub const TOTAL_DEALINGS: usize = 2 + 2 + 1;
#[derive(Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
#[serde(rename_all = "snake_case")]
pub struct Epoch {
pub state: EpochState,
pub finish_timestamp: Timestamp,
}
impl Epoch {
pub fn new(state: EpochState, current_timestamp: Timestamp) -> Self {
let duration = match state {
EpochState::PublicKeySubmission => PUBLIC_KEY_SUBMISSION_TIME_SECS,
EpochState::DealingExchange => DEALING_EXCHANGE_TIME_SECS,
EpochState::VerificationKeySubmission => VERIFICATION_KEY_SUBMISSION_TIME_SECS,
EpochState::VerificationKeyValidation => VERIFICATION_KEY_VALIDATION_TIME_SECS,
EpochState::VerificationKeyFinalization => VERIFICATION_KEY_FINALIZATION_TIME_SECS,
EpochState::InProgress => IN_PROGRESS_TIME_SECS,
};
Epoch {
state,
finish_timestamp: current_timestamp.plus_seconds(duration),
}
}
}
// currently (it is still extremely likely to change, we might be able to get rid of verification key-related complaints),
// the epoch can be in the following states (in order):
// 1. PublicKeySubmission -> potential dealers are submitting their BTE and ed25519 public keys to participate in dealing exchange
+3 -3
View File
@@ -45,13 +45,13 @@ impl PersistentStorage {
let connection_pool = match sqlx::SqlitePool::connect_with(opts).await {
Ok(db) => db,
Err(err) => {
error!("Failed to connect to SQLx database: {}", err);
error!("Failed to connect to SQLx database: {err}");
return Err(err.into());
}
};
if let Err(err) = sqlx::migrate!("./migrations").run(&connection_pool).await {
error!("Failed to perform migration on the SQLx database: {}", err);
error!("Failed to perform migration on the SQLx database: {err}");
return Err(err.into());
}
@@ -104,7 +104,7 @@ impl Storage for PersistentStorage {
pub async fn initialise_storage(path: PathBuf) -> PersistentStorage {
match PersistentStorage::init(path).await {
Err(err) => panic!("failed to initialise credential storage - {}", err),
Err(err) => panic!("failed to initialise credential storage - {err}"),
Ok(storage) => storage,
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ thiserror = "1.0"
# I guess temporarily until we get serde support in coconut up and running
coconut-interface = { path = "../coconut-interface" }
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
nym-api-requests = { path = "../../nym-api/nym-api-requests" }
validator-client = { path = "../client-libs/validator-client" }
[dev-dependencies]
+2 -2
View File
@@ -9,7 +9,7 @@ type Aes128Ctr = ctr::Ctr64LE<Aes128>;
/// Hashing algorithm used during hkdf for ephemeral shared key generation per blinded signature
/// response encryption.
pub type ValidatorApiCredentialHkdfAlgorithm = blake3::Hasher;
pub type NymApiCredentialHkdfAlgorithm = blake3::Hasher;
/// Encryption algorithm used for end-to-end encryption of blinded signature response
pub type ValidatorApiCredentialEncryptionAlgorithm = Aes128Ctr;
pub type NymApiCredentialEncryptionAlgorithm = Aes128Ctr;
+6 -8
View File
@@ -8,13 +8,11 @@ use coconut_interface::{
use crypto::asymmetric::encryption::PublicKey;
use crypto::shared_key::recompute_shared_key;
use crypto::symmetric::stream_cipher;
use validator_api_requests::coconut::BlindSignRequestBody;
use nym_api_requests::coconut::BlindSignRequestBody;
use validator_client::client::CoconutApiClient;
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
use crate::coconut::params::{
ValidatorApiCredentialEncryptionAlgorithm, ValidatorApiCredentialHkdfAlgorithm,
};
use crate::coconut::params::{NymApiCredentialEncryptionAlgorithm, NymApiCredentialHkdfAlgorithm};
use crate::error::Error;
pub async fn obtain_aggregate_verification_key(
@@ -66,11 +64,11 @@ async fn obtain_partial_credential(
let remote_key = PublicKey::from_bytes(&response.remote_key)?;
let encryption_key = recompute_shared_key::<
ValidatorApiCredentialEncryptionAlgorithm,
ValidatorApiCredentialHkdfAlgorithm,
NymApiCredentialEncryptionAlgorithm,
NymApiCredentialHkdfAlgorithm,
>(&remote_key, attributes.encryption_key());
let zero_iv = stream_cipher::zero_iv::<ValidatorApiCredentialEncryptionAlgorithm>();
let blinded_signature_bytes = stream_cipher::decrypt::<ValidatorApiCredentialEncryptionAlgorithm>(
let zero_iv = stream_cipher::zero_iv::<NymApiCredentialEncryptionAlgorithm>();
let blinded_signature_bytes = stream_cipher::decrypt::<NymApiCredentialEncryptionAlgorithm>(
&encryption_key,
&zero_iv,
&encrypted_signature,
+1
View File
@@ -22,6 +22,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
serde_bytes = { version = "0.11.6", optional = true }
serde_crate = { version = "1.0", optional = true, default_features = false, package = "serde" }
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
thiserror = "1.0.37"
# internal
nymsphinx-types = { path = "../nymsphinx/types" }
-5
View File
@@ -326,11 +326,6 @@ pub fn try_recover_verification_keys(
return Err(DkgError::MismatchedDealings);
}
// currently we expect every dealer to also be a receiver. This restriction might be relaxed in the future
if dealings.len() != receivers.len() {
return Err(DkgError::MismatchedDealings);
}
let indices = receivers.keys().collect::<Vec<_>>();
// Compute A0, ..., A_{t-1}
+122
View File
@@ -254,3 +254,125 @@ fn full_threshold_secret_resharing() {
assert_ne!(derived_secrets, reshared_secrets);
assert_ne!(recovered_partials, reshared_partials);
}
#[test]
#[ignore] // expensive test
fn full_threshold_secret_resharing_left_party() {
let dummy_seed = [42u8; 32];
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
let params = setup();
// the simplest possible case
let threshold = 2;
// the indices are going to get assigned externally, so for test sake, use non-consecutive ones
let mut node_indices = vec![15u64, 248, 33521];
let mut receivers = BTreeMap::new();
let mut full_keys = Vec::new();
for index in &node_indices {
let (dk, pk) = keygen(&params, &mut rng);
receivers.insert(*index, *pk.public_key());
full_keys.push((dk, pk))
}
let first_dealings = node_indices
.iter()
.map(|&dealer_index| {
Dealing::create(&mut rng, &params, dealer_index, threshold, &receivers, None).0
})
.collect::<Vec<_>>();
// recover verification keys
let RecoveredVerificationKeys {
recovered_master: public_original_master,
recovered_partials,
} = try_recover_verification_keys(&first_dealings, threshold, &receivers).unwrap();
let mut derived_secrets = Vec::new();
for (i, (ref mut dk, _)) in full_keys.iter_mut().enumerate() {
let shares = first_dealings
.iter()
.map(|dealing| decrypt_share(dk, i, &dealing.ciphertexts, None).unwrap())
.collect();
let recovered_secret =
combine_shares(shares, &receivers.keys().copied().collect::<Vec<_>>()).unwrap();
derived_secrets.push(recovered_secret)
}
let original_master = perform_lagrangian_interpolation_at_origin(&[
(Scalar::from(node_indices[0]), derived_secrets[0]),
(Scalar::from(node_indices[1]), derived_secrets[1]),
])
.unwrap();
// one party leaves the process
let left_party_index = node_indices.pop().unwrap();
receivers.remove(&left_party_index);
full_keys.pop();
// and another one joins, but we're still over the threshold value of initial parties
let join_party_index = 100000;
let (dk, pk) = keygen(&params, &mut rng);
receivers.insert(join_party_index, *pk.public_key());
full_keys.push((dk, pk));
// only initial parties attempt to create resharing dealings!
let resharing_dealings = node_indices
.iter()
.zip(derived_secrets.iter().take(2))
.map(|(&dealer_index, prior_secret)| {
Dealing::create(
&mut rng,
&params,
dealer_index,
threshold,
&receivers,
Some(*prior_secret),
)
.0
})
.collect::<Vec<_>>();
for (reshared_dealing, prior_vk) in resharing_dealings
.iter()
.zip(recovered_partials.iter().take(2))
{
reshared_dealing
.verify(&params, threshold, &receivers, Some(*prior_vk))
.unwrap();
}
// recover verification keys
let RecoveredVerificationKeys {
recovered_master: public_reshared_master,
recovered_partials: reshared_partials,
} = try_recover_verification_keys(&resharing_dealings, threshold, &receivers).unwrap();
let mut reshared_secrets = Vec::new();
for (i, (ref mut dk, _)) in full_keys.iter_mut().enumerate() {
let shares = resharing_dealings
.iter()
.map(|dealing| decrypt_share(dk, i, &dealing.ciphertexts, None).unwrap())
.collect();
let recovered_secret = combine_shares(shares, &node_indices).unwrap();
reshared_secrets.push(recovered_secret)
}
let reshared_master = perform_lagrangian_interpolation_at_origin(&[
(Scalar::from(node_indices[0]), reshared_secrets[0]),
(Scalar::from(join_party_index), reshared_secrets[2]),
])
.unwrap();
// the master secret and public values didn't change
assert_eq!(original_master, reshared_master);
assert_eq!(public_original_master, public_reshared_master);
// but partials did
assert_ne!(derived_secrets, reshared_secrets);
assert_ne!(recovered_partials, reshared_partials);
}
+33 -26
View File
@@ -2,11 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
use std::fmt::{self, Display, Formatter};
use thiserror::Error;
#[cfg(feature = "rand")]
use rand::{CryptoRng, RngCore};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Display, Formatter};
/// Size of a X25519 private key
pub const PRIVATE_KEY_SIZE: usize = 32;
@@ -17,31 +19,26 @@ pub const PUBLIC_KEY_SIZE: usize = 32;
/// Size of a X25519 shared secret
pub const SHARED_SECRET_SIZE: usize = 32;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
#[derive(Clone, Eq, PartialEq, Debug, Error)]
pub enum KeyRecoveryError {
InvalidPublicKeyBytes,
InvalidPrivateKeyBytes,
MalformedString(bs58::decode::Error),
}
#[error("received public key of invalid size. Got: {received}, expected: {expected}")]
InvalidSizePublicKey { received: usize, expected: usize },
impl From<bs58::decode::Error> for KeyRecoveryError {
fn from(err: bs58::decode::Error) -> Self {
KeyRecoveryError::MalformedString(err)
}
}
#[error("received private key of invalid size. Got: {received}, expected: {expected}")]
InvalidSizePrivateKey { received: usize, expected: usize },
// required for std::error::Error
impl Display for KeyRecoveryError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
KeyRecoveryError::InvalidPrivateKeyBytes => write!(f, "Invalid private key bytes"),
KeyRecoveryError::InvalidPublicKeyBytes => write!(f, "Invalid public key bytes"),
KeyRecoveryError::MalformedString(err) => write!(f, "malformed string - {}", err),
}
}
}
#[error("the base58 representation of the public key was malformed - {source}")]
MalformedPublicKeyString {
#[source]
source: bs58::decode::Error,
},
impl std::error::Error for KeyRecoveryError {}
#[error("the base58 representation of the private key was malformed - {source}")]
MalformedPrivateKeyString {
#[source]
source: bs58::decode::Error,
},
}
pub struct KeyPair {
pub(crate) private_key: PrivateKey,
@@ -112,7 +109,10 @@ impl PublicKey {
pub fn from_bytes(b: &[u8]) -> Result<Self, KeyRecoveryError> {
if b.len() != PUBLIC_KEY_SIZE {
return Err(KeyRecoveryError::InvalidPublicKeyBytes);
return Err(KeyRecoveryError::InvalidSizePublicKey {
received: b.len(),
expected: PUBLIC_KEY_SIZE,
});
}
let mut bytes = [0; PUBLIC_KEY_SIZE];
bytes.copy_from_slice(&b[..PUBLIC_KEY_SIZE]);
@@ -124,7 +124,9 @@ impl PublicKey {
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, KeyRecoveryError> {
let bytes = bs58::decode(val).into_vec()?;
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| KeyRecoveryError::MalformedPublicKeyString { source })?;
Self::from_bytes(&bytes)
}
}
@@ -188,7 +190,10 @@ impl PrivateKey {
pub fn from_bytes(b: &[u8]) -> Result<Self, KeyRecoveryError> {
if b.len() != PRIVATE_KEY_SIZE {
return Err(KeyRecoveryError::InvalidPrivateKeyBytes);
return Err(KeyRecoveryError::InvalidSizePrivateKey {
received: b.len(),
expected: PRIVATE_KEY_SIZE,
});
}
let mut bytes = [0; 32];
bytes.copy_from_slice(&b[..PRIVATE_KEY_SIZE]);
@@ -200,7 +205,9 @@ impl PrivateKey {
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, KeyRecoveryError> {
let bytes = bs58::decode(val).into_vec()?;
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| KeyRecoveryError::MalformedPrivateKeyString { source })?;
Self::from_bytes(&bytes)
}
+30 -28
View File
@@ -6,10 +6,11 @@ pub use ed25519_dalek::SignatureError;
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
use std::fmt::{self, Display, Formatter};
use thiserror::Error;
#[cfg(feature = "rand")]
use rand::{CryptoRng, RngCore};
use std::fmt::{self, Display, Formatter};
#[cfg(feature = "serde")]
use serde::de::Error as SerdeError;
#[cfg(feature = "serde")]
@@ -17,35 +18,30 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde")]
use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
#[derive(Debug)]
#[derive(Debug, Error)]
pub enum Ed25519RecoveryError {
MalformedBytes(SignatureError),
MalformedString(bs58::decode::Error),
}
#[error(transparent)]
MalformedBytes(#[from] SignatureError),
impl From<SignatureError> for Ed25519RecoveryError {
fn from(err: SignatureError) -> Self {
Ed25519RecoveryError::MalformedBytes(err)
}
}
#[error("the base58 representation of the public key was malformed - {source}")]
MalformedPublicKeyString {
#[source]
source: bs58::decode::Error,
},
impl From<bs58::decode::Error> for Ed25519RecoveryError {
fn from(err: bs58::decode::Error) -> Self {
Ed25519RecoveryError::MalformedString(err)
}
}
#[error("the base58 representation of the private key was malformed - {source}")]
MalformedPrivateKeyString {
#[source]
source: bs58::decode::Error,
},
impl fmt::Display for Ed25519RecoveryError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Ed25519RecoveryError::MalformedBytes(err) => write!(f, "malformed bytes - {}", err),
Ed25519RecoveryError::MalformedString(err) => write!(f, "malformed string - {}", err),
}
}
#[error("the base58 representation of the signature was malformed - {source}")]
MalformedSignatureString {
#[source]
source: bs58::decode::Error,
},
}
impl std::error::Error for Ed25519RecoveryError {}
/// Keypair for usage in ed25519 EdDSA.
#[derive(Debug)]
pub struct KeyPair {
@@ -134,7 +130,9 @@ impl PublicKey {
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
let bytes = bs58::decode(val).into_vec()?;
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| Ed25519RecoveryError::MalformedPublicKeyString { source })?;
Self::from_bytes(&bytes)
}
@@ -211,7 +209,9 @@ impl PrivateKey {
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
let bytes = bs58::decode(val).into_vec()?;
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| Ed25519RecoveryError::MalformedPrivateKeyString { source })?;
Self::from_bytes(&bytes)
}
@@ -277,7 +277,9 @@ impl Signature {
}
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, Ed25519RecoveryError> {
let bytes = bs58::decode(val).into_vec()?;
let bytes = bs58::decode(val)
.into_vec()
.map_err(|source| Ed25519RecoveryError::MalformedSignatureString { source })?;
Self::from_bytes(&bytes)
}
+1
View File
@@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.21.2", features = ["time", "macros", "rt", "net", "io-util"] }
tokio-util = { version = "0.7.3", features = ["codec"] }
url = "2.2"
thiserror = "1.0.37"
crypto = { path = "../crypto" }
nymsphinx-acknowledgements = { path = "../nymsphinx/acknowledgements" }
@@ -4,63 +4,22 @@
use nymsphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
use nymsphinx_addressing::nodes::NymNodeRoutingAddressError;
use nymsphinx_types::Error as SphinxError;
use std::fmt::{self, Display, Formatter};
use thiserror::Error;
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum MixProcessingError {
SphinxProcessingError(SphinxError),
InvalidHopAddress(NymNodeRoutingAddressError),
NoSurbAckInFinalHop,
MalformedSurbAck(SurbAckRecoveryError),
#[error("failed to process received packet: {0}")]
SphinxProcessingError(#[from] SphinxError),
#[error("the forward hop address was malformed: {0}")]
InvalidForwardHopAddress(#[from] NymNodeRoutingAddressError),
#[error("the final hop did not contain a SURB-Ack")]
NoSurbAckInFinalHop,
#[error("failed to recover the expected SURB-Ack packet: {0}")]
MalformedSurbAck(#[from] SurbAckRecoveryError),
#[error("the received packet was set to use the very old and very much deprecated 'VPN' mode")]
ReceivedOldTypeVpnPacket,
}
impl From<SphinxError> for MixProcessingError {
// for the time being just have a single error instance for all possible results of SphinxError
fn from(err: SphinxError) -> Self {
use MixProcessingError::*;
SphinxProcessingError(err)
}
}
impl From<NymNodeRoutingAddressError> for MixProcessingError {
fn from(err: NymNodeRoutingAddressError) -> Self {
use MixProcessingError::*;
InvalidHopAddress(err)
}
}
impl From<SurbAckRecoveryError> for MixProcessingError {
fn from(err: SurbAckRecoveryError) -> Self {
use MixProcessingError::*;
MalformedSurbAck(err)
}
}
impl Display for MixProcessingError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
MixProcessingError::SphinxProcessingError(sphinx_err) => {
write!(f, "Sphinx Processing Error - {}", sphinx_err)
}
MixProcessingError::InvalidHopAddress(address_err) => {
write!(f, "Invalid Hop Address - {:?}", address_err)
}
MixProcessingError::NoSurbAckInFinalHop => {
write!(f, "No SURBAck present in the final hop data")
}
MixProcessingError::MalformedSurbAck(surb_ack_err) => {
write!(f, "Malformed SURBAck - {:?}", surb_ack_err)
}
MixProcessingError::ReceivedOldTypeVpnPacket => {
write!(f, "Received an old-type unsafe 'VPN' mode packet")
}
}
}
}
impl std::error::Error for MixProcessingError {}
@@ -51,7 +51,7 @@ impl SphinxPacketProcessor {
packet: SphinxPacket,
) -> Result<ProcessedPacket, MixProcessingError> {
packet.process(&self.sphinx_key).map_err(|err| {
debug!("Failed to unwrap Sphinx packet: {:?}", err);
debug!("Failed to unwrap Sphinx packet: {err}");
MixProcessingError::SphinxProcessingError(err)
})
}
+3 -3
View File
@@ -53,13 +53,13 @@ impl Display for RttError {
write!(f, "The received reply packet had invalid signature")
}
RttError::UnreachableNode(id, err) => {
write!(f, "Could not establish connection to {} - {}", id, err)
write!(f, "Could not establish connection to {} - {err}", id)
}
RttError::UnexpectedConnectionFailureWrite(id, err) => {
write!(f, "Failed to write echo packet to {} - {}", id, err)
write!(f, "Failed to write echo packet to {} - {err}", id)
}
RttError::UnexpectedConnectionFailureRead(id, err) => {
write!(f, "Failed to read reply packet from {} - {}", id, err)
write!(f, "Failed to read reply packet from {} - {err}", id)
}
RttError::ConnectionReadTimeout(id) => {
write!(f, "Timed out while trying to read reply packet from {}", id)
+7 -7
View File
@@ -11,7 +11,7 @@ use std::fmt::{Display, Formatter};
use std::net::SocketAddr;
use std::sync::Arc;
use std::{fmt, io, process};
use task::ShutdownListener;
use task::TaskClient;
use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream};
use tokio_util::codec::{Decoder, Encoder, Framed};
@@ -19,14 +19,14 @@ use tokio_util::codec::{Decoder, Encoder, Framed};
pub(crate) struct PacketListener {
address: SocketAddr,
connection_handler: Arc<ConnectionHandler>,
shutdown: ShutdownListener,
shutdown: TaskClient,
}
impl PacketListener {
pub(crate) fn new(
address: SocketAddr,
identity: Arc<identity::KeyPair>,
shutdown: ShutdownListener,
shutdown: TaskClient,
) -> Self {
PacketListener {
address,
@@ -66,7 +66,7 @@ impl PacketListener {
tokio::spawn(connection_handler.handle_connection(socket, remote_addr, handler_shutdown_listener));
}
Err(err) => warn!("Failed to accept incoming connection - {:?}", err),
Err(err) => warn!("Failed to accept incoming connection - {err}"),
}
},
_ = shutdown_listener.recv() => {
@@ -91,7 +91,7 @@ impl ConnectionHandler {
self: Arc<Self>,
conn: TcpStream,
remote: SocketAddr,
mut shutdown_listener: ShutdownListener,
mut shutdown_listener: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
@@ -141,9 +141,9 @@ enum EchoPacketCodecError {
impl Display for EchoPacketCodecError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
EchoPacketCodecError::IoError(err) => write!(f, "encountered io error - {}", err),
EchoPacketCodecError::IoError(err) => write!(f, "encountered io error - {err}"),
EchoPacketCodecError::PacketRecoveryError(err) => {
write!(f, "failed to correctly decode an echo packet - {}", err)
write!(f, "failed to correctly decode an echo packet - {err}")
}
}
}

Some files were not shown because too many files have changed in this diff Show More